mirror of
				https://github.com/golang/go.git
				synced 2025-10-31 08:40:55 +00:00 
			
		
		
		
	net/http: make http.FileServer return 404 when a path is invalid/unsafe
This PR adds error handling in net/http toHTTPError to return a 404
instead of a 500 when net/http fs.Dir.Open throws the error http:
invalid or unsafe file path.
Fixes #72091
Change-Id: I7941c8fca5160a4a82732dc1d05b9b95eac84fbf
GitHub-Last-Rev: 04b5019dfb
GitHub-Pull-Request: golang/go#72108
Reviewed-on: https://go-review.googlesource.com/c/go/+/654975
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Damien Neil <dneil@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
			
			
This commit is contained in:
		
							parent
							
								
									37026a7c56
								
							
						
					
					
						commit
						061efaa8a7
					
				
					 2 changed files with 30 additions and 1 deletions
				
			
		|  | @ -67,6 +67,11 @@ func mapOpenError(originalErr error, name string, sep rune, stat func(string) (f | ||||||
| 	return originalErr | 	return originalErr | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // errInvalidUnsafePath is returned by Dir.Open when the call to | ||||||
|  | // filepath.Localize fails. filepath.Localize returns an error if the path | ||||||
|  | // cannot be represented by the operating system. | ||||||
|  | var errInvalidUnsafePath = errors.New("http: invalid or unsafe file path") | ||||||
|  | 
 | ||||||
| // Open implements [FileSystem] using [os.Open], opening files for reading rooted | // Open implements [FileSystem] using [os.Open], opening files for reading rooted | ||||||
| // and relative to the directory d. | // and relative to the directory d. | ||||||
| func (d Dir) Open(name string) (File, error) { | func (d Dir) Open(name string) (File, error) { | ||||||
|  | @ -76,7 +81,7 @@ func (d Dir) Open(name string) (File, error) { | ||||||
| 	} | 	} | ||||||
| 	path, err := filepath.Localize(path) | 	path, err := filepath.Localize(path) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, errors.New("http: invalid or unsafe file path") | 		return nil, errInvalidUnsafePath | ||||||
| 	} | 	} | ||||||
| 	dir := string(d) | 	dir := string(d) | ||||||
| 	if dir == "" { | 	if dir == "" { | ||||||
|  | @ -768,6 +773,9 @@ func toHTTPError(err error) (msg string, httpStatus int) { | ||||||
| 	if errors.Is(err, fs.ErrPermission) { | 	if errors.Is(err, fs.ErrPermission) { | ||||||
| 		return "403 Forbidden", StatusForbidden | 		return "403 Forbidden", StatusForbidden | ||||||
| 	} | 	} | ||||||
|  | 	if errors.Is(err, errInvalidUnsafePath) { | ||||||
|  | 		return "404 page not found", StatusNotFound | ||||||
|  | 	} | ||||||
| 	// Default: | 	// Default: | ||||||
| 	return "500 Internal Server Error", StatusInternalServerError | 	return "500 Internal Server Error", StatusInternalServerError | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -733,6 +733,27 @@ func testFileServerZeroByte(t *testing.T, mode testMode) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestFileServerNullByte(t *testing.T) { run(t, testFileServerNullByte) } | ||||||
|  | func testFileServerNullByte(t *testing.T, mode testMode) { | ||||||
|  | 	ts := newClientServerTest(t, mode, FileServer(Dir("testdata"))).ts | ||||||
|  | 
 | ||||||
|  | 	for _, path := range []string{ | ||||||
|  | 		"/file%00", | ||||||
|  | 		"/%00", | ||||||
|  | 		"/file/qwe/%00", | ||||||
|  | 	} { | ||||||
|  | 		res, err := ts.Client().Get(ts.URL + path) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Fatal(err) | ||||||
|  | 		} | ||||||
|  | 		res.Body.Close() | ||||||
|  | 		if res.StatusCode != 404 { | ||||||
|  | 			t.Errorf("Get(%q): got status %v, want 404", path, res.StatusCode) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestFileServerNamesEscape(t *testing.T) { run(t, testFileServerNamesEscape) } | func TestFileServerNamesEscape(t *testing.T) { run(t, testFileServerNamesEscape) } | ||||||
| func testFileServerNamesEscape(t *testing.T, mode testMode) { | func testFileServerNamesEscape(t *testing.T, mode testMode) { | ||||||
| 	ts := newClientServerTest(t, mode, FileServer(Dir("testdata"))).ts | 	ts := newClientServerTest(t, mode, FileServer(Dir("testdata"))).ts | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Grégoire Lodi
						Grégoire Lodi