@@ -23,6 +23,7 @@ use crate::utils::url_encode::{decode_uri, encode_uri, PERCENT_ENCODE_SET};
23
23
24
24
use self :: directory_entry:: { BreadcrumbItem , DirectoryEntry , DirectoryIndex } ;
25
25
use self :: http_utils:: { make_http_file_response, CacheControlDirective } ;
26
+ use self :: query_params:: { QueryParams , SortBy } ;
26
27
27
28
/// Explorer's Handlebars template filename
28
29
const EXPLORER_TEMPLATE : & str = "explorer" ;
@@ -60,22 +61,22 @@ impl<'a> FileServer {
60
61
Arc :: new ( handlebars)
61
62
}
62
63
63
- fn parse_path ( req_uri : & str ) -> Result < PathBuf > {
64
+ fn parse_path ( req_uri : & str ) -> Result < ( PathBuf , Option < QueryParams > ) > {
64
65
let uri = Uri :: from_str ( req_uri) ?;
65
66
let uri_parts = uri. into_parts ( ) ;
66
67
67
68
if let Some ( path_and_query) = uri_parts. path_and_query {
68
69
let path = path_and_query. path ( ) ;
69
- let _queries = if let Some ( query_str) = path_and_query. query ( ) {
70
- Some ( query_params :: QueryParams :: from_str ( query_str) ?)
70
+ let query_params = if let Some ( query_str) = path_and_query. query ( ) {
71
+ Some ( QueryParams :: from_str ( query_str) ?)
71
72
} else {
72
73
None
73
74
} ;
74
75
75
- return Ok ( decode_uri ( path) ) ;
76
+ return Ok ( ( decode_uri ( path) , query_params ) ) ;
76
77
}
77
78
78
- Ok ( PathBuf :: from_str ( "/" ) ?)
79
+ Ok ( ( PathBuf :: from_str ( "/" ) ?, None ) )
79
80
}
80
81
81
82
/// Resolves a HTTP Request to a file or directory.
@@ -105,11 +106,13 @@ impl<'a> FileServer {
105
106
pub async fn resolve ( & self , req_path : String ) -> Result < Response < Body > > {
106
107
use std:: io:: ErrorKind ;
107
108
108
- let path = FileServer :: parse_path ( req_path. as_str ( ) ) ?;
109
+ let ( path, query_params ) = FileServer :: parse_path ( req_path. as_str ( ) ) ?;
109
110
110
111
match self . scoped_file_system . resolve ( path) . await {
111
112
Ok ( entry) => match entry {
112
- Entry :: Directory ( dir) => self . render_directory_index ( dir. path ( ) ) . await ,
113
+ Entry :: Directory ( dir) => {
114
+ self . render_directory_index ( dir. path ( ) , query_params) . await
115
+ }
113
116
Entry :: File ( file) => {
114
117
make_http_file_response ( * file, CacheControlDirective :: MaxAge ( 2500 ) ) . await
115
118
}
@@ -134,8 +137,13 @@ impl<'a> FileServer {
134
137
/// Indexes the directory by creating a `DirectoryIndex`. Such `DirectoryIndex`
135
138
/// is used to build the Handlebars "Explorer" template using the Handlebars
136
139
/// engine and builds an HTTP Response containing such file
137
- async fn render_directory_index ( & self , path : PathBuf ) -> Result < Response < Body > > {
138
- let directory_index = FileServer :: index_directory ( self . root_dir . clone ( ) , path) ?;
140
+ async fn render_directory_index (
141
+ & self ,
142
+ path : PathBuf ,
143
+ query_params : Option < QueryParams > ,
144
+ ) -> Result < Response < Body > > {
145
+ let directory_index =
146
+ FileServer :: index_directory ( self . root_dir . clone ( ) , path, query_params) ?;
139
147
let html = self
140
148
. handlebars
141
149
. render ( EXPLORER_TEMPLATE , & directory_index)
@@ -204,7 +212,11 @@ impl<'a> FileServer {
204
212
205
213
/// Creates a `DirectoryIndex` with the provided `root_dir` and `path`
206
214
/// (HTTP Request URI)
207
- fn index_directory ( root_dir : PathBuf , path : PathBuf ) -> Result < DirectoryIndex > {
215
+ fn index_directory (
216
+ root_dir : PathBuf ,
217
+ path : PathBuf ,
218
+ query_params : Option < QueryParams > ,
219
+ ) -> Result < DirectoryIndex > {
208
220
let breadcrumbs = FileServer :: breadcrumbs_from_path ( & root_dir, & path) ?;
209
221
let entries = read_dir ( path) . context ( "Unable to read directory" ) ?;
210
222
let mut directory_entries: Vec < DirectoryEntry > = Vec :: new ( ) ;
@@ -231,17 +243,47 @@ impl<'a> FileServer {
231
243
. to_string ( ) ,
232
244
is_dir : metadata. is_dir ( ) ,
233
245
size : format_bytes ( metadata. len ( ) as f64 ) ,
246
+ len : metadata. len ( ) ,
234
247
entry_path : FileServer :: make_dir_entry_link ( & root_dir, & entry. path ( ) ) ,
235
248
created_at,
236
249
updated_at,
237
250
} ) ;
238
251
}
239
252
253
+ if let Some ( query_params) = query_params {
254
+ if let Some ( sort_by) = query_params. sort_by {
255
+ match sort_by {
256
+ SortBy :: Name => {
257
+ directory_entries. sort_by_key ( |entry| entry. display_name . clone ( ) ) ;
258
+
259
+ return Ok ( DirectoryIndex {
260
+ entries : directory_entries,
261
+ breadcrumbs,
262
+ sort_by_name : true ,
263
+ sort_by_size : false ,
264
+ } ) ;
265
+ }
266
+ SortBy :: Size => {
267
+ directory_entries. sort_by_key ( |entry| entry. len ) ;
268
+
269
+ return Ok ( DirectoryIndex {
270
+ entries : directory_entries,
271
+ breadcrumbs,
272
+ sort_by_name : false ,
273
+ sort_by_size : true ,
274
+ } ) ;
275
+ }
276
+ }
277
+ }
278
+ }
279
+
240
280
directory_entries. sort ( ) ;
241
281
242
282
Ok ( DirectoryIndex {
243
283
entries : directory_entries,
244
284
breadcrumbs,
285
+ sort_by_name : false ,
286
+ sort_by_size : false ,
245
287
} )
246
288
}
247
289
@@ -301,7 +343,7 @@ mod tests {
301
343
] ;
302
344
303
345
for ( idx, req_uri) in have. iter ( ) . enumerate ( ) {
304
- let sanitized_path = FileServer :: parse_path ( req_uri) . unwrap ( ) ;
346
+ let sanitized_path = FileServer :: parse_path ( req_uri) . unwrap ( ) . 0 ;
305
347
let wanted_path = PathBuf :: from_str ( want[ idx] ) . unwrap ( ) ;
306
348
307
349
assert_eq ! ( sanitized_path, wanted_path) ;
0 commit comments