From 6ed9057fd76b2d5d0dfdb3c663367ae861ab8093 Mon Sep 17 00:00:00 2001
From: Gusted <postmaster@gusted.xyz>
Date: Fri, 19 Jan 2024 01:14:49 +0100
Subject: [PATCH] [GITEA] Fix API inconsistencies

- Document the correct content types for Git archives. Add code that
actually sets the correct application type for `.zip` and `.tar.gz`.
- When an action (POST/PUT/DELETE method) was successful, an 204 status
code should be returned instead of status code 200.
- Add and adjust integration testing.
- Resolves #2180
- Resolves #2181

(cherry picked from commit 6c8c4512b530e966557a5584efbbb757638b3429)
(cherry picked from commit 3f74bcb14df99ee75a170813979beb5ce04c8027)
---
 routers/api/v1/admin/user.go               |  2 +-
 routers/api/v1/repo/file.go                | 14 +++++++++++++-
 templates/swagger/v1_json.tmpl             |  4 +++-
 tests/integration/api_admin_test.go        |  6 +++---
 tests/integration/api_repo_archive_test.go |  3 +++
 5 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go
index b4cc42ea5d..cfd9ff9cab 100644
--- a/routers/api/v1/admin/user.go
+++ b/routers/api/v1/admin/user.go
@@ -545,5 +545,5 @@ func RenameUser(ctx *context.APIContext) {
 	}
 
 	log.Trace("User name changed: %s -> %s", oldName, newName)
-	ctx.Status(http.StatusOK)
+	ctx.Status(http.StatusNoContent)
 }
diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go
index 065d6bf8b2..46dce95929 100644
--- a/routers/api/v1/repo/file.go
+++ b/routers/api/v1/repo/file.go
@@ -257,7 +257,9 @@ func GetArchive(ctx *context.APIContext) {
 	// ---
 	// summary: Get an archive of a repository
 	// produces:
-	// - application/json
+	// - application/octet-stream
+	// - application/zip
+	// - application/gzip
 	// parameters:
 	// - name: owner
 	//   in: path
@@ -337,7 +339,17 @@ func download(ctx *context.APIContext, archiveName string, archiver *repo_model.
 	}
 	defer fr.Close()
 
+	contentType := ""
+	switch archiver.Type {
+	case git.ZIP:
+		contentType = "application/zip"
+	case git.TARGZ:
+		// Per RFC6713.
+		contentType = "application/gzip"
+	}
+
 	ctx.ServeContent(fr, &context.ServeHeaderOptions{
+		ContentType:  contentType,
 		Filename:     downloadName,
 		LastModified: archiver.CreatedUnix.AsLocalTime(),
 	})
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 7cebaa875f..40c323b9f1 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -3533,7 +3533,9 @@
     "/repos/{owner}/{repo}/archive/{archive}": {
       "get": {
         "produces": [
-          "application/json"
+          "application/octet-stream",
+          "application/zip",
+          "application/gzip"
         ],
         "tags": [
           "repository"
diff --git a/tests/integration/api_admin_test.go b/tests/integration/api_admin_test.go
index ff7c2ddca3..3c80401e0f 100644
--- a/tests/integration/api_admin_test.go
+++ b/tests/integration/api_admin_test.go
@@ -254,14 +254,14 @@ func TestAPIRenameUser(t *testing.T) {
 		// required
 		"new_name": "User2",
 	}).AddTokenAuth(token)
-	MakeRequest(t, req, http.StatusOK)
+	MakeRequest(t, req, http.StatusNoContent)
 
 	urlStr = fmt.Sprintf("/api/v1/admin/users/%s/rename", "User2")
 	req = NewRequestWithValues(t, "POST", urlStr, map[string]string{
 		// required
 		"new_name": "User2-2-2",
 	}).AddTokenAuth(token)
-	MakeRequest(t, req, http.StatusOK)
+	MakeRequest(t, req, http.StatusNoContent)
 
 	req = NewRequestWithValues(t, "POST", urlStr, map[string]string{
 		// required
@@ -281,7 +281,7 @@ func TestAPIRenameUser(t *testing.T) {
 		// required
 		"new_name": "user2",
 	}).AddTokenAuth(token)
-	MakeRequest(t, req, http.StatusOK)
+	MakeRequest(t, req, http.StatusNoContent)
 }
 
 func TestAPICron(t *testing.T) {
diff --git a/tests/integration/api_repo_archive_test.go b/tests/integration/api_repo_archive_test.go
index 57d3abfe84..c574d49450 100644
--- a/tests/integration/api_repo_archive_test.go
+++ b/tests/integration/api_repo_archive_test.go
@@ -32,18 +32,21 @@ func TestAPIDownloadArchive(t *testing.T) {
 	bs, err := io.ReadAll(resp.Body)
 	assert.NoError(t, err)
 	assert.Len(t, bs, 320)
+	assert.EqualValues(t, "application/zip", resp.Header().Get("Content-Type"))
 
 	link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master.tar.gz", user2.Name, repo.Name))
 	resp = MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusOK)
 	bs, err = io.ReadAll(resp.Body)
 	assert.NoError(t, err)
 	assert.Len(t, bs, 266)
+	assert.EqualValues(t, "application/gzip", resp.Header().Get("Content-Type"))
 
 	link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master.bundle", user2.Name, repo.Name))
 	resp = MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusOK)
 	bs, err = io.ReadAll(resp.Body)
 	assert.NoError(t, err)
 	assert.Len(t, bs, 382)
+	assert.EqualValues(t, "application/octet-stream", resp.Header().Get("Content-Type"))
 
 	link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/archive/master", user2.Name, repo.Name))
 	MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusBadRequest)