aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPascal S. de Kloe <pascal@quies.net>2022-06-21 18:50:35 +0200
committerDavid Chase <drchase@google.com>2022-08-29 17:12:01 +0000
commit0e16d67a560f22ac1fcbc1fa12d25add8bf649d6 (patch)
tree27c837f5c860c44a73189eaadf061342ebe95c8d /src
parenteeb1ba7a89975beb1993242d8f2db05a6237e01c (diff)
downloadgo-0e16d67a560f22ac1fcbc1fa12d25add8bf649d6.tar.xz
net/http: FileServer method check + minimal OPTIONS implementation
FileServer provides a read-only service. Methods other than GET or HEAD should be denied with an Allow header. Fixes #53501 Change-Id: I1d31b405eefd90565ecd474ac3f8d8d6e3b15072 Reviewed-on: https://go-review.googlesource.com/c/go/+/413554 TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Damien Neil <dneil@google.com> Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: Heschi Kreinick <heschi@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/net/http/fs.go20
-rw-r--r--src/net/http/fs_test.go42
2 files changed, 57 insertions, 5 deletions
diff --git a/src/net/http/fs.go b/src/net/http/fs.go
index 87caeb7e90..cf80018b5e 100644
--- a/src/net/http/fs.go
+++ b/src/net/http/fs.go
@@ -843,12 +843,22 @@ func FileServer(root FileSystem) Handler {
}
func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
- upath := r.URL.Path
- if !strings.HasPrefix(upath, "/") {
- upath = "/" + upath
- r.URL.Path = upath
+ const options = MethodOptions + ", " + MethodGet + ", " + MethodHead
+
+ switch r.Method {
+ case MethodGet, MethodHead:
+ if !strings.HasPrefix(r.URL.Path, "/") {
+ r.URL.Path = "/" + r.URL.Path
+ }
+ serveFile(w, r, f.root, path.Clean(r.URL.Path), true)
+
+ case MethodOptions:
+ w.Header().Set("Allow", options)
+
+ default:
+ w.Header().Set("Allow", options)
+ Error(w, "read-only", StatusMethodNotAllowed)
}
- serveFile(w, r, f.root, path.Clean(upath), true)
}
// httpRange specifies the byte range to be sent to the client.
diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go
index 4be561cdfa..077c037c85 100644
--- a/src/net/http/fs_test.go
+++ b/src/net/http/fs_test.go
@@ -24,6 +24,7 @@ import (
"reflect"
"regexp"
"runtime"
+ "sort"
"strings"
"testing"
"time"
@@ -404,6 +405,47 @@ func TestFileServerImplicitLeadingSlash(t *testing.T) {
}
}
+func TestFileServerMethodOptions(t *testing.T) {
+ defer afterTest(t)
+ const want = "GET, HEAD, OPTIONS"
+ ts := httptest.NewServer(FileServer(Dir(".")))
+ defer ts.Close()
+
+ tests := []struct {
+ method string
+ wantStatus int
+ }{
+ {MethodOptions, StatusOK},
+
+ {MethodDelete, StatusMethodNotAllowed},
+ {MethodPut, StatusMethodNotAllowed},
+ {MethodPost, StatusMethodNotAllowed},
+ }
+
+ for _, test := range tests {
+ req, err := NewRequest(test.method, ts.URL, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res, err := ts.Client().Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+
+ if res.StatusCode != test.wantStatus {
+ t.Errorf("%s got status %q, want code %d", test.method, res.Status, test.wantStatus)
+ }
+
+ a := strings.Split(res.Header.Get("Allow"), ", ")
+ sort.Strings(a)
+ got := strings.Join(a, ", ")
+ if got != want {
+ t.Errorf("%s got Allow header %q, want %q", test.method, got, want)
+ }
+ }
+}
+
func TestDirJoin(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping test on windows")