2020-11-13 20:51:07 +08:00
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2021-06-09 07:33:54 +08:00
package web
2020-11-13 20:51:07 +08:00
import (
2022-08-28 10:43:25 +01:00
goctx "context"
2020-11-13 20:51:07 +08:00
"errors"
"fmt"
"io"
"net/http"
"os"
"path"
"strings"
2021-01-20 09:47:43 +08:00
"code.gitea.io/gitea/modules/context"
2020-11-17 23:44:52 +01:00
"code.gitea.io/gitea/modules/httpcache"
2020-11-13 20:51:07 +08:00
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
2021-01-26 23:36:53 +08:00
"code.gitea.io/gitea/modules/templates"
2021-01-30 16:55:53 +08:00
"code.gitea.io/gitea/modules/web/middleware"
2022-01-20 19:41:25 +08:00
"code.gitea.io/gitea/modules/web/routing"
2021-06-10 01:53:16 +08:00
"code.gitea.io/gitea/services/auth"
2020-11-13 20:51:07 +08:00
2021-01-05 21:05:40 +08:00
"gitea.com/go-chi/session"
2020-11-13 20:51:07 +08:00
)
func storageHandler ( storageSetting setting . Storage , prefix string , objStore storage . ObjectStorage ) func ( next http . Handler ) http . Handler {
2022-03-22 21:02:26 +00:00
prefix = strings . Trim ( prefix , "/" )
2022-01-20 19:41:25 +08:00
funcInfo := routing . GetFuncInfo ( storageHandler , prefix )
2020-11-13 20:51:07 +08:00
return func ( next http . Handler ) http . Handler {
if storageSetting . ServeDirect {
return http . HandlerFunc ( func ( w http . ResponseWriter , req * http . Request ) {
if req . Method != "GET" && req . Method != "HEAD" {
next . ServeHTTP ( w , req )
return
}
2022-03-22 21:02:26 +00:00
if ! strings . HasPrefix ( req . URL . Path , "/" + prefix + "/" ) {
2020-11-13 20:51:07 +08:00
next . ServeHTTP ( w , req )
return
}
2022-01-20 19:41:25 +08:00
routing . UpdateFuncInfo ( req . Context ( ) , funcInfo )
2020-11-13 20:51:07 +08:00
2022-03-22 21:02:26 +00:00
rPath := strings . TrimPrefix ( req . URL . Path , "/" + prefix + "/" )
rPath = path . Clean ( "/" + strings . ReplaceAll ( rPath , "\\" , "/" ) ) [ 1 : ]
2020-11-13 20:51:07 +08:00
u , err := objStore . URL ( rPath , path . Base ( rPath ) )
if err != nil {
if os . IsNotExist ( err ) || errors . Is ( err , os . ErrNotExist ) {
log . Warn ( "Unable to find %s %s" , prefix , rPath )
2022-03-23 05:54:07 +01:00
http . Error ( w , "file not found" , http . StatusNotFound )
2020-11-13 20:51:07 +08:00
return
}
log . Error ( "Error whilst getting URL for %s %s. Error: %v" , prefix , rPath , err )
2022-03-23 05:54:07 +01:00
http . Error ( w , fmt . Sprintf ( "Error whilst getting URL for %s %s" , prefix , rPath ) , http . StatusInternalServerError )
2020-11-13 20:51:07 +08:00
return
}
2022-03-22 21:02:26 +00:00
2020-11-13 20:51:07 +08:00
http . Redirect (
w ,
req ,
u . String ( ) ,
2022-05-19 23:20:34 +08:00
http . StatusTemporaryRedirect ,
2020-11-13 20:51:07 +08:00
)
} )
}
return http . HandlerFunc ( func ( w http . ResponseWriter , req * http . Request ) {
if req . Method != "GET" && req . Method != "HEAD" {
next . ServeHTTP ( w , req )
return
}
2022-03-22 21:02:26 +00:00
if ! strings . HasPrefix ( req . URL . Path , "/" + prefix + "/" ) {
2020-11-13 20:51:07 +08:00
next . ServeHTTP ( w , req )
return
}
2022-01-20 19:41:25 +08:00
routing . UpdateFuncInfo ( req . Context ( ) , funcInfo )
2020-11-13 20:51:07 +08:00
2022-03-22 21:02:26 +00:00
rPath := strings . TrimPrefix ( req . URL . Path , "/" + prefix + "/" )
rPath = path . Clean ( "/" + strings . ReplaceAll ( rPath , "\\" , "/" ) ) [ 1 : ]
2021-03-24 01:20:24 +08:00
if rPath == "" {
2022-03-23 05:54:07 +01:00
http . Error ( w , "file not found" , http . StatusNotFound )
2021-03-24 01:20:24 +08:00
return
}
2020-11-17 23:44:52 +01:00
fi , err := objStore . Stat ( rPath )
if err == nil && httpcache . HandleTimeCache ( req , w , fi ) {
return
}
2022-01-20 18:46:10 +01:00
// If we have matched and access to release or issue
2020-11-13 20:51:07 +08:00
fr , err := objStore . Open ( rPath )
if err != nil {
if os . IsNotExist ( err ) || errors . Is ( err , os . ErrNotExist ) {
log . Warn ( "Unable to find %s %s" , prefix , rPath )
2022-03-23 05:54:07 +01:00
http . Error ( w , "file not found" , http . StatusNotFound )
2020-11-13 20:51:07 +08:00
return
}
log . Error ( "Error whilst opening %s %s. Error: %v" , prefix , rPath , err )
2022-03-23 05:54:07 +01:00
http . Error ( w , fmt . Sprintf ( "Error whilst opening %s %s" , prefix , rPath ) , http . StatusInternalServerError )
2020-11-13 20:51:07 +08:00
return
}
defer fr . Close ( )
_ , err = io . Copy ( w , fr )
if err != nil {
log . Error ( "Error whilst rendering %s %s. Error: %v" , prefix , rPath , err )
2022-03-23 05:54:07 +01:00
http . Error ( w , fmt . Sprintf ( "Error whilst rendering %s %s" , prefix , rPath ) , http . StatusInternalServerError )
2020-11-13 20:51:07 +08:00
return
}
} )
}
}
2021-06-09 07:33:54 +08:00
type dataStore map [ string ] interface { }
2020-11-13 20:51:07 +08:00
2021-01-26 23:36:53 +08:00
func ( d * dataStore ) GetData ( ) map [ string ] interface { } {
2021-06-09 07:33:54 +08:00
return * d
2020-11-13 20:51:07 +08:00
}
2021-01-26 23:36:53 +08:00
// Recovery returns a middleware that recovers from any panics and writes a 500 and a log if so.
// This error will be created with the gitea 500 page.
2022-08-28 10:43:25 +01:00
func Recovery ( ctx goctx . Context ) func ( next http . Handler ) http . Handler {
_ , rnd := templates . HTMLRenderer ( ctx )
2021-01-26 23:36:53 +08:00
return func ( next http . Handler ) http . Handler {
return http . HandlerFunc ( func ( w http . ResponseWriter , req * http . Request ) {
defer func ( ) {
if err := recover ( ) ; err != nil {
2022-01-20 19:41:25 +08:00
routing . UpdatePanicError ( req . Context ( ) , err )
combinedErr := fmt . Sprintf ( "PANIC: %v\n%s" , err , log . Stack ( 2 ) )
log . Error ( "%s" , combinedErr )
2021-01-26 23:36:53 +08:00
sessionStore := session . GetSession ( req )
2020-11-16 15:33:41 +08:00
2022-01-20 18:46:10 +01:00
lc := middleware . Locale ( w , req )
store := dataStore {
2021-06-09 07:33:54 +08:00
"Language" : lc . Language ( ) ,
"CurrentURL" : setting . AppSubURL + req . URL . RequestURI ( ) ,
2022-06-27 22:58:46 +02:00
"locale" : lc ,
2021-01-26 23:36:53 +08:00
}
2020-11-13 20:51:07 +08:00
2022-01-20 18:46:10 +01:00
user := context . GetContextUser ( req )
2021-05-15 16:32:09 +01:00
if user == nil {
// Get user from session if logged in - do not attempt to sign-in
2021-06-10 01:53:16 +08:00
user = auth . SessionUser ( sessionStore )
2021-05-15 16:32:09 +01:00
}
2021-01-26 23:36:53 +08:00
if user != nil {
2021-06-09 07:33:54 +08:00
store [ "IsSigned" ] = true
store [ "SignedUser" ] = user
store [ "SignedUserID" ] = user . ID
store [ "SignedUserName" ] = user . Name
store [ "IsAdmin" ] = user . IsAdmin
2021-01-26 23:36:53 +08:00
} else {
2021-06-09 07:33:54 +08:00
store [ "SignedUserID" ] = int64 ( 0 )
store [ "SignedUserName" ] = ""
2021-01-26 23:36:53 +08:00
}
2020-11-13 20:51:07 +08:00
2022-07-23 08:38:03 +02:00
httpcache . AddCacheControlToHeader ( w . Header ( ) , 0 , "no-transform" )
2021-08-06 21:47:10 +01:00
w . Header ( ) . Set ( ` X-Frame-Options ` , setting . CORSConfig . XFrameOptions )
2020-11-18 04:50:06 +08:00
2021-10-20 22:37:19 +08:00
if ! setting . IsProd {
2021-06-09 07:33:54 +08:00
store [ "ErrorMsg" ] = combinedErr
2021-01-26 23:36:53 +08:00
}
2022-03-23 05:54:07 +01:00
err = rnd . HTML ( w , http . StatusInternalServerError , "status/500" , templates . BaseVars ( ) . Merge ( store ) )
2021-01-26 23:36:53 +08:00
if err != nil {
log . Error ( "%v" , err )
}
}
} ( )
2020-11-18 04:50:06 +08:00
2021-01-26 23:36:53 +08:00
next . ServeHTTP ( w , req )
} )
2020-11-18 04:50:06 +08:00
}
2020-11-13 20:51:07 +08:00
}