Changes
4 changed files (+40/-51)
-
-
@@ -6,7 +6,6 @@ package storageimport ( "context" "errors" "io" "net/url" "os"
-
@@ -18,8 +17,6 @@ import ("code.gitea.io/gitea/modules/util" ) // ErrLocalPathNotSupported represents an error that path is not supported var ErrLocalPathNotSupported = errors.New("local path is not supported") var _ ObjectStorage = &LocalStorage{} // LocalStorageType is the type descriptor for local storage
-
@@ -62,21 +59,18 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error}, nil } func (l *LocalStorage) buildLocalPath(p string) string { return filepath.Join(l.dir, path.Clean("/" + strings.ReplaceAll(p, "\\", "/"))[1:]) } // Open a file func (l *LocalStorage) Open(path string) (Object, error) { if !isLocalPathValid(path) { return nil, ErrLocalPathNotSupported } return os.Open(filepath.Join(l.dir, path)) return os.Open(l.buildLocalPath(path)) } // Save a file func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error) { if !isLocalPathValid(path) { return 0, ErrLocalPathNotSupported } p := filepath.Join(l.dir, path) p := l.buildLocalPath(path) if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil { return 0, err }
-
@@ -116,24 +110,12 @@ func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error)// Stat returns the info of the file func (l *LocalStorage) Stat(path string) (os.FileInfo, error) { return os.Stat(filepath.Join(l.dir, path)) } func isLocalPathValid(p string) bool { a := path.Clean(p) if strings.HasPrefix(a, "../") || strings.HasPrefix(a, "..\\") { return false } return a == p return os.Stat(l.buildLocalPath(path)) } // Delete delete a file func (l *LocalStorage) Delete(path string) error { if !isLocalPathValid(path) { return ErrLocalPathNotSupported } p := filepath.Join(l.dir, path) return util.Remove(p) return util.Remove(l.buildLocalPath(path)) } // URL gets the redirect URL to a file
-
-
-
@@ -10,36 +10,44 @@ import ("github.com/stretchr/testify/assert" ) func TestLocalPathIsValid(t *testing.T) { func TestBuildLocalPath(t *testing.T) { kases := []struct { path string valid bool localDir string path string expected string }{ { "a", "0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", "a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", true, }, { "../a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", false, "a", "../0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", "a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", }, { "a\\0\\a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", true, "a", "0\\a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", "a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", }, { "b/../a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", false, "b", "a/../0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", "b/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", }, { "..\\a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", false, "b", "a\\..\\0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", "b/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14", }, } for _, k := range kases { t.Run(k.path, func(t *testing.T) { assert.EqualValues(t, k.valid, isLocalPathValid(k.path)) l := LocalStorage{dir: k.localDir} assert.EqualValues(t, k.expected, l.buildLocalPath(k.path)) }) } }
-
-
-
@@ -117,7 +117,7 @@ func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error} func (m *MinioStorage) buildMinioPath(p string) string { return strings.TrimPrefix(path.Join(m.basePath, p), "/") return strings.TrimPrefix(path.Join(m.basePath, path.Clean("/" + strings.ReplaceAll(p, "\\", "/"))[1:]), "/") } // Open open a file
-
-
-
@@ -11,7 +11,6 @@ import ("net/http" "os" "path" "path/filepath" "strings" "code.gitea.io/gitea/modules/context"
-
@@ -28,6 +27,7 @@ import () func storageHandler(storageSetting setting.Storage, prefix string, objStore storage.ObjectStorage) func(next http.Handler) http.Handler { prefix = strings.Trim(prefix, "/") funcInfo := routing.GetFuncInfo(storageHandler, prefix) return func(next http.Handler) http.Handler { if storageSetting.ServeDirect {
-
@@ -37,13 +37,15 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore storreturn } if !strings.HasPrefix(req.URL.RequestURI(), "/"+prefix) { if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") { next.ServeHTTP(w, req) return } routing.UpdateFuncInfo(req.Context(), funcInfo) rPath := strings.TrimPrefix(req.URL.RequestURI(), "/"+prefix) rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/") rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:] u, err := objStore.URL(rPath, path.Base(rPath)) if err != nil { if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
-
@@ -55,11 +57,12 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore storhttp.Error(w, fmt.Sprintf("Error whilst getting URL for %s %s", prefix, rPath), 500) return } http.Redirect( w, req, u.String(), 301, http.StatusMovedPermanently, ) }) }
-
@@ -70,22 +73,18 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore storreturn } prefix := strings.Trim(prefix, "/") if !strings.HasPrefix(req.URL.EscapedPath(), "/"+prefix+"/") { if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") { next.ServeHTTP(w, req) return } routing.UpdateFuncInfo(req.Context(), funcInfo) rPath := strings.TrimPrefix(req.URL.EscapedPath(), "/"+prefix+"/") rPath = strings.TrimPrefix(rPath, "/") rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/") rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:] if rPath == "" { http.Error(w, "file not found", 404) return } rPath = path.Clean("/" + filepath.ToSlash(rPath)) rPath = rPath[1:] fi, err := objStore.Stat(rPath) if err == nil && httpcache.HandleTimeCache(req, w, fi) {
-