}
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.
"reflect"
"regexp"
"runtime"
+ "sort"
"strings"
"testing"
"time"
}
}
+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")