@@ -89,6 +89,9 @@ func commonMiddlewares() []func(http.Handler) http.Handler {
89
89
handlers = append (handlers , LoggerHandler (setting .RouterLogLevel ))
90
90
}
91
91
}
92
+ if setting .EnableAccessLog {
93
+ handlers = append (handlers , context .AccessLogger ())
94
+ }
92
95
93
96
handlers = append (handlers , func (next http.Handler ) http.Handler {
94
97
return http .HandlerFunc (func (resp http.ResponseWriter , req * http.Request ) {
@@ -128,9 +131,9 @@ func NormalRoutes() *web.Route {
128
131
129
132
// WebRoutes returns all web routes
130
133
func WebRoutes () * web.Route {
131
- r := web .NewRoute ()
134
+ routes := web .NewRoute ()
132
135
133
- r .Use (session .Sessioner (session.Options {
136
+ routes .Use (session .Sessioner (session.Options {
134
137
Provider : setting .SessionConfig .Provider ,
135
138
ProviderConfig : setting .SessionConfig .ProviderConfig ,
136
139
CookieName : setting .SessionConfig .CookieName ,
@@ -141,93 +144,99 @@ func WebRoutes() *web.Route {
141
144
Domain : setting .SessionConfig .Domain ,
142
145
}))
143
146
144
- r .Use (Recovery ())
147
+ routes .Use (Recovery ())
145
148
146
- r .Use (public .Custom (
149
+ // TODO: we should consider if there is a way to mount these using r.Route as at present
150
+ // these two handlers mean that every request has to hit these "filesystems" twice
151
+ // before finally getting to the router. It allows them to override any matching router below.
152
+ routes .Use (public .Custom (
147
153
& public.Options {
148
154
SkipLogging : setting .DisableRouterLog ,
149
155
},
150
156
))
151
- r .Use (public .Static (
157
+ routes .Use (public .Static (
152
158
& public.Options {
153
159
Directory : path .Join (setting .StaticRootPath , "public" ),
154
160
SkipLogging : setting .DisableRouterLog ,
155
161
Prefix : "/assets" ,
156
162
},
157
163
))
158
164
159
- r .Use (storageHandler (setting .Avatar .Storage , "avatars" , storage .Avatars ))
160
- r .Use (storageHandler (setting .RepoAvatar .Storage , "repo-avatars" , storage .RepoAvatars ))
165
+ // We use r.Route here over r.Use because this prevents requests that are not for avatars having to go through this additional handler
166
+ routes .Route ("/avatars" , "GET, HEAD" , storageHandler (setting .Avatar .Storage , "avatars" , storage .Avatars ))
167
+ routes .Route ("/repo-avatars" , "GET, HEAD" , storageHandler (setting .RepoAvatar .Storage , "repo-avatars" , storage .RepoAvatars ))
168
+
169
+ // for health check - doeesn't need to be passed through gzip handler
170
+ routes .Head ("/" , func (w http.ResponseWriter , req * http.Request ) {
171
+ w .WriteHeader (http .StatusOK )
172
+ })
173
+
174
+ // this png is very likely to always be below the limit for gzip so it doesn't need to pass through gzip
175
+ routes .Get ("/apple-touch-icon.png" , func (w http.ResponseWriter , req * http.Request ) {
176
+ http .Redirect (w , req , path .Join (setting .StaticURLPrefix , "img/apple-touch-icon.png" ), 301 )
177
+ })
161
178
162
179
gob .Register (& u2f.Challenge {})
163
180
181
+ common := []interface {}{}
182
+
164
183
if setting .EnableGzip {
165
184
h , err := gziphandler .GzipHandlerWithOpts (gziphandler .MinSize (GzipMinSize ))
166
185
if err != nil {
167
186
log .Fatal ("GzipHandlerWithOpts failed: %v" , err )
168
187
}
169
- r . Use ( h )
188
+ common = append ( common , h )
170
189
}
171
190
172
191
mailer .InitMailRender (templates .Mailer ())
173
192
174
193
if setting .Service .EnableCaptcha {
175
- r .Use (captcha .Captchaer (context .GetImageCaptcha ()))
176
- }
177
- // Removed: toolbox.Toolboxer middleware will provide debug informations which seems unnecessary
178
- r .Use (context .Contexter ())
179
- // GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route
180
- r .Use (middleware .GetHead )
181
-
182
- if setting .EnableAccessLog {
183
- r .Use (context .AccessLogger ())
194
+ // The captcha http.Handler should only fire on /captcha/* so we can just mount this on that url
195
+ routes .Route ("/captcha/*" , "GET,HEAD" , append (common , captcha .Captchaer (context .GetImageCaptcha ()))... )
184
196
}
185
197
186
- r .Use (user .GetNotificationCount )
187
- r .Use (repo .GetActiveStopwatch )
188
- r .Use (func (ctx * context.Context ) {
189
- ctx .Data ["UnitWikiGlobalDisabled" ] = models .UnitTypeWiki .UnitGlobalDisabled ()
190
- ctx .Data ["UnitIssuesGlobalDisabled" ] = models .UnitTypeIssues .UnitGlobalDisabled ()
191
- ctx .Data ["UnitPullsGlobalDisabled" ] = models .UnitTypePullRequests .UnitGlobalDisabled ()
192
- ctx .Data ["UnitProjectsGlobalDisabled" ] = models .UnitTypeProjects .UnitGlobalDisabled ()
193
- })
194
-
195
- // for health check
196
- r .Head ("/" , func (w http.ResponseWriter , req * http.Request ) {
197
- w .WriteHeader (http .StatusOK )
198
- })
199
-
200
198
if setting .HasRobotsTxt {
201
- r .Get ("/robots.txt" , func (w http.ResponseWriter , req * http.Request ) {
199
+ routes .Get ("/robots.txt" , append ( common , func (w http.ResponseWriter , req * http.Request ) {
202
200
filePath := path .Join (setting .CustomPath , "robots.txt" )
203
201
fi , err := os .Stat (filePath )
204
202
if err == nil && httpcache .HandleTimeCache (req , w , fi ) {
205
203
return
206
204
}
207
205
http .ServeFile (w , req , filePath )
208
- })
206
+ })... )
209
207
}
210
208
211
- r .Get ("/apple-touch-icon.png" , func (w http.ResponseWriter , req * http.Request ) {
212
- http .Redirect (w , req , path .Join (setting .StaticURLPrefix , "img/apple-touch-icon.png" ), 301 )
213
- })
214
-
215
- // prometheus metrics endpoint
209
+ // prometheus metrics endpoint - do not need to go through contexter
216
210
if setting .Metrics .Enabled {
217
211
c := metrics .NewCollector ()
218
212
prometheus .MustRegister (c )
219
213
220
- r .Get ("/metrics" , routers .Metrics )
214
+ routes .Get ("/metrics" , append ( common , routers .Metrics ) ... )
221
215
}
222
216
217
+ // Removed: toolbox.Toolboxer middleware will provide debug informations which seems unnecessary
218
+ common = append (common , context .Contexter ())
219
+
220
+ // GetHead allows a HEAD request redirect to GET if HEAD method is not defined for that route
221
+ common = append (common , middleware .GetHead )
222
+
223
223
if setting .API .EnableSwagger {
224
224
// Note: The route moved from apiroutes because it's in fact want to render a web page
225
- r .Get ("/api/swagger" , misc .Swagger ) // Render V1 by default
225
+ routes .Get ("/api/swagger" , append ( common , misc .Swagger ) ... ) // Render V1 by default
226
226
}
227
227
228
- RegisterRoutes (r )
228
+ // TODO: These really seem like things that could be folded into Contexter or as helper functions
229
+ common = append (common , user .GetNotificationCount )
230
+ common = append (common , repo .GetActiveStopwatch )
229
231
230
- return r
232
+ others := web .NewRoute ()
233
+ for _ , middle := range common {
234
+ others .Use (middle )
235
+ }
236
+
237
+ RegisterRoutes (others )
238
+ routes .Mount ("" , others )
239
+ return routes
231
240
}
232
241
233
242
func goGet (ctx * context.Context ) {
0 commit comments