From ce286f9d9c00ceb24fb4eab4cab56c0b0678765a Mon Sep 17 00:00:00 2001
From: Jimmy Praet <jimmy.praet@telenet.be>
Date: Wed, 30 Jun 2021 23:31:54 +0200
Subject: [PATCH] Support custom mime type mapping for text files (#16304)

* Support custom mime type mapping for text files

* Apply suggested change to routers/common/repo.go

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
---
 integrations/download_test.go                 |  28 ++++++++++++++++++
 .../10/32bbf17fbc0d9c95bb5418dabe8f8c99278700 |   2 ++
 .../26/f842bcad37fa40a1bb34cbb5ee219ee35d863d | Bin 0 -> 75 bytes
 .../ba/1aed4e2ea2443d76cec241b96be4ec990852ec | Bin 0 -> 117 bytes
 .../user2/repo2.git/refs/heads/master         |   2 +-
 routers/common/repo.go                        |  20 ++++++++-----
 6 files changed, 43 insertions(+), 9 deletions(-)
 create mode 100644 integrations/gitea-repositories-meta/user2/repo2.git/objects/10/32bbf17fbc0d9c95bb5418dabe8f8c99278700
 create mode 100644 integrations/gitea-repositories-meta/user2/repo2.git/objects/26/f842bcad37fa40a1bb34cbb5ee219ee35d863d
 create mode 100644 integrations/gitea-repositories-meta/user2/repo2.git/objects/ba/1aed4e2ea2443d76cec241b96be4ec990852ec

diff --git a/integrations/download_test.go b/integrations/download_test.go
index 305155e9ac..38de75f476 100644
--- a/integrations/download_test.go
+++ b/integrations/download_test.go
@@ -8,6 +8,7 @@ import (
 	"net/http"
 	"testing"
 
+	"code.gitea.io/gitea/modules/setting"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -62,3 +63,30 @@ func TestDownloadByIDMediaForSVGUsesSecureHeaders(t *testing.T) {
 	assert.Equal(t, "image/svg+xml", resp.HeaderMap.Get("Content-Type"))
 	assert.Equal(t, "nosniff", resp.HeaderMap.Get("X-Content-Type-Options"))
 }
+
+func TestDownloadRawTextFileWithoutMimeTypeMapping(t *testing.T) {
+	defer prepareTestEnv(t)()
+
+	session := loginUser(t, "user2")
+
+	req := NewRequest(t, "GET", "/user2/repo2/raw/branch/master/test.xml")
+	resp := session.MakeRequest(t, req, http.StatusOK)
+
+	assert.Equal(t, "text/plain; charset=utf-8", resp.HeaderMap.Get("Content-Type"))
+}
+
+func TestDownloadRawTextFileWithMimeTypeMapping(t *testing.T) {
+	defer prepareTestEnv(t)()
+	setting.MimeTypeMap.Map[".xml"] = "text/xml"
+	setting.MimeTypeMap.Enabled = true
+
+	session := loginUser(t, "user2")
+
+	req := NewRequest(t, "GET", "/user2/repo2/raw/branch/master/test.xml")
+	resp := session.MakeRequest(t, req, http.StatusOK)
+
+	assert.Equal(t, "text/xml; charset=utf-8", resp.HeaderMap.Get("Content-Type"))
+
+	delete(setting.MimeTypeMap.Map, ".xml")
+	setting.MimeTypeMap.Enabled = false
+}
diff --git a/integrations/gitea-repositories-meta/user2/repo2.git/objects/10/32bbf17fbc0d9c95bb5418dabe8f8c99278700 b/integrations/gitea-repositories-meta/user2/repo2.git/objects/10/32bbf17fbc0d9c95bb5418dabe8f8c99278700
new file mode 100644
index 0000000000..736e40878e
--- /dev/null
+++ b/integrations/gitea-repositories-meta/user2/repo2.git/objects/10/32bbf17fbc0d9c95bb5418dabe8f8c99278700
@@ -0,0 +1,2 @@
+x��K
+�0Eg�%��":u��􊕦J|������p˭�Q��~%
�9ل����G6G� �ͦw(��E4}*���{�)`YƆ�l�e�MJO�ܚ>�����%��^��ݿ�L�!]�N[v#E�6�U~/���0Z��U'�gpJ5
\ No newline at end of file
diff --git a/integrations/gitea-repositories-meta/user2/repo2.git/objects/26/f842bcad37fa40a1bb34cbb5ee219ee35d863d b/integrations/gitea-repositories-meta/user2/repo2.git/objects/26/f842bcad37fa40a1bb34cbb5ee219ee35d863d
new file mode 100644
index 0000000000000000000000000000000000000000..c3e7e778c5bc1e5a44f0ff429b4aa801c0938199
GIT binary patch
literal 75
zcmV-R0JQ&j0ZYosPf{>5VX(2U$jwnGOD!tS%+Iq`GSo9rQb^59&QHnAOSe@D4RO=8
hP_nn<vMEU|F0l*A$ShU>q6l9f8-1_{7XU4N7C{`8AG`nn

literal 0
HcmV?d00001

diff --git a/integrations/gitea-repositories-meta/user2/repo2.git/objects/ba/1aed4e2ea2443d76cec241b96be4ec990852ec b/integrations/gitea-repositories-meta/user2/repo2.git/objects/ba/1aed4e2ea2443d76cec241b96be4ec990852ec
new file mode 100644
index 0000000000000000000000000000000000000000..add9a3af0d4c37c916e85c963b20a314b8fe3294
GIT binary patch
literal 117
zcmV-*0E+*30V^p=O;s>7FlR6{FfcPQQSivmP1VayVR+T_r@efUH~XP%EAKClN_3cu
z?N&pT<YeZh>J^uzGbB&l)+hgNx13LEwg3F=Md?`@Hr!A(C8@<FdKI}j3~E1|_N+Dk
X<*;zK$?2`{6z4sTZL<XcZ(A&<y_GrQ

literal 0
HcmV?d00001

diff --git a/integrations/gitea-repositories-meta/user2/repo2.git/refs/heads/master b/integrations/gitea-repositories-meta/user2/repo2.git/refs/heads/master
index 10967a9b8a..334d09ca02 100644
--- a/integrations/gitea-repositories-meta/user2/repo2.git/refs/heads/master
+++ b/integrations/gitea-repositories-meta/user2/repo2.git/refs/heads/master
@@ -1 +1 @@
-205ac761f3326a7ebe416e8673760016450b5cec
+1032bbf17fbc0d9c95bb5418dabe8f8c99278700
diff --git a/routers/common/repo.go b/routers/common/repo.go
index 22403da097..8d33fb07fb 100644
--- a/routers/common/repo.go
+++ b/routers/common/repo.go
@@ -64,16 +64,26 @@ func ServeData(ctx *context.Context, name string, size int64, reader io.Reader)
 
 	st := typesniffer.DetectContentType(buf)
 
+	mappedMimeType := ""
+	if setting.MimeTypeMap.Enabled {
+		fileExtension := strings.ToLower(filepath.Ext(name))
+		mappedMimeType = setting.MimeTypeMap.Map[fileExtension]
+	}
 	if st.IsText() || ctx.QueryBool("render") {
 		cs, err := charset.DetectEncoding(buf)
 		if err != nil {
 			log.Error("Detect raw file %s charset failed: %v, using by default utf-8", name, err)
 			cs = "utf-8"
 		}
-		ctx.Resp.Header().Set("Content-Type", "text/plain; charset="+strings.ToLower(cs))
+		if mappedMimeType == "" {
+			mappedMimeType = "text/plain"
+		}
+		ctx.Resp.Header().Set("Content-Type", mappedMimeType+"; charset="+strings.ToLower(cs))
 	} else {
 		ctx.Resp.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
-
+		if mappedMimeType != "" {
+			ctx.Resp.Header().Set("Content-Type", mappedMimeType)
+		}
 		if (st.IsImage() || st.IsPDF()) && (setting.UI.SVG.Enabled || !st.IsSvgImage()) {
 			ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name))
 			if st.IsSvgImage() {
@@ -83,12 +93,6 @@ func ServeData(ctx *context.Context, name string, size int64, reader io.Reader)
 			}
 		} else {
 			ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name))
-			if setting.MimeTypeMap.Enabled {
-				fileExtension := strings.ToLower(filepath.Ext(name))
-				if mimetype, ok := setting.MimeTypeMap.Map[fileExtension]; ok {
-					ctx.Resp.Header().Set("Content-Type", mimetype)
-				}
-			}
 		}
 	}