Skip to content

Commit c6fc6ed

Browse files
committed
Serve raw files with the correct content types
Resolves #8152. Signed-off-by: Trevor Slocum <[email protected]>
1 parent 1ba8b95 commit c6fc6ed

File tree

1 file changed

+33
-12
lines changed

1 file changed

+33
-12
lines changed

routers/repo/download.go

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ import (
1919
"code.gitea.io/gitea/modules/log"
2020
)
2121

22+
var javascriptTypes = []string{"application/ecmascript", "application/javascript", "text/ecmascript", "text/javascript",
23+
"text/jscript", "text/livescript"}
24+
2225
// ServeData download file from io.Reader
2326
func ServeData(ctx *context.Context, name string, size int64, reader io.Reader) error {
2427
buf := make([]byte, 1024)
@@ -41,26 +44,44 @@ func ServeData(ctx *context.Context, name string, size int64, reader io.Reader)
4144
// Google Chrome dislike commas in filenames, so let's change it to a space
4245
name = strings.ReplaceAll(name, ",", " ")
4346

44-
if base.IsTextFile(buf) || ctx.QueryBool("render") {
45-
cs, err := charset.DetectEncoding(buf)
46-
if err != nil {
47-
log.Error("Detect raw file %s charset failed: %v, using by default utf-8", name, err)
48-
cs = "utf-8"
47+
ct := base.DetectContentType(buf)
48+
matches := func(mimes []string) bool {
49+
for _, mime := range mimes {
50+
if strings.Contains(ct, mime) {
51+
return true
52+
}
4953
}
50-
ctx.Resp.Header().Set("Content-Type", "text/plain; charset="+strings.ToLower(cs))
51-
} else if base.IsImageFile(buf) || base.IsPDFFile(buf) {
54+
return false
55+
}
56+
if ct == "" {
57+
log.Error("Detect raw file %s content type failed: %v, using by default text/plain", name, err)
58+
ct = "text/plain"
59+
} else if matches(javascriptTypes) {
60+
// Serve JavaScript files as plain text to prevent XSS attacks
61+
ct = "text/plain"
62+
}
63+
64+
if matches([]string{"text/"}) || ctx.QueryBool("render") {
65+
if !strings.Contains(ct, "charset=") {
66+
cs, err := charset.DetectEncoding(buf)
67+
if err != nil {
68+
log.Error("Detect raw file %s charset failed: %v, using by default utf-8", name, err)
69+
cs = "utf-8"
70+
}
71+
ct += "; charset=" + cs
72+
}
73+
} else if matches([]string{"image/", "application/pdf"}) {
5274
ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name))
5375
ctx.Resp.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
54-
if base.IsSVGImageFile(buf) {
55-
ctx.Resp.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")
56-
ctx.Resp.Header().Set("X-Content-Type-Options", "nosniff")
57-
ctx.Resp.Header().Set("Content-Type", base.SVGMimeType)
58-
}
5976
} else {
6077
ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name))
6178
ctx.Resp.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
6279
}
6380

81+
ctx.Resp.Header().Set("Content-Type", strings.ToLower(ct))
82+
ctx.Resp.Header().Set("X-Content-Type-Options", "nosniff")
83+
ctx.Resp.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")
84+
6485
_, err = ctx.Resp.Write(buf)
6586
if err != nil {
6687
return err

0 commit comments

Comments
 (0)