@@ -89,6 +89,9 @@ func commonMiddlewares() []func(http.Handler) http.Handler {
8989 handlers = append (handlers , LoggerHandler (setting .RouterLogLevel ))
9090 }
9191 }
92+ if setting .EnableAccessLog {
93+ handlers = append (handlers , context .AccessLogger ())
94+ }
9295
9396 handlers = append (handlers , func (next http.Handler ) http.Handler {
9497 return http .HandlerFunc (func (resp http.ResponseWriter , req * http.Request ) {
@@ -128,9 +131,9 @@ func NormalRoutes() *web.Route {
128131
129132// WebRoutes returns all web routes
130133func WebRoutes () * web.Route {
131- r := web .NewRoute ()
134+ routes := web .NewRoute ()
132135
133- r .Use (session .Sessioner (session.Options {
136+ routes .Use (session .Sessioner (session.Options {
134137 Provider : setting .SessionConfig .Provider ,
135138 ProviderConfig : setting .SessionConfig .ProviderConfig ,
136139 CookieName : setting .SessionConfig .CookieName ,
@@ -141,93 +144,99 @@ func WebRoutes() *web.Route {
141144 Domain : setting .SessionConfig .Domain ,
142145 }))
143146
144- r .Use (Recovery ())
147+ routes .Use (Recovery ())
145148
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 (
147153 & public.Options {
148154 SkipLogging : setting .DisableRouterLog ,
149155 },
150156 ))
151- r .Use (public .Static (
157+ routes .Use (public .Static (
152158 & public.Options {
153159 Directory : path .Join (setting .StaticRootPath , "public" ),
154160 SkipLogging : setting .DisableRouterLog ,
155161 Prefix : "/assets" ,
156162 },
157163 ))
158164
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+ })
161178
162179 gob .Register (& u2f.Challenge {})
163180
181+ common := []interface {}{}
182+
164183 if setting .EnableGzip {
165184 h , err := gziphandler .GzipHandlerWithOpts (gziphandler .MinSize (GzipMinSize ))
166185 if err != nil {
167186 log .Fatal ("GzipHandlerWithOpts failed: %v" , err )
168187 }
169- r . Use ( h )
188+ common = append ( common , h )
170189 }
171190
172191 mailer .InitMailRender (templates .Mailer ())
173192
174193 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 ()))... )
184196 }
185197
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-
200198 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 ) {
202200 filePath := path .Join (setting .CustomPath , "robots.txt" )
203201 fi , err := os .Stat (filePath )
204202 if err == nil && httpcache .HandleTimeCache (req , w , fi ) {
205203 return
206204 }
207205 http .ServeFile (w , req , filePath )
208- })
206+ })... )
209207 }
210208
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
216210 if setting .Metrics .Enabled {
217211 c := metrics .NewCollector ()
218212 prometheus .MustRegister (c )
219213
220- r .Get ("/metrics" , routers .Metrics )
214+ routes .Get ("/metrics" , append ( common , routers .Metrics ) ... )
221215 }
222216
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+
223223 if setting .API .EnableSwagger {
224224 // 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
226226 }
227227
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 )
229231
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
231240}
232241
233242func goGet (ctx * context.Context ) {
0 commit comments