diff options
author | wxiaoguang <wxiaoguang@gmail.com> | 2023-07-19 02:14:47 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-18 18:14:47 +0000 |
commit | 236c645bf16754ca9294545e71014a01a24ccfd8 (patch) | |
tree | 4ca9d8f93aca854d841a7379955e9653a8212546 /routers/api/v1/repo/file.go | |
parent | 265a28802a6062d86964c9bfe1959437eaf69afb (diff) | |
download | gitea-236c645bf16754ca9294545e71014a01a24ccfd8.tar.gz gitea-236c645bf16754ca9294545e71014a01a24ccfd8.zip |
Refactor "Content" for file uploading (#25851)
Before: the concept "Content string" is used everywhere. It has some
problems:
1. Sometimes it means "base64 encoded content", sometimes it means "raw
binary content"
2. It doesn't work with large files, eg: uploading a 1G LFS file would
make Gitea process OOM
This PR does the refactoring: use "ContentReader" / "ContentBase64"
instead of "Content"
This PR is not breaking because the key in API JSON is still "content":
`` ContentBase64 string `json:"content"` ``
Diffstat (limited to 'routers/api/v1/repo/file.go')
-rw-r--r-- | routers/api/v1/repo/file.go | 61 |
1 files changed, 39 insertions, 22 deletions
diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index bf37532fc8..ffde5855ba 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -408,6 +408,14 @@ func canReadFiles(r *context.Repository) bool { return r.Permission.CanRead(unit.TypeCode) } +func base64Reader(s string) (io.Reader, error) { + b, err := base64.StdEncoding.DecodeString(s) + if err != nil { + return nil, err + } + return bytes.NewReader(b), nil +} + // ChangeFiles handles API call for modifying multiple files func ChangeFiles(ctx *context.APIContext) { // swagger:operation POST /repos/{owner}/{repo}/contents repository repoChangeFiles @@ -449,14 +457,19 @@ func ChangeFiles(ctx *context.APIContext) { apiOpts.BranchName = ctx.Repo.Repository.DefaultBranch } - files := []*files_service.ChangeRepoFile{} + var files []*files_service.ChangeRepoFile for _, file := range apiOpts.Files { + contentReader, err := base64Reader(file.ContentBase64) + if err != nil { + ctx.Error(http.StatusUnprocessableEntity, "Invalid base64 content", err) + return + } changeRepoFile := &files_service.ChangeRepoFile{ - Operation: file.Operation, - TreePath: file.Path, - FromTreePath: file.FromPath, - Content: file.Content, - SHA: file.SHA, + Operation: file.Operation, + TreePath: file.Path, + FromTreePath: file.FromPath, + ContentReader: contentReader, + SHA: file.SHA, } files = append(files, changeRepoFile) } @@ -544,12 +557,18 @@ func CreateFile(ctx *context.APIContext) { apiOpts.BranchName = ctx.Repo.Repository.DefaultBranch } + contentReader, err := base64Reader(apiOpts.ContentBase64) + if err != nil { + ctx.Error(http.StatusUnprocessableEntity, "Invalid base64 content", err) + return + } + opts := &files_service.ChangeRepoFilesOptions{ Files: []*files_service.ChangeRepoFile{ { - Operation: "create", - TreePath: ctx.Params("*"), - Content: apiOpts.Content, + Operation: "create", + TreePath: ctx.Params("*"), + ContentReader: contentReader, }, }, Message: apiOpts.Message, @@ -636,14 +655,20 @@ func UpdateFile(ctx *context.APIContext) { apiOpts.BranchName = ctx.Repo.Repository.DefaultBranch } + contentReader, err := base64Reader(apiOpts.ContentBase64) + if err != nil { + ctx.Error(http.StatusUnprocessableEntity, "Invalid base64 content", err) + return + } + opts := &files_service.ChangeRepoFilesOptions{ Files: []*files_service.ChangeRepoFile{ { - Operation: "update", - Content: apiOpts.Content, - SHA: apiOpts.SHA, - FromTreePath: apiOpts.FromPath, - TreePath: ctx.Params("*"), + Operation: "update", + ContentReader: contentReader, + SHA: apiOpts.SHA, + FromTreePath: apiOpts.FromPath, + TreePath: ctx.Params("*"), }, }, Message: apiOpts.Message, @@ -709,14 +734,6 @@ func createOrUpdateFiles(ctx *context.APIContext, opts *files_service.ChangeRepo } } - for _, file := range opts.Files { - content, err := base64.StdEncoding.DecodeString(file.Content) - if err != nil { - return nil, err - } - file.Content = string(content) - } - return files_service.ChangeRepoFiles(ctx, ctx.Repo.Repository, ctx.Doer, opts) } |