@@ -7,6 +7,7 @@ package public
7
7
import (
8
8
"net/http"
9
9
"os"
10
+ "path"
10
11
"path/filepath"
11
12
"strings"
12
13
@@ -17,12 +18,13 @@ import (
17
18
18
19
// Options represents the available options to configure the handler.
19
20
type Options struct {
20
- Directory string
21
- Prefix string
21
+ Directory string
22
+ Prefix string
23
+ CorsHandler func (http.Handler ) http.Handler
22
24
}
23
25
24
26
// AssetsHandler implements the static handler for serving custom or original assets.
25
- func AssetsHandler (opts * Options ) func (resp http.ResponseWriter , req * http.Request ) {
27
+ func AssetsHandler (opts * Options ) func (next http.Handler ) http.Handler {
26
28
var custPath = filepath .Join (setting .CustomPath , "public" )
27
29
if ! filepath .IsAbs (custPath ) {
28
30
custPath = filepath .Join (setting .AppWorkPath , custPath )
@@ -31,19 +33,55 @@ func AssetsHandler(opts *Options) func(resp http.ResponseWriter, req *http.Reque
31
33
if ! filepath .IsAbs (opts .Directory ) {
32
34
opts .Directory = filepath .Join (setting .AppWorkPath , opts .Directory )
33
35
}
36
+ if opts .Prefix == "" {
37
+ opts .Prefix = "/"
38
+ }
34
39
35
- return func (resp http.ResponseWriter , req * http.Request ) {
36
- // custom files
37
- if opts .handle (resp , req , http .Dir (custPath ), opts .Prefix ) {
38
- return
39
- }
40
-
41
- // internal files
42
- if opts .handle (resp , req , fileSystem (opts .Directory ), opts .Prefix ) {
43
- return
44
- }
45
-
46
- resp .WriteHeader (404 )
40
+ return func (next http.Handler ) http.Handler {
41
+ return http .HandlerFunc (func (resp http.ResponseWriter , req * http.Request ) {
42
+ if ! strings .HasPrefix (req .URL .Path , opts .Prefix ) {
43
+ next .ServeHTTP (resp , req )
44
+ return
45
+ }
46
+ if req .Method != "GET" && req .Method != "HEAD" {
47
+ resp .WriteHeader (http .StatusNotFound )
48
+ return
49
+ }
50
+
51
+ file := req .URL .Path
52
+ file = file [len (opts .Prefix ):]
53
+ if len (file ) == 0 {
54
+ resp .WriteHeader (http .StatusNotFound )
55
+ return
56
+ }
57
+ if ! strings .HasPrefix (file , "/" ) {
58
+ next .ServeHTTP (resp , req )
59
+ return
60
+ }
61
+
62
+ var written bool
63
+ if opts .CorsHandler != nil {
64
+ written = true
65
+ opts .CorsHandler (http .HandlerFunc (func (http.ResponseWriter , * http.Request ) {
66
+ written = false
67
+ })).ServeHTTP (resp , req )
68
+ }
69
+ if written {
70
+ return
71
+ }
72
+
73
+ // custom files
74
+ if opts .handle (resp , req , http .Dir (custPath ), file ) {
75
+ return
76
+ }
77
+
78
+ // internal files
79
+ if opts .handle (resp , req , fileSystem (opts .Directory ), file ) {
80
+ return
81
+ }
82
+
83
+ resp .WriteHeader (http .StatusNotFound )
84
+ })
47
85
}
48
86
}
49
87
@@ -57,44 +95,29 @@ func parseAcceptEncoding(val string) map[string]bool {
57
95
return types
58
96
}
59
97
60
- func (opts * Options ) handle (w http.ResponseWriter , req * http.Request , fs http.FileSystem , prefix string ) bool {
61
- if req .Method != "GET" && req .Method != "HEAD" {
62
- return false
63
- }
64
-
65
- file := req .URL .Path
66
- // if we have a prefix, filter requests by stripping the prefix
67
- if prefix != "" {
68
- if ! strings .HasPrefix (file , prefix ) {
69
- return false
70
- }
71
- file = file [len (prefix ):]
72
- if file != "" && file [0 ] != '/' {
73
- return false
74
- }
75
- }
76
-
77
- f , err := fs .Open (file )
98
+ func (opts * Options ) handle (w http.ResponseWriter , req * http.Request , fs http.FileSystem , file string ) bool {
99
+ // use clean to keep the file is a valid path with no . or ..
100
+ f , err := fs .Open (path .Clean (file ))
78
101
if err != nil {
79
102
if os .IsNotExist (err ) {
80
103
return false
81
104
}
82
- w .WriteHeader (500 )
105
+ w .WriteHeader (http . StatusInternalServerError )
83
106
log .Error ("[Static] Open %q failed: %v" , file , err )
84
107
return true
85
108
}
86
109
defer f .Close ()
87
110
88
111
fi , err := f .Stat ()
89
112
if err != nil {
90
- w .WriteHeader (500 )
113
+ w .WriteHeader (http . StatusInternalServerError )
91
114
log .Error ("[Static] %q exists, but fails to open: %v" , file , err )
92
115
return true
93
116
}
94
117
95
118
// Try to serve index file
96
119
if fi .IsDir () {
97
- w .WriteHeader (404 )
120
+ w .WriteHeader (http . StatusNotFound )
98
121
return true
99
122
}
100
123
0 commit comments