Skip to content

Commit

Permalink
make fs change back compat
Browse files Browse the repository at this point in the history
  • Loading branch information
umputun committed Aug 22, 2021
1 parent 075a441 commit 7fd99e5
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 45 deletions.
30 changes: 21 additions & 9 deletions file_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import (
"strings"
)

// FileServer provides http.FileServer handler to serve static files from a http.FileSystem,
// FS provides http.FileServer handler to serve static files from a http.FileSystem,
// prevents directory listing by default and supports spa-friendly mode (off by default) returning /index.html on 404.
// - public defines base path of the url, i.e. for http://example.com/static/* it should be /static
// - local for the local path to the root of the served directory
// - notFound is the reader for the custom 404 html, can be nil for default
type FileServer struct {
type FS struct {
public, root string
notFound io.Reader
isSpa bool
Expand All @@ -24,8 +24,8 @@ type FileServer struct {
}

// NewFileServer creates file server with optional spa mode and optional direcroty listing (disabled by default)
func NewFileServer(public, local string, options ...FSOpt) (*FileServer, error) {
res := FileServer{
func NewFileServer(public, local string, options ...FSOpt) (*FS, error) {
res := FS{
public: public,
notFound: nil,
isSpa: false,
Expand Down Expand Up @@ -73,29 +73,41 @@ func NewFileServer(public, local string, options ...FSOpt) (*FileServer, error)
return &res, nil
}

// FileServer is a shortcut for making FS with listing disabled and the custom noFound reader (can be nil).
// The method is for back-compatibility only and user should use the universal NewFileServer instead
func FileServer(public, local string, notFound io.Reader) (http.Handler, error) {
return NewFileServer(public, local, FsOptCustom404(notFound))
}

// FileServerSPA is a shortcut for making FS with SPA-friendly handling of 404, listing disabled and the custom noFound reader (can be nil).
// The method is for back-compatibility only and user should use the universal NewFileServer instead
func FileServerSPA(public, local string, notFound io.Reader) (http.Handler, error) {
return NewFileServer(public, local, FsOptCustom404(notFound), FsOptSPA)
}

// ServeHTTP makes FileServer compatible with http.Handler interface
func (fs *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func (fs *FS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fs.handler(w, r)
}

// FSOpt defines functional option type
type FSOpt func(fs *FileServer) error
type FSOpt func(fs *FS) error

// FsOptSPA turns on SPA mode returning "/index.html" on not-found
func FsOptSPA(fs *FileServer) error {
func FsOptSPA(fs *FS) error {
fs.isSpa = true
return nil
}

// FsOptListing turns on directory listing
func FsOptListing(fs *FileServer) error {
func FsOptListing(fs *FS) error {
fs.enableListing = true
return nil
}

// FsOptCustom404 sets custom 404 reader
func FsOptCustom404(fr io.Reader) FSOpt {
return func(fs *FileServer) error {
return func(fs *FS) error {
fs.notFound = fr
return nil
}
Expand Down
86 changes: 50 additions & 36 deletions file_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@ import (
)

func TestFileServerDefault(t *testing.T) {
fh, err := NewFileServer("/static", "./testdata/root")
fh1, err := NewFileServer("/static", "./testdata/root")
require.NoError(t, err)
ts := httptest.NewServer(logger.Logger(fh))
defer ts.Close()

fh2, err := FileServer("/static", "./testdata/root", nil)
require.NoError(t, err)

ts1 := httptest.NewServer(logger.Logger(fh1))
defer ts1.Close()
ts2 := httptest.NewServer(logger.Logger(fh2))
defer ts2.Close()

client := http.Client{Timeout: 599 * time.Second}

tbl := []struct {
Expand Down Expand Up @@ -48,22 +55,23 @@ func TestFileServerDefault(t *testing.T) {
for i, tt := range tbl {
tt := tt
t.Run(strconv.Itoa(i), func(t *testing.T) {
req, err := http.NewRequest("GET", ts.URL+tt.req, nil)
require.NoError(t, err)
resp, err := client.Do(req)
require.NoError(t, err)
t.Logf("headers: %v", resp.Header)
assert.Equal(t, tt.status, resp.StatusCode)
if resp.StatusCode == http.StatusNotFound {
msg, e := ioutil.ReadAll(resp.Body)
require.NoError(t, e)
assert.Equal(t, "404 page not found\n", string(msg))
return
for _, ts := range []*httptest.Server{ts1, ts2} {
req, err := http.NewRequest("GET", ts.URL+tt.req, nil)
require.NoError(t, err)
resp, err := client.Do(req)
require.NoError(t, err)
t.Logf("headers: %v", resp.Header)
assert.Equal(t, tt.status, resp.StatusCode)
if resp.StatusCode == http.StatusNotFound {
msg, e := ioutil.ReadAll(resp.Body)
require.NoError(t, e)
assert.Equal(t, "404 page not found\n", string(msg))
return
}
body, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, tt.body, string(body))
}
body, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, tt.body, string(body))

})
}
}
Expand Down Expand Up @@ -165,10 +173,15 @@ func TestFileServer_Custom404(t *testing.T) {
}

func TestFileServerSPA(t *testing.T) {
fh, err := NewFileServer("/static", "./testdata/root", FsOptSPA)
fh1, err := NewFileServer("/static", "./testdata/root", FsOptSPA)
require.NoError(t, err)
ts := httptest.NewServer(logger.Logger(fh))
defer ts.Close()
fh2, err := FileServerSPA("/static", "./testdata/root", nil)
require.NoError(t, err)

ts1 := httptest.NewServer(logger.Logger(fh1))
defer ts1.Close()
ts2 := httptest.NewServer(logger.Logger(fh2))
defer ts2.Close()
client := http.Client{Timeout: 599 * time.Second}

tbl := []struct {
Expand Down Expand Up @@ -199,22 +212,23 @@ func TestFileServerSPA(t *testing.T) {
for i, tt := range tbl {
tt := tt
t.Run(strconv.Itoa(i), func(t *testing.T) {
req, err := http.NewRequest("GET", ts.URL+tt.req, nil)
require.NoError(t, err)
resp, err := client.Do(req)
require.NoError(t, err)
t.Logf("headers: %v", resp.Header)
assert.Equal(t, tt.status, resp.StatusCode)
if resp.StatusCode == http.StatusNotFound {
msg, e := ioutil.ReadAll(resp.Body)
require.NoError(t, e)
assert.Equal(t, "404 page not found\n", string(msg))
return
for _, ts := range []*httptest.Server{ts1, ts2} {
req, err := http.NewRequest("GET", ts.URL+tt.req, nil)
require.NoError(t, err)
resp, err := client.Do(req)
require.NoError(t, err)
t.Logf("headers: %v", resp.Header)
assert.Equal(t, tt.status, resp.StatusCode)
if resp.StatusCode == http.StatusNotFound {
msg, e := ioutil.ReadAll(resp.Body)
require.NoError(t, e)
assert.Equal(t, "404 page not found\n", string(msg))
return
}
body, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, tt.body, string(body))
}
body, err := ioutil.ReadAll(resp.Body)
require.NoError(t, err)
assert.Equal(t, tt.body, string(body))

})
}
}

0 comments on commit 7fd99e5

Please sign in to comment.