forked from teambition/gear
-
Notifications
You must be signed in to change notification settings - Fork 0
/
static.go
96 lines (88 loc) · 2.27 KB
/
static.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package static
import (
"bytes"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"github.com/teambition/gear"
)
// Options is static middleware options
type Options struct {
Root string // The directory you wish to serve
Prefix string // The url prefix you wish to serve as static request, default to `'/'`.
StripPrefix bool // Strip the prefix from URL path, default to `false`.
Files map[string][]byte // Optional, a map of File objects to serve.
}
// New creates a static middleware to serves static content from the provided root directory.
//
// package main
//
// import (
// "github.com/teambition/gear"
// "github.com/teambition/gear/middleware/favicon"
// "github.com/teambition/gear/middleware/static"
// )
//
// func main() {
// app := gear.New()
// app.Use(favicon.New("./testdata/favicon.ico"))
// app.Use(static.New(static.Options{
// Root: "./testdata",
// Prefix: "/",
// StripPrefix: false,
// }))
// app.Use(func(ctx *gear.Context) error {
// return ctx.HTML(200, "<h1>Hello, Gear!</h1>")
// })
// app.Error(app.Listen(":3000"))
// }
//
func New(opts Options) gear.Middleware {
modTime := time.Now()
if opts.Root == "" {
opts.Root = "."
}
root := filepath.FromSlash(opts.Root)
if root[0] == '.' {
wd, err := os.Getwd()
if err != nil {
panic(err)
}
root = filepath.Join(wd, root)
}
info, _ := os.Stat(root)
if info == nil || !info.IsDir() {
panic(gear.Err.WithMsgf("invalid root path: %s", root))
}
if opts.Prefix == "" {
opts.Prefix = "/"
}
return func(ctx *gear.Context) (err error) {
path := ctx.Path
if !strings.HasPrefix(path, opts.Prefix) {
return nil
}
if ctx.Method != http.MethodGet && ctx.Method != http.MethodHead {
status := 200
if ctx.Method != http.MethodOptions {
status = 405
}
ctx.Set(gear.HeaderAllow, "GET, HEAD, OPTIONS")
return ctx.End(status)
}
if opts.StripPrefix {
path = strings.TrimPrefix(path, opts.Prefix)
}
if opts.Files != nil {
if file, ok := opts.Files[path]; ok {
http.ServeContent(ctx.Res, ctx.Req, path, modTime, bytes.NewReader(file))
return nil
}
}
path = filepath.Join(root, filepath.FromSlash(path))
http.ServeFile(ctx.Res, ctx.Req, path)
return nil
}
}