// 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 ( "context" "net/http" "net/http/httptest" "os" "path/filepath" "runtime" "strings" "testing" "time" "github.com/caddyserver/caddy/v2" ) func TestFileHidden(t *testing.T) { for i, tc := range []struct { inputHide []string inputPath string expect bool }{ { inputHide: nil, inputPath: "", expect: false, }, { inputHide: []string{".gitignore"}, inputPath: "/.gitignore", expect: true, }, { inputHide: []string{".git"}, inputPath: "/.gitignore", expect: false, }, { inputHide: []string{"/.git"}, inputPath: "/.gitignore", expect: false, }, { inputHide: []string{".git"}, inputPath: "/.git", expect: true, }, { inputHide: []string{".git"}, inputPath: "/.git/foo", expect: true, }, { inputHide: []string{".git"}, inputPath: "/foo/.git/bar", expect: true, }, { inputHide: []string{"/prefix"}, inputPath: "/prefix/foo", expect: true, }, { inputHide: []string{"/foo/*/bar"}, inputPath: "/foo/asdf/bar", expect: true, }, { inputHide: []string{"*.txt"}, inputPath: "/foo/bar.txt", expect: true, }, { inputHide: []string{"/foo/bar/*.txt"}, inputPath: "/foo/bar/baz.txt", expect: true, }, { inputHide: []string{"/foo/bar/*.txt"}, inputPath: "/foo/bar.txt", expect: false, }, { inputHide: []string{"/foo/bar/*.txt"}, inputPath: "/foo/bar/index.html", expect: false, }, { inputHide: []string{"/foo"}, inputPath: "/foo", expect: true, }, { inputHide: []string{"/foo"}, inputPath: "/foobar", expect: false, }, { inputHide: []string{"first", "second"}, inputPath: "/second", expect: true, }, } { if runtime.GOOS == "windows" { if strings.HasPrefix(tc.inputPath, "/") { tc.inputPath, _ = filepath.Abs(tc.inputPath) } tc.inputPath = filepath.FromSlash(tc.inputPath) for i := range tc.inputHide { if strings.HasPrefix(tc.inputHide[i], "/") { tc.inputHide[i], _ = filepath.Abs(tc.inputHide[i]) } tc.inputHide[i] = filepath.FromSlash(tc.inputHide[i]) } } actual := fileHidden(tc.inputPath, tc.inputHide) if actual != tc.expect { t.Errorf("Test %d: Does %v hide %s? Got %t but expected %t", i, tc.inputHide, tc.inputPath, actual, tc.expect) } } } // Check to make sure that we don't serve ETag and Last-Modified headers // for files with invalid modification times func TestModTimeHeaders(t *testing.T) { check_validator_headers(time.Now(), true, t) check_validator_headers(time.Unix(0, 0), false, t) check_validator_headers(time.Unix(1, 0), false, t) check_validator_headers(time.Unix(2, 0), true, t) } func check_validator_headers(modTime time.Time, expect_headers bool, t *testing.T) { f := false fsrv := FileServer{ Root: "./testdata", CanonicalURIs: &f, } w := httptest.NewRecorder() r, err := http.NewRequest("GET", "/modtime.txt", nil) if err != nil { t.Fatal(err) } repl := caddy.NewReplacer() ctx := context.WithValue(r.Context(), caddy.ReplacerCtxKey, repl) r = r.WithContext(ctx) ctx2, _ := caddy.NewContext(caddy.Context{Context: context.Background()}) // module will be nil by default fsrv.Provision(ctx2) path := "testdata/modtime.txt" os.Chtimes(path, modTime, modTime) fsrv.ServeHTTP(w, r, nil) if expect_headers { if w.Header().Get("ETag") == "" { t.Errorf("Didn't get ETag header for file with valid mod time %s", modTime) } if w.Header().Get("Last-Modified") == "" { t.Errorf("Didn't get Last-Modified header for file with valid mod time %s", modTime) } } else { if w.Header().Get("ETag") != "" { t.Errorf("Got ETag header for file with invalid mod time %s", modTime) } if w.Header().Get("Last-Modified") != "" { t.Errorf("Got Last-Modified header for file with invalid mod time %s", modTime) } } }