You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							95 lines
						
					
					
						
							2.2 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							95 lines
						
					
					
						
							2.2 KiB
						
					
					
				| // Copyright 2015 Matthew Holt and The Caddy Authors | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| //     http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
|  | |
| package fileserver | |
| 
 | |
| import ( | |
| 	"net/url" | |
| 	"testing" | |
| ) | |
| 
 | |
| func TestSanitizedPathJoin(t *testing.T) { | |
| 	// For easy reference: | |
| 	// %2E = . | |
| 	// %2F = / | |
| 	// %5C = \ | |
| 	for i, tc := range []struct { | |
| 		inputRoot string | |
| 		inputPath string | |
| 		expect    string | |
| 	}{ | |
| 		{ | |
| 			inputPath: "", | |
| 			expect:    ".", | |
| 		}, | |
| 		{ | |
| 			inputPath: "/", | |
| 			expect:    ".", | |
| 		}, | |
| 		{ | |
| 			inputPath: "/foo", | |
| 			expect:    "foo", | |
| 		}, | |
| 		{ | |
| 			inputPath: "/foo/bar", | |
| 			expect:    "foo/bar", | |
| 		}, | |
| 		{ | |
| 			inputRoot: "/a", | |
| 			inputPath: "/foo/bar", | |
| 			expect:    "/a/foo/bar", | |
| 		}, | |
| 		{ | |
| 			inputPath: "/foo/../bar", | |
| 			expect:    "bar", | |
| 		}, | |
| 		{ | |
| 			inputRoot: "/a/b", | |
| 			inputPath: "/foo/../bar", | |
| 			expect:    "/a/b/bar", | |
| 		}, | |
| 		{ | |
| 			inputRoot: "/a/b", | |
| 			inputPath: "/..%2fbar", | |
| 			expect:    "/a/b/bar", | |
| 		}, | |
| 		{ | |
| 			inputRoot: "/a/b", | |
| 			inputPath: "/%2e%2e%2fbar", | |
| 			expect:    "/a/b/bar", | |
| 		}, | |
| 		{ | |
| 			inputRoot: "/a/b", | |
| 			inputPath: "/%2e%2e%2f%2e%2e%2f", | |
| 			expect:    "/a/b", | |
| 		}, | |
| 		// TODO: test windows paths... on windows... sigh. | |
| 	} { | |
| 		// we don't *need* to use an actual parsed URL, but it | |
| 		// adds some authenticity to the tests since real-world | |
| 		// values will be coming in from URLs; thus, the test | |
| 		// corpus can contain paths as encoded by clients, which | |
| 		// more closely emulates the actual attack vector | |
| 		u, err := url.Parse("http://test:9999" + tc.inputPath) | |
| 		if err != nil { | |
| 			t.Fatalf("Test %d: invalid URL: %v", i, err) | |
| 		} | |
| 		actual := sanitizedPathJoin(tc.inputRoot, u.Path) | |
| 		if actual != tc.expect { | |
| 			t.Errorf("Test %d: [%s %s] => %s (expected %s)", i, tc.inputRoot, tc.inputPath, actual, tc.expect) | |
| 		} | |
| 	} | |
| } | |
| 
 | |
| // TODO: test fileHidden
 | |
| 
 |