code.gitea.io/gitea@v1.21.7/routers/web/base.go (about) 1 // Copyright 2020 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package web 5 6 import ( 7 "errors" 8 "fmt" 9 "net/http" 10 "os" 11 "path" 12 "strings" 13 14 "code.gitea.io/gitea/modules/httpcache" 15 "code.gitea.io/gitea/modules/log" 16 "code.gitea.io/gitea/modules/setting" 17 "code.gitea.io/gitea/modules/storage" 18 "code.gitea.io/gitea/modules/util" 19 "code.gitea.io/gitea/modules/web/routing" 20 ) 21 22 func storageHandler(storageSetting *setting.Storage, prefix string, objStore storage.ObjectStorage) http.HandlerFunc { 23 prefix = strings.Trim(prefix, "/") 24 funcInfo := routing.GetFuncInfo(storageHandler, prefix) 25 26 if storageSetting.MinioConfig.ServeDirect { 27 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 28 if req.Method != "GET" && req.Method != "HEAD" { 29 http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) 30 return 31 } 32 33 if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") { 34 http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) 35 return 36 } 37 routing.UpdateFuncInfo(req.Context(), funcInfo) 38 39 rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/") 40 rPath = util.PathJoinRelX(rPath) 41 42 u, err := objStore.URL(rPath, path.Base(rPath)) 43 if err != nil { 44 if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) { 45 log.Warn("Unable to find %s %s", prefix, rPath) 46 http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) 47 return 48 } 49 log.Error("Error whilst getting URL for %s %s. Error: %v", prefix, rPath, err) 50 http.Error(w, fmt.Sprintf("Error whilst getting URL for %s %s", prefix, rPath), http.StatusInternalServerError) 51 return 52 } 53 54 http.Redirect(w, req, u.String(), http.StatusTemporaryRedirect) 55 }) 56 } 57 58 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 59 if req.Method != "GET" && req.Method != "HEAD" { 60 http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) 61 return 62 } 63 64 if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") { 65 http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) 66 return 67 } 68 routing.UpdateFuncInfo(req.Context(), funcInfo) 69 70 rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/") 71 rPath = util.PathJoinRelX(rPath) 72 if rPath == "" || rPath == "." { 73 http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) 74 return 75 } 76 77 fi, err := objStore.Stat(rPath) 78 if err != nil { 79 if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) { 80 log.Warn("Unable to find %s %s", prefix, rPath) 81 http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) 82 return 83 } 84 log.Error("Error whilst opening %s %s. Error: %v", prefix, rPath, err) 85 http.Error(w, fmt.Sprintf("Error whilst opening %s %s", prefix, rPath), http.StatusInternalServerError) 86 return 87 } 88 89 fr, err := objStore.Open(rPath) 90 if err != nil { 91 log.Error("Error whilst opening %s %s. Error: %v", prefix, rPath, err) 92 http.Error(w, fmt.Sprintf("Error whilst opening %s %s", prefix, rPath), http.StatusInternalServerError) 93 return 94 } 95 defer fr.Close() 96 httpcache.ServeContentWithCacheControl(w, req, path.Base(rPath), fi.ModTime(), fr) 97 }) 98 }