From 49cacce22f2a1d0939df6a4ed276066c1f6dd2b2 Mon Sep 17 00:00:00 2001 From: Adphi Date: Wed, 29 Jun 2022 20:13:40 +0200 Subject: [PATCH] add fs.FS support (#19) Signed-off-by: Adphi --- fileserver_test.go | 155 ++++++++++++++++++++++++++++++--------------- filesystem.go | 23 +++++++ go.mod | 6 +- go.sum | 3 - 4 files changed, 129 insertions(+), 58 deletions(-) diff --git a/fileserver_test.go b/fileserver_test.go index 6e41f7e..343113f 100644 --- a/fileserver_test.go +++ b/fileserver_test.go @@ -3,6 +3,8 @@ package gzipped import ( "bytes" "compress/gzip" + "embed" + fs2 "io/fs" "io/ioutil" "net/http" "net/http/httptest" @@ -34,8 +36,8 @@ func TestPreference(t *testing.T) { } } -func testGet(t *testing.T, acceptGzip bool, urlPath string, expectedBody string) { - fs := FileServer(Dir("./testdata/")) +func testGet(t *testing.T, f FileSystem, acceptGzip bool, urlPath string, expectedBody string) { + fs := FileServer(f) rr := httptest.NewRecorder() req, _ := http.NewRequest("GET", urlPath, nil) if acceptGzip { @@ -88,62 +90,113 @@ func testGet(t *testing.T, acceptGzip bool, urlPath string, expectedBody string) } } -func TestOpenStat(t *testing.T) { - fh := &fileHandler{Dir(".")} - _, _, err := fh.openAndStat(".") - if err == nil { - t.Errorf("openAndStat directory succeeded, should have failed") - } - _, _, err = fh.openAndStat("updog") - if err == nil { - t.Errorf("openAndStat nonexistent file succeeded, should have failed") - } -} +//go:embed testdata +var testData embed.FS -func TestNoBrowse(t *testing.T) { - fs := FileServer(Dir("./testdata/")) - rr := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) - fs.ServeHTTP(rr, req) - if rr.Code != 404 { - t.Errorf("Directory browse succeeded") - } +type TestCase struct { + name string + test func(t *testing.T) } -func TestLeadingSlash(t *testing.T) { - fs := FileServer(Dir("./testdata/")) - rr := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "file.txt", nil) - fs.ServeHTTP(rr, req) - if rr.Code != 200 { - t.Errorf("Missing leading / on HTTP path caused error") +func TestFileServer(t *testing.T) { + tests := func(f FileSystem) []TestCase { + return []TestCase{ + { + name: "OpenStat", + test: func(t *testing.T) { + fh := &fileHandler{f} + _, _, err := fh.openAndStat(".") + if err == nil { + t.Errorf("openAndStat directory succeeded, should have failed") + } + _, _, err = fh.openAndStat("updog") + if err == nil { + t.Errorf("openAndStat nonexistent file succeeded, should have failed") + } + }, + }, + { + + name: "NoBrowse", + test: func(t *testing.T) { + fs := FileServer(f) + rr := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/", nil) + fs.ServeHTTP(rr, req) + if rr.Code != 404 { + t.Errorf("Directory browse succeeded") + } + }, + }, + { + + name: "LeadingSlash", + test: func(t *testing.T) { + fs := FileServer(f) + rr := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "file.txt", nil) + fs.ServeHTTP(rr, req) + if rr.Code != 200 { + t.Errorf("Missing leading / on HTTP path caused error") + } + }, + }, + { + + name: "404", + test: func(t *testing.T) { + fs := FileServer(f) + rr := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/nonexistent.txt", nil) + fs.ServeHTTP(rr, req) + if rr.Code != 404 { + t.Errorf("Directory browse succeeded") + } + }, + }, + { + + name: "Get", + test: func(t *testing.T) { + testGet(t, f, false, "/file.txt", "zyxwvutsrqponmlkjihgfedcba\n") + }, + }, + { + + name: "GzipGet", + test: func(t *testing.T) { + testGet(t, f, true, "/file.txt", "abcdefghijklmnopqrstuvwxyz\n") + }, + }, + { + + name: "GetIdentity", + test: func(t *testing.T) { + testGet(t, f, false, "/file2.txt", "1234567890987654321\n") + }, + }, + { + + name: "GzipGetIdentity", + test: func(t *testing.T) { + testGet(t, f, true, "/file2.txt", "1234567890987654321\n") + }, + }, + } } -} -func Test404(t *testing.T) { - fs := FileServer(Dir("./testdata/")) - rr := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/nonexistent.txt", nil) - fs.ServeHTTP(rr, req) - if rr.Code != 404 { - t.Errorf("Directory browse succeeded") + sub, err := fs2.Sub(testData, "testdata") + if err != nil { + t.Fatal(err) } -} - -func TestGet(t *testing.T) { - testGet(t, false, "/file.txt", "zyxwvutsrqponmlkjihgfedcba\n") -} - -func TestGzipGet(t *testing.T) { - testGet(t, true, "/file.txt", "abcdefghijklmnopqrstuvwxyz\n") -} - -func TestGetIdentity(t *testing.T) { - testGet(t, false, "/file2.txt", "1234567890987654321\n") -} -func TestGzipGetIdentity(t *testing.T) { - testGet(t, true, "/file2.txt", "1234567890987654321\n") + for name, fs := range map[string]FileSystem{"dir": Dir("./testdata/"), "fs": FS(sub)} { + t.Run(name, func(t *testing.T) { + for _, tt := range tests(fs) { + t.Run(tt.name, tt.test) + } + }) + } } func TestConstHeaders(t *testing.T) { diff --git a/filesystem.go b/filesystem.go index 09d113b..4f268e2 100644 --- a/filesystem.go +++ b/filesystem.go @@ -1,6 +1,7 @@ package gzipped import ( + fs2 "io/fs" "net/http" "os" "path" @@ -36,3 +37,25 @@ func (d Dir) Exists(name string) bool { func (d Dir) Open(name string) (http.File, error) { return http.Dir(d).Open(name) } + +func FS(f fs2.FS) FileSystem { + return fs{fs: f} +} + +type fs struct { + fs fs2.FS +} + +// Exists tests whether a file with the specified name exists, resolved relative to the file system. +func (f fs) Exists(name string) bool { + if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) { + return false + } + _, err := fs2.Stat(f.fs, strings.TrimPrefix(filepath.FromSlash(path.Clean(name)), "/")) + return err == nil +} + +// Open defers to http.FS's Open so that gzipped.fs implements http.FileSystem. +func (f fs) Open(name string) (http.File, error) { + return http.FS(f.fs).Open(strings.TrimPrefix(name, "/")) +} diff --git a/go.mod b/go.mod index 2723db0..0bcceea 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,5 @@ module github.com/lpar/gzipped/v2 -require ( - github.com/kevinpollet/nego v0.0.0-20200324111829-b3061ca9dd9d -) +require github.com/kevinpollet/nego v0.0.0-20200324111829-b3061ca9dd9d -go 1.13 +go 1.16 diff --git a/go.sum b/go.sum index bf153be..28393a6 100644 --- a/go.sum +++ b/go.sum @@ -2,14 +2,11 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/kevinpollet/nego v0.0.0-20200324111829-b3061ca9dd9d h1:BaIpmhcqpBnz4+NZjUjVGxKNA+/E7ovKsjmwqjXcGYc= github.com/kevinpollet/nego v0.0.0-20200324111829-b3061ca9dd9d/go.mod h1:3FSWkzk9h42opyV0o357Fq6gsLF/A6MI/qOca9kKobY= -github.com/lpar/accept v0.1.0 h1:q4+k1TJuCfoe8cIBRLTfiMMoiaHKpn1rlD1yYE/wj7o= -github.com/lpar/accept v0.1.0/go.mod h1:/ZcJqAhzugu4J4EZ7hwixKslL0y07dMxQzIZZLpbZbk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=