11use awc:: http:: Uri ;
2+ use std:: ffi:: OsStr ;
23use std:: path:: PathBuf ;
34use RoutingAction :: { Error , Execute , NotFound , Redirect , Serve } ;
45
@@ -21,68 +22,96 @@ pub trait ExecutionStore {
2122}
2223
2324pub trait RoutingConfig {
24- fn prefix ( & self ) -> & str ;
25+ fn prefix ( & self ) -> & Uri ;
2526}
2627
2728pub async fn calculate_route < T , C > ( uri : Uri , store : & T , config : & C ) -> RoutingAction
2829where
2930 T : ExecutionStore ,
3031 C : RoutingConfig ,
3132{
32- if !uri. path ( ) . starts_with ( config. prefix ( ) ) {
33- return Redirect ( config. prefix ( ) . parse ( ) . unwrap ( ) ) ;
34- } ;
35-
36- let mut path = PathBuf :: from ( format ! (
37- "/{}" ,
38- uri. path( ) . strip_prefix( config. prefix( ) ) . unwrap( )
39- ) ) ;
40-
41- match path. extension ( ) {
42- None => {
43- if uri. path ( ) . ends_with ( FORWARD_SLASH ) {
44- path. push ( INDEX ) ;
45- find_execution_or_not_found ( path, store) . await
46- } else {
47- let path_with_ext = path. with_extension ( EXECUTION_EXTENSION ) ;
48- match find_execution ( path_with_ext, store) . await {
49- Some ( action) => action,
50- None => Redirect ( append_to_uri_path ( & uri, FORWARD_SLASH ) ) ,
51- }
52- }
53- }
54- Some ( extension) => {
55- if extension == EXECUTION_EXTENSION {
56- find_execution_or_not_found ( path, store) . await
57- } else {
58- Serve ( path)
59- }
33+ match check_uri ( & uri, config) {
34+ Ok ( path) => match path. clone ( ) . extension ( ) {
35+ None => calculate_route_without_extension ( & uri, path, store) . await ,
36+ Some ( extension) => calculate_route_with_extension ( path, extension, store) . await ,
37+ } ,
38+ Err ( action) => action,
39+ }
40+ }
41+
42+ fn check_uri < C > ( uri : & Uri , config : & C ) -> Result < PathBuf , RoutingAction >
43+ where
44+ C : RoutingConfig ,
45+ {
46+ if uri. path ( ) . starts_with ( config. prefix ( ) . path ( ) ) {
47+ Ok ( PathBuf :: from ( format ! (
48+ "/{}" ,
49+ uri. path( )
50+ . strip_prefix( config. prefix( ) . path( ) )
51+ . expect( "Unable to remove expected prefix from path" )
52+ ) ) )
53+ } else {
54+ Err ( Redirect ( config. prefix ( ) . clone ( ) ) )
55+ }
56+ }
57+
58+ async fn calculate_route_without_extension < T > (
59+ uri : & Uri ,
60+ mut path : PathBuf ,
61+ store : & T ,
62+ ) -> RoutingAction
63+ where
64+ T : ExecutionStore ,
65+ {
66+ if uri. path ( ) . ends_with ( FORWARD_SLASH ) {
67+ path. push ( INDEX ) ;
68+ find_execution_or_not_found ( & path, store) . await
69+ } else {
70+ let path_with_ext = path. with_extension ( EXECUTION_EXTENSION ) ;
71+ match find_execution ( & path_with_ext, store) . await {
72+ Some ( action) => action,
73+ None => Redirect ( append_to_uri_path ( & uri, FORWARD_SLASH ) ) ,
6074 }
6175 }
6276}
6377
64- async fn find_execution_or_not_found < T > ( path : PathBuf , store : & T ) -> RoutingAction
78+ async fn calculate_route_with_extension < T > (
79+ path : PathBuf ,
80+ extension : & OsStr ,
81+ store : & T ,
82+ ) -> RoutingAction
83+ where
84+ T : ExecutionStore ,
85+ {
86+ if extension == EXECUTION_EXTENSION {
87+ find_execution_or_not_found ( & path, store) . await
88+ } else {
89+ Serve ( path)
90+ }
91+ }
92+
93+ async fn find_execution_or_not_found < T > ( path : & PathBuf , store : & T ) -> RoutingAction
6594where
6695 T : ExecutionStore ,
6796{
68- match find_execution ( path. clone ( ) , store) . await {
97+ match find_execution ( path, store) . await {
6998 None => find_not_found ( path, store) . await ,
7099 Some ( execute) => execute,
71100 }
72101}
73102
74- async fn find_execution < T > ( path : PathBuf , store : & T ) -> Option < RoutingAction >
103+ async fn find_execution < T > ( path : & PathBuf , store : & T ) -> Option < RoutingAction >
75104where
76105 T : ExecutionStore ,
77106{
78- if store. contains ( & path) . await {
79- Some ( Execute ( path) )
107+ if store. contains ( path) . await {
108+ Some ( Execute ( path. clone ( ) ) )
80109 } else {
81110 None
82111 }
83112}
84113
85- async fn find_not_found < T > ( path : PathBuf , store : & T ) -> RoutingAction
114+ async fn find_not_found < T > ( path : & PathBuf , store : & T ) -> RoutingAction
86115where
87116 T : ExecutionStore ,
88117{
@@ -96,13 +125,13 @@ where
96125 }
97126 }
98127
99- Error ( path_to_string ( & path) )
128+ Error ( path_to_string ( path) )
100129}
101130
102131fn append_to_uri_path ( uri : & Uri , append : & str ) -> Uri {
103132 let mut full_uri = uri. to_string ( ) ;
104133 full_uri. insert_str ( uri. path ( ) . len ( ) , append) ;
105- full_uri. parse ( ) . unwrap ( )
134+ full_uri. parse ( ) . expect ( "Could not append uri path" )
106135}
107136
108137fn path_to_string ( path : & PathBuf ) -> String {
@@ -132,23 +161,23 @@ mod tests {
132161 }
133162
134163 #[ tokio:: test]
135- async fn root_path_with_site_prefix_executes_index ( ) {
164+ async fn root_path_and_site_prefix_executes_index ( ) {
136165 let actual = do_route ( "/prefix/" , Default , Some ( "/prefix/" ) ) . await ;
137166 let expected = execute ( "/index.sql" ) ;
138167
139168 assert_eq ! ( expected, actual) ;
140169 }
141170
142171 #[ tokio:: test]
143- async fn sql_extension ( ) {
172+ async fn extension ( ) {
144173 let actual = do_route ( "/index.sql" , Default , None ) . await ;
145174 let expected = execute ( "/index.sql" ) ;
146175
147176 assert_eq ! ( expected, actual) ;
148177 }
149178
150179 #[ tokio:: test]
151- async fn sql_extension_and_site_prefix ( ) {
180+ async fn extension_and_site_prefix ( ) {
152181 let actual = do_route ( "/prefix/index.sql" , Default , Some ( "/prefix/" ) ) . await ;
153182 let expected = execute ( "/index.sql" ) ;
154183
@@ -294,6 +323,22 @@ mod tests {
294323 assert_eq ! ( expected, actual) ;
295324 }
296325
326+ #[ tokio:: test]
327+ async fn asset_trims_query ( ) {
328+ let actual = do_route ( "/favicon.ico?version=10" , Default , None ) . await ;
329+ let expected = serve ( "/favicon.ico" ) ;
330+
331+ assert_eq ! ( expected, actual) ;
332+ }
333+
334+ #[ tokio:: test]
335+ async fn asset_trims_fragment ( ) {
336+ let actual = do_route ( "/favicon.ico#asset1" , Default , None ) . await ;
337+ let expected = serve ( "/favicon.ico" ) ;
338+
339+ assert_eq ! ( expected, actual) ;
340+ }
341+
297342 #[ tokio:: test]
298343 async fn serves_corresponding_asset_given_site_prefix ( ) {
299344 let actual = do_route ( "/prefix/favicon.ico" , Default , Some ( "/prefix/" ) ) . await ;
@@ -323,6 +368,22 @@ mod tests {
323368 assert_eq ! ( expected, actual) ;
324369 }
325370
371+ #[ tokio:: test]
372+ async fn no_extension_no_corresponding_file_redirects_with_trailing_slash_and_query ( ) {
373+ let actual = do_route ( "/folder?misc=1&foo=bar" , Default , None ) . await ;
374+ let expected = redirect ( "/folder/?misc=1&foo=bar" ) ;
375+
376+ assert_eq ! ( expected, actual) ;
377+ }
378+
379+ #[ tokio:: test]
380+ async fn no_extension_no_corresponding_file_redirects_with_trailing_slash_and_fragment ( ) {
381+ let actual = do_route ( "/folder#anchor1" , Default , None ) . await ;
382+ let expected = redirect ( "/folder/#anchor1" ) ;
383+
384+ assert_eq ! ( expected, actual) ;
385+ }
386+
326387 #[ tokio:: test]
327388 async fn no_extension_site_prefix_and_no_corresponding_file_redirects_with_trailing_slash ( )
328389 {
@@ -409,19 +470,19 @@ mod tests {
409470 }
410471
411472 struct Config {
412- prefix : String ,
473+ prefix : Uri ,
413474 }
414475
415476 impl Config {
416477 fn new ( prefix : & str ) -> Self {
417478 Self {
418- prefix : prefix. to_string ( ) ,
479+ prefix : prefix. parse ( ) . unwrap ( ) ,
419480 }
420481 }
421482 }
422483 impl RoutingConfig for Config {
423- fn prefix ( & self ) -> & str {
424- self . prefix . as_str ( )
484+ fn prefix ( & self ) -> & Uri {
485+ & self . prefix
425486 }
426487 }
427488
0 commit comments