aboutsummaryrefslogtreecommitdiff
path: root/mediaapi
diff options
context:
space:
mode:
authorTill <2353100+S7evinK@users.noreply.github.com>2023-12-12 11:15:50 +0100
committerGitHub <noreply@github.com>2023-12-12 11:15:50 +0100
commit185ad6b00de8079fb6a638ed63e392dfe9f2b49f (patch)
treebe06de8a25a18e8966c118a706a7318eb2471988 /mediaapi
parentfd11e65a9d113839177f9f7a32af328a0292b195 (diff)
Allow some content types to be inlined (#3274)
"Shamelessly" stolen from https://github.com/matrix-org/synapse/pull/15988
Diffstat (limited to 'mediaapi')
-rw-r--r--mediaapi/routing/download.go54
-rw-r--r--mediaapi/routing/download_test.go13
2 files changed, 62 insertions, 5 deletions
diff --git a/mediaapi/routing/download.go b/mediaapi/routing/download.go
index 51afa1f9..fa1c417a 100644
--- a/mediaapi/routing/download.go
+++ b/mediaapi/routing/download.go
@@ -63,6 +63,40 @@ type downloadRequest struct {
DownloadFilename string
}
+// Taken from: https://github.com/matrix-org/synapse/blob/c3627d0f99ed5a23479305dc2bd0e71ca25ce2b1/synapse/media/_base.py#L53C1-L84
+// A list of all content types that are "safe" to be rendered inline in a browser.
+var allowInlineTypes = map[types.ContentType]struct{}{
+ "text/css": {},
+ "text/plain": {},
+ "text/csv": {},
+ "application/json": {},
+ "application/ld+json": {},
+ // We allow some media files deemed as safe, which comes from the matrix-react-sdk.
+ // https://github.com/matrix-org/matrix-react-sdk/blob/a70fcfd0bcf7f8c85986da18001ea11597989a7c/src/utils/blobs.ts#L51
+ // SVGs are *intentionally* omitted.
+ "image/jpeg": {},
+ "image/gif": {},
+ "image/png": {},
+ "image/apng": {},
+ "image/webp": {},
+ "image/avif": {},
+ "video/mp4": {},
+ "video/webm": {},
+ "video/ogg": {},
+ "video/quicktime": {},
+ "audio/mp4": {},
+ "audio/webm": {},
+ "audio/aac": {},
+ "audio/mpeg": {},
+ "audio/ogg": {},
+ "audio/wave": {},
+ "audio/wav": {},
+ "audio/x-wav": {},
+ "audio/x-pn-wav": {},
+ "audio/flac": {},
+ "audio/x-flac": {},
+}
+
// Download implements GET /download and GET /thumbnail
// Files from this server (i.e. origin == cfg.ServerName) are served directly
// Files from remote servers (i.e. origin != cfg.ServerName) are cached locally.
@@ -353,7 +387,7 @@ func (r *downloadRequest) addDownloadFilenameToHeaders(
}
if len(filename) == 0 {
- w.Header().Set("Content-Disposition", "attachment")
+ w.Header().Set("Content-Disposition", contentDispositionFor(""))
return nil
}
@@ -383,20 +417,21 @@ func (r *downloadRequest) addDownloadFilenameToHeaders(
unescaped = strings.ReplaceAll(unescaped, `\`, `\\"`)
unescaped = strings.ReplaceAll(unescaped, `"`, `\"`)
+ disposition := contentDispositionFor(responseMetadata.ContentType)
if isASCII {
// For ASCII filenames, we should only quote the filename if
// it needs to be done, e.g. it contains a space or a character
// that would otherwise be parsed as a control character in the
// Content-Disposition header
w.Header().Set("Content-Disposition", fmt.Sprintf(
- `attachment; filename=%s%s%s`,
- quote, unescaped, quote,
+ `%s; filename=%s%s%s`,
+ disposition, quote, unescaped, quote,
))
} else {
// For UTF-8 filenames, we quote always, as that's the standard
w.Header().Set("Content-Disposition", fmt.Sprintf(
- `attachment; filename*=utf-8''%s`,
- url.QueryEscape(unescaped),
+ `%s; filename*=utf-8''%s`,
+ disposition, url.QueryEscape(unescaped),
))
}
@@ -808,3 +843,12 @@ func (r *downloadRequest) fetchRemoteFile(
return types.Path(finalPath), duplicate, nil
}
+
+// contentDispositionFor returns the Content-Disposition for a given
+// content type.
+func contentDispositionFor(contentType types.ContentType) string {
+ if _, ok := allowInlineTypes[contentType]; ok {
+ return "inline"
+ }
+ return "attachment"
+}
diff --git a/mediaapi/routing/download_test.go b/mediaapi/routing/download_test.go
new file mode 100644
index 00000000..21f6bfc2
--- /dev/null
+++ b/mediaapi/routing/download_test.go
@@ -0,0 +1,13 @@
+package routing
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func Test_dispositionFor(t *testing.T) {
+ assert.Equal(t, "attachment", contentDispositionFor(""), "empty content type")
+ assert.Equal(t, "attachment", contentDispositionFor("image/svg"), "image/svg")
+ assert.Equal(t, "inline", contentDispositionFor("image/jpeg"), "image/jpg")
+}