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  }