@@ -7,6 +7,7 @@ package public
77import (
88 "net/http"
99 "os"
10+ "path"
1011 "path/filepath"
1112 "strings"
1213
@@ -17,12 +18,13 @@ import (
1718
1819// Options represents the available options to configure the handler.
1920type Options struct {
20- Directory string
21- Prefix string
21+ Directory string
22+ Prefix string
23+ CorsHandler func (http.Handler ) http.Handler
2224}
2325
2426// 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 {
2628 var custPath = filepath .Join (setting .CustomPath , "public" )
2729 if ! filepath .IsAbs (custPath ) {
2830 custPath = filepath .Join (setting .AppWorkPath , custPath )
@@ -31,19 +33,55 @@ func AssetsHandler(opts *Options) func(resp http.ResponseWriter, req *http.Reque
3133 if ! filepath .IsAbs (opts .Directory ) {
3234 opts .Directory = filepath .Join (setting .AppWorkPath , opts .Directory )
3335 }
36+ if opts .Prefix == "" {
37+ opts .Prefix = "/"
38+ }
3439
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+ })
4785 }
4886}
4987
@@ -57,44 +95,29 @@ func parseAcceptEncoding(val string) map[string]bool {
5795 return types
5896}
5997
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 ))
78101 if err != nil {
79102 if os .IsNotExist (err ) {
80103 return false
81104 }
82- w .WriteHeader (500 )
105+ w .WriteHeader (http . StatusInternalServerError )
83106 log .Error ("[Static] Open %q failed: %v" , file , err )
84107 return true
85108 }
86109 defer f .Close ()
87110
88111 fi , err := f .Stat ()
89112 if err != nil {
90- w .WriteHeader (500 )
113+ w .WriteHeader (http . StatusInternalServerError )
91114 log .Error ("[Static] %q exists, but fails to open: %v" , file , err )
92115 return true
93116 }
94117
95118 // Try to serve index file
96119 if fi .IsDir () {
97- w .WriteHeader (404 )
120+ w .WriteHeader (http . StatusNotFound )
98121 return true
99122 }
100123
0 commit comments