From 0a97480934fc2082c9cff18a5b66cedc12575919 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Thu, 21 Jul 2022 21:18:41 +0200 Subject: [PATCH] Add "X-Gitea-Object-Type" header for GET `/raw/` & `/media/` API (#20438) --- integrations/api_repo_raw_test.go | 8 ++++++-- routers/api/v1/repo/file.go | 14 ++++++++++---- services/repository/files/content.go | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/integrations/api_repo_raw_test.go b/integrations/api_repo_raw_test.go index 2a77d1ba63..258b409bef 100644 --- a/integrations/api_repo_raw_test.go +++ b/integrations/api_repo_raw_test.go @@ -10,6 +10,8 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + + "github.com/stretchr/testify/assert" ) func TestAPIReposRaw(t *testing.T) { @@ -25,9 +27,11 @@ func TestAPIReposRaw(t *testing.T) { "65f1bf27bc3bf70f64657658635e66094edbcb4d", // Commit } { req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/%s/README.md?token="+token, user.Name, ref) - session.MakeRequest(t, req, http.StatusOK) + resp := session.MakeRequest(t, req, http.StatusOK) + assert.EqualValues(t, "file", resp.Header().Get("x-gitea-object-type")) } // Test default branch req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/README.md?token="+token, user.Name) - session.MakeRequest(t, req, http.StatusOK) + resp := session.MakeRequest(t, req, http.StatusOK) + assert.EqualValues(t, "file", resp.Header().Get("x-gitea-object-type")) } diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index 1ac1088839..ba8a938b83 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -33,6 +33,8 @@ import ( files_service "code.gitea.io/gitea/services/repository/files" ) +const giteaObjectTypeHeader = "X-Gitea-Object-Type" + // GetRawFile get a file by path on a repository func GetRawFile(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/raw/{filepath} repository repoGetRawFile @@ -72,11 +74,13 @@ func GetRawFile(ctx *context.APIContext) { return } - blob, lastModified := getBlobForEntry(ctx) + blob, entry, lastModified := getBlobForEntry(ctx) if ctx.Written() { return } + ctx.RespHeader().Set(giteaObjectTypeHeader, string(files_service.GetObjectTypeFromTreeEntry(entry))) + if err := common.ServeBlob(ctx.Context, blob, lastModified); err != nil { ctx.Error(http.StatusInternalServerError, "ServeBlob", err) } @@ -119,11 +123,13 @@ func GetRawFileOrLFS(ctx *context.APIContext) { return } - blob, lastModified := getBlobForEntry(ctx) + blob, entry, lastModified := getBlobForEntry(ctx) if ctx.Written() { return } + ctx.RespHeader().Set(giteaObjectTypeHeader, string(files_service.GetObjectTypeFromTreeEntry(entry))) + // LFS Pointer files are at most 1024 bytes - so any blob greater than 1024 bytes cannot be an LFS file if blob.Size() > 1024 { // First handle caching for the blob @@ -218,7 +224,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) { } } -func getBlobForEntry(ctx *context.APIContext) (blob *git.Blob, lastModified time.Time) { +func getBlobForEntry(ctx *context.APIContext) (blob *git.Blob, entry *git.TreeEntry, lastModified time.Time) { entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) if err != nil { if git.IsErrNotExist(err) { @@ -251,7 +257,7 @@ func getBlobForEntry(ctx *context.APIContext) (blob *git.Blob, lastModified time } blob = entry.Blob() - return blob, lastModified + return blob, entry, lastModified } // GetArchive get archive of a repository diff --git a/services/repository/files/content.go b/services/repository/files/content.go index 2237671a60..c206909289 100644 --- a/services/repository/files/content.go +++ b/services/repository/files/content.go @@ -101,6 +101,22 @@ func GetContentsOrList(ctx context.Context, repo *repo_model.Repository, treePat return fileList, nil } +// GetObjectTypeFromTreeEntry check what content is behind it +func GetObjectTypeFromTreeEntry(entry *git.TreeEntry) ContentType { + switch { + case entry.IsDir(): + return ContentTypeDir + case entry.IsSubModule(): + return ContentTypeSubmodule + case entry.IsExecutable(), entry.IsRegular(): + return ContentTypeRegular + case entry.IsLink(): + return ContentTypeLink + default: + return "" + } +} + // GetContents gets the meta data on a file's contents. Ref can be a branch, commit or tag func GetContents(ctx context.Context, repo *repo_model.Repository, treePath, ref string, forList bool) (*api.ContentsResponse, error) { if ref == "" {