mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08:00 
			
		
		
		
	* Fix minio bug * Add tests for storage configuration * Change the Seek flag to keep compitable minio? * Fix test when first-byte-pos of all ranges is greater than the resource length Co-authored-by: techknowlogick <techknowlogick@gitea.io> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
This commit is contained in:
		@@ -11,7 +11,6 @@ import (
 | 
				
			|||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"log"
 | 
					 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/http/cookiejar"
 | 
						"net/http/cookiejar"
 | 
				
			||||||
	"net/http/httptest"
 | 
						"net/http/httptest"
 | 
				
			||||||
@@ -27,8 +26,10 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/base"
 | 
						"code.gitea.io/gitea/modules/base"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/graceful"
 | 
						"code.gitea.io/gitea/modules/graceful"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/queue"
 | 
						"code.gitea.io/gitea/modules/queue"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/storage"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
	"code.gitea.io/gitea/routers"
 | 
						"code.gitea.io/gitea/routers"
 | 
				
			||||||
	"code.gitea.io/gitea/routers/routes"
 | 
						"code.gitea.io/gitea/routers/routes"
 | 
				
			||||||
@@ -59,6 +60,8 @@ func NewNilResponseRecorder() *NilResponseRecorder {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMain(m *testing.M) {
 | 
					func TestMain(m *testing.M) {
 | 
				
			||||||
 | 
						defer log.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	managerCtx, cancel := context.WithCancel(context.Background())
 | 
						managerCtx, cancel := context.WithCancel(context.Background())
 | 
				
			||||||
	graceful.InitManager(managerCtx)
 | 
						graceful.InitManager(managerCtx)
 | 
				
			||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
@@ -142,6 +145,10 @@ func initIntegrationTest() {
 | 
				
			|||||||
	util.RemoveAll(models.LocalCopyPath())
 | 
						util.RemoveAll(models.LocalCopyPath())
 | 
				
			||||||
	setting.CheckLFSVersion()
 | 
						setting.CheckLFSVersion()
 | 
				
			||||||
	setting.InitDBConfig()
 | 
						setting.InitDBConfig()
 | 
				
			||||||
 | 
						if err := storage.Init(); err != nil {
 | 
				
			||||||
 | 
							fmt.Printf("Init storage failed: %v", err)
 | 
				
			||||||
 | 
							os.Exit(1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch {
 | 
						switch {
 | 
				
			||||||
	case setting.Database.UseMySQL:
 | 
						case setting.Database.UseMySQL:
 | 
				
			||||||
@@ -149,27 +156,27 @@ func initIntegrationTest() {
 | 
				
			|||||||
			setting.Database.User, setting.Database.Passwd, setting.Database.Host))
 | 
								setting.Database.User, setting.Database.Passwd, setting.Database.Host))
 | 
				
			||||||
		defer db.Close()
 | 
							defer db.Close()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Fatalf("sql.Open: %v", err)
 | 
								log.Fatal("sql.Open: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", setting.Database.Name)); err != nil {
 | 
							if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", setting.Database.Name)); err != nil {
 | 
				
			||||||
			log.Fatalf("db.Exec: %v", err)
 | 
								log.Fatal("db.Exec: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case setting.Database.UsePostgreSQL:
 | 
						case setting.Database.UsePostgreSQL:
 | 
				
			||||||
		db, err := sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s",
 | 
							db, err := sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s",
 | 
				
			||||||
			setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode))
 | 
								setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode))
 | 
				
			||||||
		defer db.Close()
 | 
							defer db.Close()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Fatalf("sql.Open: %v", err)
 | 
								log.Fatal("sql.Open: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		dbrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", setting.Database.Name))
 | 
							dbrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", setting.Database.Name))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Fatalf("db.Query: %v", err)
 | 
								log.Fatal("db.Query: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		defer dbrows.Close()
 | 
							defer dbrows.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if !dbrows.Next() {
 | 
							if !dbrows.Next() {
 | 
				
			||||||
			if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", setting.Database.Name)); err != nil {
 | 
								if _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", setting.Database.Name)); err != nil {
 | 
				
			||||||
				log.Fatalf("db.Exec: CREATE DATABASE: %v", err)
 | 
									log.Fatal("db.Exec: CREATE DATABASE: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Check if we need to setup a specific schema
 | 
							// Check if we need to setup a specific schema
 | 
				
			||||||
@@ -183,18 +190,18 @@ func initIntegrationTest() {
 | 
				
			|||||||
		// This is a different db object; requires a different Close()
 | 
							// This is a different db object; requires a different Close()
 | 
				
			||||||
		defer db.Close()
 | 
							defer db.Close()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Fatalf("sql.Open: %v", err)
 | 
								log.Fatal("sql.Open: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		schrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema))
 | 
							schrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Fatalf("db.Query: %v", err)
 | 
								log.Fatal("db.Query: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		defer schrows.Close()
 | 
							defer schrows.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if !schrows.Next() {
 | 
							if !schrows.Next() {
 | 
				
			||||||
			// Create and setup a DB schema
 | 
								// Create and setup a DB schema
 | 
				
			||||||
			if _, err = db.Exec(fmt.Sprintf("CREATE SCHEMA %s", setting.Database.Schema)); err != nil {
 | 
								if _, err = db.Exec(fmt.Sprintf("CREATE SCHEMA %s", setting.Database.Schema)); err != nil {
 | 
				
			||||||
				log.Fatalf("db.Exec: CREATE SCHEMA: %v", err)
 | 
									log.Fatal("db.Exec: CREATE SCHEMA: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -203,10 +210,10 @@ func initIntegrationTest() {
 | 
				
			|||||||
		db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
 | 
							db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
 | 
				
			||||||
			host, port, "master", setting.Database.User, setting.Database.Passwd))
 | 
								host, port, "master", setting.Database.User, setting.Database.Passwd))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Fatalf("sql.Open: %v", err)
 | 
								log.Fatal("sql.Open: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if _, err := db.Exec(fmt.Sprintf("If(db_id(N'%s') IS NULL) BEGIN CREATE DATABASE %s; END;", setting.Database.Name, setting.Database.Name)); err != nil {
 | 
							if _, err := db.Exec(fmt.Sprintf("If(db_id(N'%s') IS NULL) BEGIN CREATE DATABASE %s; END;", setting.Database.Name, setting.Database.Name)); err != nil {
 | 
				
			||||||
			log.Fatalf("db.Exec: %v", err)
 | 
								log.Fatal("db.Exec: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		defer db.Close()
 | 
							defer db.Close()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,6 +78,7 @@ func storeAndGetLfs(t *testing.T, content *[]byte, extraHeader *http.Header, exp
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	resp := session.MakeRequest(t, req, expectedStatus)
 | 
						resp := session.MakeRequest(t, req, expectedStatus)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return resp
 | 
						return resp
 | 
				
			||||||
@@ -210,7 +211,7 @@ func TestGetLFSRange(t *testing.T) {
 | 
				
			|||||||
		{"bytes=0-10", "123456789\n", http.StatusPartialContent},
 | 
							{"bytes=0-10", "123456789\n", http.StatusPartialContent},
 | 
				
			||||||
		// end-range bigger than length-1 is ignored
 | 
							// end-range bigger than length-1 is ignored
 | 
				
			||||||
		{"bytes=0-11", "123456789\n", http.StatusPartialContent},
 | 
							{"bytes=0-11", "123456789\n", http.StatusPartialContent},
 | 
				
			||||||
		{"bytes=11-", "", http.StatusPartialContent},
 | 
							{"bytes=11-", "Requested Range Not Satisfiable", http.StatusRequestedRangeNotSatisfiable},
 | 
				
			||||||
		// incorrect header value cause whole header to be ignored
 | 
							// incorrect header value cause whole header to be ignored
 | 
				
			||||||
		{"bytes=-", "123456789\n", http.StatusOK},
 | 
							{"bytes=-", "123456789\n", http.StatusOK},
 | 
				
			||||||
		{"foobar", "123456789\n", http.StatusOK},
 | 
							{"foobar", "123456789\n", http.StatusOK},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,19 +45,21 @@ START_SSH_SERVER = true
 | 
				
			|||||||
OFFLINE_MODE     = false
 | 
					OFFLINE_MODE     = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LFS_START_SERVER = true
 | 
					LFS_START_SERVER = true
 | 
				
			||||||
LFS_CONTENT_PATH = integrations/gitea-integration-mysql/datalfs-mysql
 | 
					 | 
				
			||||||
LFS_JWT_SECRET   = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
 | 
					LFS_JWT_SECRET   = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
 | 
				
			||||||
LFS_STORE_TYPE = minio
 | 
					
 | 
				
			||||||
LFS_SERVE_DIRECT = false
 | 
					[lfs]
 | 
				
			||||||
LFS_MINIO_ENDPOINT = minio:9000
 | 
					MINIO_BASE_PATH = lfs/
 | 
				
			||||||
LFS_MINIO_ACCESS_KEY_ID = 123456
 | 
					 | 
				
			||||||
LFS_MINIO_SECRET_ACCESS_KEY = 12345678
 | 
					 | 
				
			||||||
LFS_MINIO_BUCKET = gitea
 | 
					 | 
				
			||||||
LFS_MINIO_LOCATION = us-east-1
 | 
					 | 
				
			||||||
LFS_MINIO_BASE_PATH = lfs/
 | 
					 | 
				
			||||||
LFS_MINIO_USE_SSL = false
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
[attachment]
 | 
					[attachment]
 | 
				
			||||||
 | 
					MINIO_BASE_PATH = attachments/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[avatars]
 | 
				
			||||||
 | 
					MINIO_BASE_PATH = avatars/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[repo-avatars]
 | 
				
			||||||
 | 
					MINIO_BASE_PATH = repo-avatars/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[storage]
 | 
				
			||||||
STORAGE_TYPE = minio
 | 
					STORAGE_TYPE = minio
 | 
				
			||||||
SERVE_DIRECT = false
 | 
					SERVE_DIRECT = false
 | 
				
			||||||
MINIO_ENDPOINT = minio:9000
 | 
					MINIO_ENDPOINT = minio:9000
 | 
				
			||||||
@@ -65,7 +67,6 @@ MINIO_ACCESS_KEY_ID = 123456
 | 
				
			|||||||
MINIO_SECRET_ACCESS_KEY = 12345678
 | 
					MINIO_SECRET_ACCESS_KEY = 12345678
 | 
				
			||||||
MINIO_BUCKET = gitea
 | 
					MINIO_BUCKET = gitea
 | 
				
			||||||
MINIO_LOCATION = us-east-1
 | 
					MINIO_LOCATION = us-east-1
 | 
				
			||||||
MINIO_BASE_PATH = attachments/
 | 
					 | 
				
			||||||
MINIO_USE_SSL = false
 | 
					MINIO_USE_SSL = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[mailer]
 | 
					[mailer]
 | 
				
			||||||
@@ -88,9 +89,6 @@ ENABLE_NOTIFY_MAIL                = true
 | 
				
			|||||||
DISABLE_GRAVATAR              = false
 | 
					DISABLE_GRAVATAR              = false
 | 
				
			||||||
ENABLE_FEDERATED_AVATAR       = false
 | 
					ENABLE_FEDERATED_AVATAR       = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AVATAR_UPLOAD_PATH            = integrations/gitea-integration-mysql/data/avatars
 | 
					 | 
				
			||||||
REPOSITORY_AVATAR_UPLOAD_PATH = integrations/gitea-integration-mysql/data/repo-avatars
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[session]
 | 
					[session]
 | 
				
			||||||
PROVIDER        = file
 | 
					PROVIDER        = file
 | 
				
			||||||
PROVIDER_CONFIG = integrations/gitea-integration-mysql/data/sessions
 | 
					PROVIDER_CONFIG = integrations/gitea-integration-mysql/data/sessions
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import (
 | 
				
			|||||||
	"crypto/sha256"
 | 
						"crypto/sha256"
 | 
				
			||||||
	"encoding/hex"
 | 
						"encoding/hex"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -21,6 +22,21 @@ var (
 | 
				
			|||||||
	errSizeMismatch = errors.New("Content size does not match")
 | 
						errSizeMismatch = errors.New("Content size does not match")
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ErrRangeNotSatisfiable represents an error which request range is not satisfiable.
 | 
				
			||||||
 | 
					type ErrRangeNotSatisfiable struct {
 | 
				
			||||||
 | 
						FromByte int64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (err ErrRangeNotSatisfiable) Error() string {
 | 
				
			||||||
 | 
						return fmt.Sprintf("Requested range %d is not satisfiable", err.FromByte)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsErrRangeNotSatisfiable returns true if the error is an ErrRangeNotSatisfiable
 | 
				
			||||||
 | 
					func IsErrRangeNotSatisfiable(err error) bool {
 | 
				
			||||||
 | 
						_, ok := err.(ErrRangeNotSatisfiable)
 | 
				
			||||||
 | 
						return ok
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ContentStore provides a simple file system based storage.
 | 
					// ContentStore provides a simple file system based storage.
 | 
				
			||||||
type ContentStore struct {
 | 
					type ContentStore struct {
 | 
				
			||||||
	storage.ObjectStorage
 | 
						storage.ObjectStorage
 | 
				
			||||||
@@ -35,7 +51,12 @@ func (s *ContentStore) Get(meta *models.LFSMetaObject, fromByte int64) (io.ReadC
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if fromByte > 0 {
 | 
						if fromByte > 0 {
 | 
				
			||||||
		_, err = f.Seek(fromByte, os.SEEK_CUR)
 | 
							if fromByte >= meta.Size {
 | 
				
			||||||
 | 
								return nil, ErrRangeNotSatisfiable{
 | 
				
			||||||
 | 
									FromByte: fromByte,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							_, err = f.Seek(fromByte, io.SeekStart)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			log.Error("Whilst trying to read LFS OID[%s]: Unable to seek to %d Error: %v", meta.Oid, fromByte, err)
 | 
								log.Error("Whilst trying to read LFS OID[%s]: Unable to seek to %d Error: %v", meta.Oid, fromByte, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -191,8 +191,12 @@ func getContentHandler(ctx *context.Context) {
 | 
				
			|||||||
	contentStore := &ContentStore{ObjectStorage: storage.LFS}
 | 
						contentStore := &ContentStore{ObjectStorage: storage.LFS}
 | 
				
			||||||
	content, err := contentStore.Get(meta, fromByte)
 | 
						content, err := contentStore.Get(meta, fromByte)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		// Errors are logged in contentStore.Get
 | 
							if IsErrRangeNotSatisfiable(err) {
 | 
				
			||||||
		writeStatus(ctx, 404)
 | 
								writeStatus(ctx, http.StatusRequestedRangeNotSatisfiable)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// Errors are logged in contentStore.Get
 | 
				
			||||||
 | 
								writeStatus(ctx, 404)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer content.Close()
 | 
						defer content.Close()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,14 +32,12 @@ func (s *Storage) MapTo(v interface{}) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getStorage(name, typ string, overrides ...*ini.Section) Storage {
 | 
					func getStorage(name, typ string, overrides ...*ini.Section) Storage {
 | 
				
			||||||
	sectionName := "storage"
 | 
						const sectionName = "storage"
 | 
				
			||||||
	if len(name) > 0 {
 | 
					 | 
				
			||||||
		sectionName = sectionName + "." + typ
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	sec := Cfg.Section(sectionName)
 | 
						sec := Cfg.Section(sectionName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(overrides) == 0 {
 | 
						if len(overrides) == 0 {
 | 
				
			||||||
		overrides = []*ini.Section{
 | 
							overrides = []*ini.Section{
 | 
				
			||||||
 | 
								Cfg.Section(sectionName + "." + typ),
 | 
				
			||||||
			Cfg.Section(sectionName + "." + name),
 | 
								Cfg.Section(sectionName + "." + name),
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user