Skip to content

Commit b58830f

Browse files
committed
Still use middleware to serve assets then less middleware stack for assets
1 parent 0fba106 commit b58830f

File tree

4 files changed

+73
-55
lines changed

4 files changed

+73
-55
lines changed

modules/public/public.go

+59-36
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package public
77
import (
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.
1920
type 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

modules/public/static.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func serveContent(w http.ResponseWriter, req *http.Request, fi os.FileInfo, modt
4141
_, err := rd.Seek(0, io.SeekStart) // rewind to output whole file
4242
if err != nil {
4343
log.Error("rd.Seek error: %v", err)
44-
http.Error(w, http.StatusText(500), 500)
44+
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
4545
return
4646
}
4747
}

routers/routes/install.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ func InstallRoutes() *web.Route {
8181
r.Use(middle)
8282
}
8383

84+
r.Use(public.AssetsHandler(&public.Options{
85+
Directory: path.Join(setting.StaticRootPath, "public"),
86+
Prefix: "/assets",
87+
}))
88+
8489
r.Use(session.Sessioner(session.Options{
8590
Provider: setting.SessionConfig.Provider,
8691
ProviderConfig: setting.SessionConfig.ProviderConfig,
@@ -95,11 +100,6 @@ func InstallRoutes() *web.Route {
95100
r.Use(installRecovery())
96101
r.Use(routers.InstallInit)
97102

98-
r.Route("/assets/*", "GET, HEAD", corsHandler, public.AssetsHandler(&public.Options{
99-
Directory: path.Join(setting.StaticRootPath, "public"),
100-
Prefix: "/assets",
101-
}))
102-
103103
r.Get("/", routers.Install)
104104
r.Post("/", web.Bind(forms.InstallForm{}), routers.InstallPost)
105105
r.NotFound(func(w http.ResponseWriter, req *http.Request) {

routers/routes/web.go

+8-13
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,7 @@ func NormalRoutes() *web.Route {
133133
})
134134
} else {
135135
corsHandler = func(next http.Handler) http.Handler {
136-
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
137-
next.ServeHTTP(resp, req)
138-
})
136+
return next
139137
}
140138
}
141139

@@ -149,6 +147,12 @@ func NormalRoutes() *web.Route {
149147
func WebRoutes() *web.Route {
150148
routes := web.NewRoute()
151149

150+
routes.Use(public.AssetsHandler(&public.Options{
151+
Directory: path.Join(setting.StaticRootPath, "public"),
152+
Prefix: "/assets",
153+
CorsHandler: corsHandler,
154+
}))
155+
152156
routes.Use(session.Sessioner(session.Options{
153157
Provider: setting.SessionConfig.Provider,
154158
ProviderConfig: setting.SessionConfig.ProviderConfig,
@@ -162,11 +166,6 @@ func WebRoutes() *web.Route {
162166

163167
routes.Use(Recovery())
164168

165-
routes.Route("/assets/*", "GET, HEAD", corsHandler, public.AssetsHandler(&public.Options{
166-
Directory: path.Join(setting.StaticRootPath, "public"),
167-
Prefix: "/assets",
168-
}))
169-
170169
// We use r.Route here over r.Use because this prevents requests that are not for avatars having to go through this additional handler
171170
routes.Route("/avatars/*", "GET, HEAD", storageHandler(setting.Avatar.Storage, "avatars", storage.Avatars))
172171
routes.Route("/repo-avatars/*", "GET, HEAD", storageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars))
@@ -356,11 +355,7 @@ func RegisterRoutes(m *web.Route) {
356355
m.Post("/authorize", bindIgnErr(forms.AuthorizationForm{}), user.AuthorizeOAuth)
357356
}, ignSignInAndCsrf, reqSignIn)
358357
m.Get("/login/oauth/userinfo", ignSignInAndCsrf, user.InfoOAuth)
359-
if setting.CORSConfig.Enabled {
360-
m.Post("/login/oauth/access_token", corsHandler, bindIgnErr(forms.AccessTokenForm{}), ignSignInAndCsrf, user.AccessTokenOAuth)
361-
} else {
362-
m.Post("/login/oauth/access_token", bindIgnErr(forms.AccessTokenForm{}), ignSignInAndCsrf, user.AccessTokenOAuth)
363-
}
358+
m.Post("/login/oauth/access_token", corsHandler, bindIgnErr(forms.AccessTokenForm{}), ignSignInAndCsrf, user.AccessTokenOAuth)
364359

365360
m.Group("/user/settings", func() {
366361
m.Get("", userSetting.Profile)

0 commit comments

Comments
 (0)