@@ -117,24 +117,20 @@ impl StaticFileServer {
117117 }
118118
119119 fn resolve_relative_candidate ( & self , relative : & SafeRelativePath ) -> io:: Result < ResolveResult > {
120- if path_contains_symlink ( & self . root , relative) ? {
121- return Ok ( ResolveResult :: NotFound ) ;
122- }
123-
124120 let candidate = self . root . join ( relative. as_path ( ) ) ;
125- let candidate = match candidate. canonicalize ( ) {
121+ let canonical = match candidate. canonicalize ( ) {
126122 Ok ( path) => path,
127123 Err ( error) if error. kind ( ) == io:: ErrorKind :: NotFound => {
128124 return Ok ( ResolveResult :: NotFound ) ;
129125 }
130126 Err ( error) => return Err ( error) ,
131127 } ;
132128
133- if !candidate . starts_with ( & self . root ) {
129+ if !canonical . starts_with ( & self . root ) || canonical != candidate {
134130 return Ok ( ResolveResult :: NotFound ) ;
135131 }
136132
137- let candidate_metadata = match candidate . metadata ( ) {
133+ let candidate_metadata = match canonical . metadata ( ) {
138134 Ok ( metadata) => metadata,
139135 Err ( error) if error. kind ( ) == io:: ErrorKind :: NotFound => {
140136 return Ok ( ResolveResult :: NotFound ) ;
@@ -144,14 +140,14 @@ impl StaticFileServer {
144140
145141 if candidate_metadata. is_dir ( ) {
146142 for index in & self . index_files {
147- let index_candidate = candidate . join ( index) ;
143+ let index_candidate = canonical . join ( index) ;
148144 if let Some ( file) = self . static_file ( & index_candidate) ? {
149145 return Ok ( ResolveResult :: Found ( file) ) ;
150146 }
151147 }
152148
153149 if self . directory_listing . enabled {
154- return self . directory_listing ( & candidate ) ;
150+ return self . directory_listing ( & canonical ) ;
155151 }
156152
157153 return Ok ( ResolveResult :: NotFound ) ;
@@ -167,17 +163,15 @@ impl StaticFileServer {
167163 let Some ( relative) = SafeRelativePath :: from_rooted ( & self . root , candidate) else {
168164 return Ok ( None ) ;
169165 } ;
170- if path_contains_symlink ( & self . root , & relative) ? {
171- return Ok ( None ) ;
172- }
173166
167+ let expected = self . root . join ( relative. as_path ( ) ) ;
174168 let canonical = match candidate. canonicalize ( ) {
175169 Ok ( path) => path,
176170 Err ( error) if error. kind ( ) == io:: ErrorKind :: NotFound => return Ok ( None ) ,
177171 Err ( error) => return Err ( error) ,
178172 } ;
179173
180- if !canonical. starts_with ( & self . root ) {
174+ if !canonical. starts_with ( & self . root ) || canonical != expected {
181175 return Ok ( None ) ;
182176 }
183177
@@ -208,7 +202,7 @@ impl StaticFileServer {
208202 let Some ( relative) = SafeRelativePath :: from_rooted ( & self . root , directory) else {
209203 return Ok ( ResolveResult :: NotFound ) ;
210204 } ;
211- if path_contains_symlink ( & self . root , & relative) ? {
205+ if directory != self . root . join ( relative. as_path ( ) ) {
212206 return Ok ( ResolveResult :: NotFound ) ;
213207 }
214208 let mut entries = Vec :: new ( ) ;
@@ -293,56 +287,27 @@ impl SafeRelativePath {
293287 }
294288}
295289
296- fn normal_component ( component : & std:: ffi:: OsStr ) -> Option < & std:: ffi:: OsStr > {
297- let mut components = Path :: new ( component) . components ( ) ;
298- match ( components. next ( ) , components. next ( ) ) {
299- ( Some ( std:: path:: Component :: Normal ( component) ) , None ) => Some ( component) ,
300- _ => None ,
301- }
302- }
303-
304- fn path_contains_symlink ( root : & Path , relative : & SafeRelativePath ) -> io:: Result < bool > {
305- let mut current = root. to_path_buf ( ) ;
306- for component in & relative. components {
307- let Some ( component) = normal_component ( component) else {
308- return Ok ( true ) ;
309- } ;
310- current. push ( component) ;
311- match std:: fs:: read_link ( & current) {
312- Ok ( _) => return Ok ( true ) ,
313- Err ( error) if error. kind ( ) == io:: ErrorKind :: NotFound => return Ok ( false ) ,
314- Err ( error) if error. kind ( ) == io:: ErrorKind :: InvalidInput => { }
315- Err ( error) => return Err ( error) ,
316- }
317- }
318-
319- Ok ( false )
320- }
321-
322290fn configured_web_path_contains_symlink ( path : & Path ) -> io:: Result < bool > {
323- let mut current = PathBuf :: new ( ) ;
324291 for component in path. components ( ) {
325292 match component {
326- std:: path:: Component :: Prefix ( _) | std:: path:: Component :: RootDir => {
327- current. push ( component) ;
328- }
329- std:: path:: Component :: Normal ( component) => {
330- let Some ( component) = normal_component ( component) else {
331- return Ok ( true ) ;
332- } ;
333- current. push ( component) ;
334- }
293+ std:: path:: Component :: Prefix ( _)
294+ | std:: path:: Component :: RootDir
295+ | std:: path:: Component :: Normal ( _) => { }
335296 std:: path:: Component :: CurDir | std:: path:: Component :: ParentDir => return Ok ( true ) ,
336297 }
337- match std:: fs:: read_link ( & current) {
338- Ok ( _) => return Ok ( true ) ,
339- Err ( error) if error. kind ( ) == io:: ErrorKind :: NotFound => return Ok ( false ) ,
340- Err ( error) if error. kind ( ) == io:: ErrorKind :: InvalidInput => { }
341- Err ( error) => return Err ( error) ,
342- }
343298 }
344299
345- Ok ( false )
300+ let expected = if path. is_absolute ( ) {
301+ path. to_path_buf ( )
302+ } else {
303+ std:: env:: current_dir ( ) ?. join ( path)
304+ } ;
305+
306+ match path. canonicalize ( ) {
307+ Ok ( canonical) => Ok ( canonical != expected) ,
308+ Err ( error) if error. kind ( ) == io:: ErrorKind :: NotFound => Ok ( false ) ,
309+ Err ( error) => Err ( error) ,
310+ }
346311}
347312
348313fn directory_listing_path ( relative : & Path ) -> String {
@@ -880,7 +845,7 @@ fn open_static_body_file(file: &StaticFile) -> io::Result<std::fs::File> {
880845 "static body path escaped web root" ,
881846 )
882847 } ) ?;
883- if path_contains_symlink ( & file. root , & relative) ? {
848+ if file. path != file . root . join ( relative. as_path ( ) ) {
884849 return Err ( io:: Error :: new (
885850 io:: ErrorKind :: InvalidInput ,
886851 "static body path contains a symlink" ,
0 commit comments