Compare commits

...

6 Commits

Author SHA1 Message Date
a1012112796
ad26b52ff5
Merge 5f200eea5bd324302125ba8c32db94b6cfdb33db into c5332fdc559a725b73e0d89b79e34906b5a6c2c6 2025-09-29 17:35:29 +08:00
wxiaoguang
5f200eea5b user modern golang error system 2025-09-24 23:21:57 +08:00
a1012112796
e19a4b17a5
fix nits 2025-09-24 23:00:49 +08:00
a1012112796
d11f7c899b
Merge remote-tracking branch 'origin/main' into zzc/dev/attach_size_limit 2025-09-24 22:19:50 +08:00
a1012112796
08035a7af2
fix test and apply suggestions
Signed-off-by: a1012112796 <1012112796@qq.com>
2025-09-23 10:45:01 +08:00
a1012112796
7342304809
fix attachment file size limit in server backend
fix #35512

Signed-off-by: a1012112796 <1012112796@qq.com>
2025-09-22 17:29:49 +08:00
8 changed files with 60 additions and 6 deletions

View File

@ -16,6 +16,7 @@ var (
ErrPermissionDenied = errors.New("permission denied") // also implies HTTP 403
ErrNotExist = errors.New("resource does not exist") // also implies HTTP 404
ErrAlreadyExist = errors.New("resource already exists") // also implies HTTP 409
ErrContentTooLarge = errors.New("content exceeds limit") // also implies HTTP 413
// ErrUnprocessableContent implies HTTP 422, the syntax of the request content is correct,
// but the server is unable to process the contained instructions

View File

@ -4,6 +4,7 @@
package repo
import (
"errors"
"net/http"
issues_model "code.gitea.io/gitea/models/issues"
@ -11,6 +12,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
attachment_service "code.gitea.io/gitea/services/attachment"
"code.gitea.io/gitea/services/context"
@ -154,6 +156,8 @@ func CreateIssueAttachment(ctx *context.APIContext) {
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/error"
// "413":
// "$ref": "#/responses/error"
// "422":
// "$ref": "#/responses/validationError"
// "423":
@ -181,7 +185,7 @@ func CreateIssueAttachment(ctx *context.APIContext) {
filename = query
}
attachment, err := attachment_service.UploadAttachment(ctx, file, setting.Attachment.AllowedTypes, header.Size, &repo_model.Attachment{
attachment, err := attachment_service.UploadAttachment(ctx, file, setting.Attachment.AllowedTypes, setting.Attachment.MaxSize<<20, header.Size, &repo_model.Attachment{
Name: filename,
UploaderID: ctx.Doer.ID,
RepoID: ctx.Repo.Repository.ID,
@ -190,6 +194,8 @@ func CreateIssueAttachment(ctx *context.APIContext) {
if err != nil {
if upload.IsErrFileTypeForbidden(err) {
ctx.APIError(http.StatusUnprocessableEntity, err)
} else if errors.Is(err, util.ErrContentTooLarge) {
ctx.APIError(http.StatusRequestEntityTooLarge, err)
} else {
ctx.APIErrorInternal(err)
}

View File

@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
attachment_service "code.gitea.io/gitea/services/attachment"
"code.gitea.io/gitea/services/context"
@ -161,6 +162,8 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) {
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/error"
// "413":
// "$ref": "#/responses/error"
// "422":
// "$ref": "#/responses/validationError"
// "423":
@ -189,7 +192,7 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) {
filename = query
}
attachment, err := attachment_service.UploadAttachment(ctx, file, setting.Attachment.AllowedTypes, header.Size, &repo_model.Attachment{
attachment, err := attachment_service.UploadAttachment(ctx, file, setting.Attachment.AllowedTypes, setting.Attachment.MaxSize<<20, header.Size, &repo_model.Attachment{
Name: filename,
UploaderID: ctx.Doer.ID,
RepoID: ctx.Repo.Repository.ID,
@ -199,6 +202,8 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) {
if err != nil {
if upload.IsErrFileTypeForbidden(err) {
ctx.APIError(http.StatusUnprocessableEntity, err)
} else if errors.Is(err, util.ErrContentTooLarge) {
ctx.APIError(http.StatusRequestEntityTooLarge, err)
} else {
ctx.APIErrorInternal(err)
}

View File

@ -4,6 +4,7 @@
package repo
import (
"errors"
"io"
"net/http"
"strings"
@ -12,6 +13,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
attachment_service "code.gitea.io/gitea/services/attachment"
"code.gitea.io/gitea/services/context"
@ -191,6 +193,8 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/notFound"
// "413":
// "$ref": "#/responses/error"
// Check if attachments are enabled
if !setting.Attachment.Enabled {
@ -234,7 +238,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
}
// Create a new attachment and save the file
attach, err := attachment_service.UploadAttachment(ctx, content, setting.Repository.Release.AllowedTypes, size, &repo_model.Attachment{
attach, err := attachment_service.UploadAttachment(ctx, content, setting.Repository.Release.AllowedTypes, setting.Attachment.MaxSize<<20, size, &repo_model.Attachment{
Name: filename,
UploaderID: ctx.Doer.ID,
RepoID: ctx.Repo.Repository.ID,
@ -245,6 +249,12 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
ctx.APIError(http.StatusBadRequest, err)
return
}
if errors.Is(err, util.ErrContentTooLarge) {
ctx.APIError(http.StatusRequestEntityTooLarge, err)
return
}
ctx.APIErrorInternal(err)
return
}

View File

@ -45,7 +45,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) {
}
defer file.Close()
attach, err := attachment.UploadAttachment(ctx, file, allowedTypes, header.Size, &repo_model.Attachment{
attach, err := attachment.UploadAttachment(ctx, file, allowedTypes, setting.Attachment.MaxSize<<20, header.Size, &repo_model.Attachment{
Name: header.Filename,
UploaderID: ctx.Doer.ID,
RepoID: repoID,

View File

@ -38,8 +38,21 @@ func NewAttachment(ctx context.Context, attach *repo_model.Attachment, file io.R
return attach, err
}
type ErrAttachmentSizeExceed struct {
MaxSize int64
Size int64
}
func (e ErrAttachmentSizeExceed) Error() string {
return fmt.Sprintf("attachment size %d exceeds limit %d", e.Size, e.MaxSize)
}
func (e ErrAttachmentSizeExceed) Unwrap() error {
return util.ErrContentTooLarge
}
// UploadAttachment upload new attachment into storage and update database
func UploadAttachment(ctx context.Context, file io.Reader, allowedTypes string, fileSize int64, attach *repo_model.Attachment) (*repo_model.Attachment, error) {
func UploadAttachment(ctx context.Context, file io.Reader, allowedTypes string, maxFileSize, fileSize int64, attach *repo_model.Attachment) (*repo_model.Attachment, error) {
buf := make([]byte, 1024)
n, _ := util.ReadAtMost(file, buf)
buf = buf[:n]
@ -48,6 +61,10 @@ func UploadAttachment(ctx context.Context, file io.Reader, allowedTypes string,
return nil, err
}
if maxFileSize >= 0 && fileSize > (maxFileSize) {
return nil, ErrAttachmentSizeExceed{MaxSize: maxFileSize, Size: fileSize}
}
return NewAttachment(ctx, attach, io.MultiReader(bytes.NewReader(buf), file), fileSize)
}

View File

@ -6,6 +6,7 @@ package incoming
import (
"bytes"
"context"
"errors"
"fmt"
issues_model "code.gitea.io/gitea/models/issues"
@ -85,7 +86,7 @@ func (h *ReplyHandler) Handle(ctx context.Context, content *MailContent, doer *u
attachmentIDs := make([]string, 0, len(content.Attachments))
if setting.Attachment.Enabled {
for _, attachment := range content.Attachments {
a, err := attachment_service.UploadAttachment(ctx, bytes.NewReader(attachment.Content), setting.Attachment.AllowedTypes, int64(len(attachment.Content)), &repo_model.Attachment{
a, err := attachment_service.UploadAttachment(ctx, bytes.NewReader(attachment.Content), setting.Attachment.AllowedTypes, setting.Attachment.MaxSize<<20, int64(len(attachment.Content)), &repo_model.Attachment{
Name: attachment.Name,
UploaderID: doer.ID,
RepoID: issue.Repo.ID,
@ -95,6 +96,11 @@ func (h *ReplyHandler) Handle(ctx context.Context, content *MailContent, doer *u
log.Info("Skipping disallowed attachment type: %s", attachment.Name)
continue
}
if errors.Is(err, util.ErrContentTooLarge) {
log.Info("Skipping attachment exceeding size limit: %s", attachment.Name)
continue
}
return err
}
attachmentIDs = append(attachmentIDs, a.UUID)

View File

@ -9569,6 +9569,9 @@
"404": {
"$ref": "#/responses/error"
},
"413": {
"$ref": "#/responses/error"
},
"422": {
"$ref": "#/responses/validationError"
},
@ -10194,6 +10197,9 @@
"404": {
"$ref": "#/responses/error"
},
"413": {
"$ref": "#/responses/error"
},
"422": {
"$ref": "#/responses/validationError"
},
@ -15510,6 +15516,9 @@
},
"404": {
"$ref": "#/responses/notFound"
},
"413": {
"$ref": "#/responses/error"
}
}
}