diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 54e727f940..b1fe95e6e2 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -903,6 +903,15 @@ PATH = ;; - approved: only sign when merging an approved pr to a protected branch ;MERGES = pubkey, twofa, basesigned, commitssigned +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;[repository.mimetype_mapping] +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Custom MIME type mapping for downloadable files +;.apk=application/vnd.android.package-archive + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[project] @@ -912,7 +921,6 @@ PATH = ;PROJECT_BOARD_BASIC_KANBAN_TYPE = To Do, In Progress, Done ;PROJECT_BOARD_BUG_TRIAGE_TYPE = Needs Triage, High Priority, Low Priority, Closed - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[cors] diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index a37d06fab6..9bb790f4c9 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -143,6 +143,15 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. - `LOCAL_COPY_PATH`: **tmp/local-repo**: Path for temporary local repository copies. Defaults to `tmp/local-repo` +## Repository - MIME type mapping (`repository.mimetype_mapping`) + +Configuration for set the expected MIME type based on file extensions of downloadable files. Configuration presents in key-value pairs and file extensions starts with leading `.`. + +The following configuration set `Content-Type: application/vnd.android.package-archive` header when downloading files with `.apk` file extension. +```ini +.apk=application/vnd.android.package-archive +``` + ## CORS (`cors`) - `ENABLED`: **false**: enable cors headers (disabled by default) diff --git a/modules/setting/mime_type_map.go b/modules/setting/mime_type_map.go new file mode 100644 index 0000000000..5c1fc7f71a --- /dev/null +++ b/modules/setting/mime_type_map.go @@ -0,0 +1,31 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package setting + +import "strings" + +var ( + // MimeTypeMap defines custom mime type mapping settings + MimeTypeMap = struct { + Enabled bool + Map map[string]string + }{ + Enabled: false, + Map: map[string]string{}, + } +) + +func newMimeTypeMap() { + sec := Cfg.Section("repository.mimetype_mapping") + keys := sec.Keys() + m := make(map[string]string, len(keys)) + for _, key := range keys { + m[strings.ToLower(key.Name())] = key.Value() + } + MimeTypeMap.Map = m + if len(keys) > 0 { + MimeTypeMap.Enabled = true + } +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index aef0d86700..4244b55939 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -1177,4 +1177,5 @@ func NewServices() { newTaskService() NewQueueService() newProject() + newMimeTypeMap() } diff --git a/routers/repo/download.go b/routers/repo/download.go index dafa62d0d9..4917c233ae 100644 --- a/routers/repo/download.go +++ b/routers/repo/download.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "path" + "path/filepath" "strings" "code.gitea.io/gitea/modules/base" @@ -18,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/httpcache" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" ) // ServeData download file from io.Reader @@ -61,6 +63,12 @@ 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)) ctx.Resp.Header().Set("Access-Control-Expose-Headers", "Content-Disposition") + 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) + } + } } _, err = ctx.Resp.Write(buf)