Skip to content

Commit d41184b

Browse files
committed
fileserver struct rather than DefaultServeMux
1 parent b172369 commit d41184b

File tree

8 files changed

+132
-51
lines changed

8 files changed

+132
-51
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,27 @@ to your `$PATH`, can now be used.
8888
serve version
8989
```
9090

91+
## Using `serve` manually
92+
93+
Serve also exposes a reusable `FileServer` convenience struct, letting you
94+
easily create your own static file server:
95+
96+
```go
97+
package main
98+
99+
import (
100+
"log"
101+
"net/http"
102+
103+
"github.com/syntaqx/serve"
104+
)
105+
106+
func main() {
107+
fs := serve.NewFileServer(".")
108+
log.Fatal(http.ListenAndServe(":8080", fs))
109+
}
110+
```
111+
91112
## License
92113

93114
[MIT]: https://opensource.org/licenses/MIT

example/simple/main.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"net/http"
6+
7+
"github.com/syntaqx/serve"
8+
)
9+
10+
func main() {
11+
fs := serve.NewFileServer(".")
12+
log.Fatal(http.ListenAndServe(":8080", fs))
13+
}

internal/commands/server.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,23 @@ import (
88
"strconv"
99
"time"
1010

11+
"github.com/syntaqx/serve"
1112
"github.com/syntaqx/serve/internal/config"
12-
"github.com/syntaqx/serve/internal/router"
13+
"github.com/syntaqx/serve/internal/middleware"
1314
)
1415

1516
// Server implements the static http server command.
1617
func Server(log *log.Logger, opt config.Flags) error {
17-
r := router.NewRouter(log, opt)
18+
fs := serve.NewFileServer(opt.Dir)
19+
20+
fs.Use(middleware.Logger(log))
21+
fs.Use(middleware.Recover())
22+
fs.Use(middleware.CORS())
23+
fs.Use(middleware.NoCache())
1824

1925
server := &http.Server{
2026
Addr: net.JoinHostPort(opt.Host, strconv.Itoa(opt.Port)),
21-
Handler: r,
27+
Handler: fs,
2228
ReadTimeout: 15 * time.Second,
2329
WriteTimeout: 15 * time.Second,
2430
}

internal/middleware/recover_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ func TestRecover(t *testing.T) {
2525
Recover()(testHandler).ServeHTTP(res, req)
2626

2727
assert.Equal(http.StatusInternalServerError, res.Code)
28-
assert.Equal(strings.TrimSpace(res.Body.String()), "[PANIC RECOVERED] test")
28+
assert.Equal("[PANIC RECOVERED] test", strings.TrimSpace(res.Body.String()))
2929
}

internal/router/router.go

Lines changed: 0 additions & 25 deletions
This file was deleted.

internal/router/router_test.go

Lines changed: 0 additions & 22 deletions
This file was deleted.

serve.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,28 @@
11
// Package serve provides a static http server anywhere you need one.
22
package serve
3+
4+
import "net/http"
5+
6+
// FileServer implements the http.FileServer.
7+
type FileServer struct {
8+
Handler http.Handler
9+
}
10+
11+
// NewFileServer initializes a FileServer.
12+
func NewFileServer(dir string) *FileServer {
13+
fs := &FileServer{
14+
Handler: http.FileServer(http.Dir(dir)),
15+
}
16+
17+
return fs
18+
}
19+
20+
// Use wraps the handler with another, middleware style.
21+
func (fs *FileServer) Use(h func(http.Handler) http.Handler) {
22+
fs.Handler = h(fs.Handler)
23+
}
24+
25+
// ServeHTTP implements the net/http.Handler interface.
26+
func (fs *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
27+
fs.Handler.ServeHTTP(w, r)
28+
}

serve_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package serve
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestFileServerUse(t *testing.T) {
12+
t.Parallel()
13+
assert := assert.New(t)
14+
15+
req, err := http.NewRequest(http.MethodGet, "/", nil)
16+
assert.NoError(err)
17+
res := httptest.NewRecorder()
18+
19+
testMiddleware1 := func(next http.Handler) http.Handler {
20+
fn := func(w http.ResponseWriter, r *http.Request) {
21+
_, _ = w.Write([]byte("start\n"))
22+
next.ServeHTTP(w, r)
23+
}
24+
return http.HandlerFunc(fn)
25+
}
26+
27+
testMiddleware2 := func(next http.Handler) http.Handler {
28+
fn := func(w http.ResponseWriter, r *http.Request) {
29+
_, _ = w.Write([]byte("end\n"))
30+
}
31+
return http.HandlerFunc(fn)
32+
}
33+
34+
fs := NewFileServer(".")
35+
fs.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
36+
t.Fail()
37+
})
38+
39+
fs.Use(testMiddleware2)
40+
fs.Use(testMiddleware1)
41+
42+
fs.ServeHTTP(res, req)
43+
44+
assert.Equal("start\nend\n", res.Body.String())
45+
}
46+
47+
func TestFileServerServeHTTP(t *testing.T) {
48+
t.Parallel()
49+
assert := assert.New(t)
50+
51+
req, err := http.NewRequest(http.MethodGet, "/", nil)
52+
assert.NoError(err)
53+
res := httptest.NewRecorder()
54+
55+
fs := NewFileServer(".")
56+
fs.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
57+
_, _ = w.Write([]byte("expected"))
58+
})
59+
fs.ServeHTTP(res, req)
60+
61+
assert.Equal("expected", res.Body.String())
62+
}

0 commit comments

Comments
 (0)