* Fix APK's Content-Type header * Fix case sensitive comparison * Add custom mime type mapping for downloadable files * Add documentation for MIME type mapping * Rename download.mimetype.mapping configuration to repository.mimetype_mapping Co-authored-by: zeripath <art27@cantab.net>tags/v1.15.0-rc1
@@ -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] |
@@ -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) |
@@ -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 | |||
} | |||
} |
@@ -1177,4 +1177,5 @@ func NewServices() { | |||
newTaskService() | |||
NewQueueService() | |||
newProject() | |||
newMimeTypeMap() | |||
} |
@@ -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) |