Skip to content

Commit 57dc3d1

Browse files
committed
Add response size limit
1 parent 6b08536 commit 57dc3d1

File tree

8 files changed

+51
-4
lines changed

8 files changed

+51
-4
lines changed

custom/conf/app.example.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2417,6 +2417,8 @@ LEVEL = Info
24172417
;DEFAULT_GIT_TREES_PER_PAGE = 1000
24182418
;; Default max size of a blob returned by the blobs API (default is 10MiB)
24192419
;DEFAULT_MAX_BLOB_SIZE = 10485760
2420+
;; Default max combined size of all blobs returned by the files API (default is 100MiB)
2421+
;DEFAULT_MAX_RESPONSE_SIZE = 104857600
24202422

24212423
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
24222424
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

modules/setting/api.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ var API = struct {
1818
DefaultPagingNum int
1919
DefaultGitTreesPerPage int
2020
DefaultMaxBlobSize int64
21+
DefaultMaxResponseSize int64
2122
}{
2223
EnableSwagger: true,
2324
SwaggerURL: "",
2425
MaxResponseItems: 50,
2526
DefaultPagingNum: 30,
2627
DefaultGitTreesPerPage: 1000,
2728
DefaultMaxBlobSize: 10485760,
29+
DefaultMaxResponseSize: 104857600,
2830
}
2931

3032
func loadAPIFrom(rootCfg ConfigProvider) {

modules/structs/settings.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type GeneralAPISettings struct {
2626
DefaultPagingNum int `json:"default_paging_num"`
2727
DefaultGitTreesPerPage int `json:"default_git_trees_per_page"`
2828
DefaultMaxBlobSize int64 `json:"default_max_blob_size"`
29+
DefaultMaxResponseSize int64 `json:"default_max_response_size"`
2930
}
3031

3132
// GeneralAttachmentSettings contains global Attachment settings exposed by API

routers/api/v1/repo/file.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,8 @@ func GetFiles(ctx *context.APIContext) {
10261026
// "$ref": "#/responses/ContentsListResponse"
10271027
// "404":
10281028
// "$ref": "#/responses/notFound"
1029+
// "413":
1030+
// "$ref": "#/responses/contentTooLarge"
10291031

10301032
apiOpts := web.GetForm(ctx).(*api.GetFilesOptions)
10311033

@@ -1045,7 +1047,10 @@ func GetFiles(ctx *context.APIContext) {
10451047
listOpts := utils.GetListOptions(ctx)
10461048
files = util.PaginateSlice(files, listOpts.Page, listOpts.PageSize).([]string)
10471049

1048-
filesResponse := files_service.GetContentsListFromTrees(ctx, ctx.Repo.Repository, ref, files)
1050+
filesResponse, err := files_service.GetContentsListFromTrees(ctx, ctx.Repo.Repository, ref, files)
1051+
if err != nil {
1052+
ctx.APIError(http.StatusRequestEntityTooLarge, err.Error())
1053+
}
10491054

10501055
ctx.SetTotalCountHeader(int64(count))
10511056
ctx.JSON(http.StatusOK, filesResponse)

services/context/api.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ type APIForbiddenError struct {
9191
// swagger:response notFound
9292
type APINotFound struct{}
9393

94+
// APIContentTooLarge is a content too large error response
95+
// swagger:response contentTooLarge
96+
type APIContentTooLarge struct {
97+
APIError
98+
}
99+
94100
// APIConflict is a conflict empty response
95101
// swagger:response conflict
96102
type APIConflict struct{}

services/repository/files/file.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,32 @@ import (
1313

1414
repo_model "code.gitea.io/gitea/models/repo"
1515
"code.gitea.io/gitea/modules/git"
16+
"code.gitea.io/gitea/modules/setting"
1617
api "code.gitea.io/gitea/modules/structs"
1718
"code.gitea.io/gitea/modules/util"
1819
)
1920

20-
func GetContentsListFromTrees(ctx context.Context, repo *repo_model.Repository, branch string, treeNames []string) []*api.ContentsResponse {
21+
func GetContentsListFromTrees(ctx context.Context, repo *repo_model.Repository, branch string, treeNames []string) ([]*api.ContentsResponse, error) {
2122
files := []*api.ContentsResponse{}
23+
var size int64 = 0
2224
for _, file := range treeNames {
2325
fileContents, _ := GetContents(ctx, repo, file, branch, false) // ok if fails, then will be nil
26+
if *fileContents.Content != "" {
27+
size += fileContents.Size // if content isn't empty (e. g. due to the single blob being too large), add file size to response size
28+
}
29+
if size > setting.API.DefaultMaxResponseSize {
30+
return nil, fmt.Errorf("the combined size of the requested blobs exceeds the per-request limit set by the server administrator")
31+
}
2432
files = append(files, fileContents)
2533
}
26-
return files
34+
return files, nil
2735
}
2836

2937
func GetFilesResponseFromCommit(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, branch string, treeNames []string) (*api.FilesResponse, error) {
30-
files := GetContentsListFromTrees(ctx, repo, branch, treeNames)
38+
files, err := GetContentsListFromTrees(ctx, repo, branch, treeNames)
39+
if err != nil {
40+
return nil, err
41+
}
3142
fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil
3243
verification := GetPayloadCommitVerification(ctx, commit)
3344
filesResponse := &api.FilesResponse{

templates/swagger/v1_json.tmpl

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/integration/api_settings_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func TestAPIExposedSettings(t *testing.T) {
3535
DefaultPagingNum: setting.API.DefaultPagingNum,
3636
DefaultGitTreesPerPage: setting.API.DefaultGitTreesPerPage,
3737
DefaultMaxBlobSize: setting.API.DefaultMaxBlobSize,
38+
DefaultMaxResponseSize: setting.API.DefaultMaxResponseSize,
3839
}, apiSettings)
3940

4041
repo := new(api.GeneralRepoSettings)

0 commit comments

Comments
 (0)