diff --git a/api/client-server/content-repo.yaml b/api/client-server/content-repo.yaml index 4460bb69..a9a0c2f6 100644 --- a/api/client-server/content-repo.yaml +++ b/api/client-server/content-repo.yaml @@ -1,4 +1,5 @@ # Copyright 2016 OpenMarket Ltd +# Copyright 2019 The Matrix.org Foundation C.I.C. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -58,18 +59,41 @@ paths: format: byte responses: 200: - description: The MXC URI for the uploaded content. + description: The `MXC URI`_ for the uploaded content. schema: type: object required: ["content_uri"] properties: content_uri: type: string - description: "The MXC URI to the uploaded content." + description: "The `MXC URI`_ to the uploaded content." examples: application/json: { - "content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw" - } + "content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw" + } + 403: + description: |- + The user does not have permission to upload the content. Some reasons for this error include: + + - The server does not permit the file type. + - The user has reached a quota for uploaded content. + examples: + application/json: { + "errcode": "M_FORBIDDEN", + "error": "Cannot upload this content" + } + schema: + "$ref": "definitions/errors/error.yaml" + 413: + description: |- + The uploaded content is too large for the server. + examples: + application/json: { + "errcode": "M_TOO_LARGE", + "error": "Cannot upload files larger than 100mb" + } + schema: + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: @@ -114,10 +138,23 @@ paths: description: "The content type of the file that was previously uploaded." type: "string" Content-Disposition: - description: "The name of the file that was previously uploaded, if set." + description: |- + The name of the file that was previously uploaded, if set. type: "string" schema: type: file + # This is a workaround for us not being able to say the response is required. + description: "**Required.** The bytes for the uploaded file." + 502: + description: |- + The content is too large for the server to serve. + examples: + application/json: { + "errcode": "M_TOO_LARGE", + "error": "Content is too large to serve" + } + schema: + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: @@ -126,7 +163,9 @@ paths: - Media "/download/{serverName}/{mediaId}/{fileName}": get: - summary: "Download content from the content repository as a given filename." + summary: |- + Download content from the content repository. This is the same as + the download endpoint above, except permitting a desired file name. operationId: getContentOverrideName produces: ["*/*"] parameters: @@ -149,8 +188,7 @@ paths: name: fileName x-example: filename.jpg required: true - description: | - The filename to give in the Content-Disposition + description: A filename to give in the ``Content-Disposition`` header. - in: query type: boolean name: allow_remote @@ -169,10 +207,24 @@ paths: description: "The content type of the file that was previously uploaded." type: "string" Content-Disposition: - description: "The name of file given in the request" + description: |- + The ``fileName`` requested or the name of the file that was previously + uploaded, if set. type: "string" schema: type: file + # This is a workaround for us not being able to say the response is required. + description: "**Required.** The bytes for the uploaded file." + 502: + description: |- + The content is too large for the server to serve. + examples: + application/json: { + "errcode": "M_TOO_LARGE", + "error": "Content is too large to serve" + } + schema: + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: @@ -181,7 +233,9 @@ paths: - Media "/thumbnail/{serverName}/{mediaId}": get: - summary: "Download a thumbnail of the content from the content repository." + summary: |- + Download a thumbnail of content from the content repository. See the `thumbnailing <#thumbnails>`_ + section for more information. operationId: getContentThumbnail produces: ["image/jpeg", "image/png"] parameters: @@ -189,7 +243,7 @@ paths: type: string name: serverName required: true - x-example: matrix.org + x-example: example.org description: | The server name from the ``mxc://`` URI (the authoritory component) - in: path @@ -205,22 +259,24 @@ paths: name: width required: true description: |- - The *desired* width of the thumbnail. The actual thumbnail may not - match the size specified. + The *desired* width of the thumbnail. The actual thumbnail may be + larger than the size specified. - in: query type: integer x-example: 64 name: height required: true description: |- - The *desired* height of the thumbnail. The actual thumbnail may not - match the size specified. + The *desired* height of the thumbnail. The actual thumbnail may be + larger than the size specified. - in: query type: string enum: ["crop", "scale"] name: method x-example: "scale" - description: The desired resizing method. + description: |- + The desired resizing method. See the `thumbnailing <#thumbnails>`_ + section for more information. - in: query type: boolean name: allow_remote @@ -241,6 +297,40 @@ paths: enum: ["image/jpeg", "image/png"] schema: type: file + # This is a workaround for us not being able to say the response is required. + description: "**Required.** The bytes for the thumbnail." + 400: + description: |- + The request does not make sense to the server, or the server cannot thumbnail + the content. For example, the client requested non-integer dimensions or asked + for negatively-sized images. + examples: + application/json: { + "errcode": "M_UNKNOWN", + "error": "Cannot generate thumbnails for the requested content" + } + schema: + "$ref": "definitions/errors/error.yaml" + 413: + description: |- + The local content is too large for the server to thumbnail. + examples: + application/json: { + "errcode": "M_TOO_LARGE", + "error": "Content is too large to thumbnail" + } + schema: + "$ref": "definitions/errors/error.yaml" + 502: + description: |- + The remote content is too large for the server to thumbnail. + examples: + application/json: { + "errcode": "M_TOO_LARGE", + "error": "Content is too large to thumbnail" + } + schema: + "$ref": "definitions/errors/error.yaml" 429: description: This request was rate-limited. schema: @@ -259,7 +349,7 @@ paths: type: string x-example: "https://matrix.org" name: url - description: "The URL to get a preview of" + description: "The URL to get a preview of." required: true - in: query type: integer @@ -287,7 +377,7 @@ paths: "og:image": type: string description: |- - An MXC URI to the image. Omitted if there is no image. + An `MXC URI`_ to the image. Omitted if there is no image. examples: application/json: { "og:title": "Matrix Blog Post", diff --git a/api/client-server/room_state.yaml b/api/client-server/room_state.yaml index 37da0335..62168f26 100644 --- a/api/client-server/room_state.yaml +++ b/api/client-server/room_state.yaml @@ -75,7 +75,7 @@ paths: type: object example: { "membership": "join", - "avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF#auto", + "avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid" } responses: diff --git a/changelogs/client_server/newsfragments/2068.clarification b/changelogs/client_server/newsfragments/2068.clarification new file mode 100644 index 00000000..77ad7125 --- /dev/null +++ b/changelogs/client_server/newsfragments/2068.clarification @@ -0,0 +1 @@ +Clarify how the content repository works, and what it is used for. diff --git a/event-schemas/examples/m.room.member b/event-schemas/examples/m.room.member index b0aa59dd..18bc457b 100644 --- a/event-schemas/examples/m.room.member +++ b/event-schemas/examples/m.room.member @@ -4,7 +4,7 @@ "type": "m.room.member", "content": { "membership": "join", - "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF#auto", + "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid" } } diff --git a/event-schemas/examples/m.room.member$invite_room_state b/event-schemas/examples/m.room.member$invite_room_state index 2c93eb9b..54fcba60 100644 --- a/event-schemas/examples/m.room.member$invite_room_state +++ b/event-schemas/examples/m.room.member$invite_room_state @@ -2,7 +2,7 @@ "$ref": "m.room.member", "content": { "membership": "invite", - "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF#auto", + "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid" }, "unsigned": { diff --git a/event-schemas/examples/m.room.member$third_party_invite b/event-schemas/examples/m.room.member$third_party_invite index c688a283..a40d44f9 100644 --- a/event-schemas/examples/m.room.member$third_party_invite +++ b/event-schemas/examples/m.room.member$third_party_invite @@ -2,7 +2,7 @@ "$ref": "m.room.member", "content": { "membership": "invite", - "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF#auto", + "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", "displayname": "Alice Margatroid", "third_party_invite": { "display_name": "alice", diff --git a/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml b/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml index 8ff27b1e..ff40efcb 100644 --- a/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml +++ b/event-schemas/schema/core-event-schema/msgtype_infos/image_info.yaml @@ -19,8 +19,8 @@ properties: type: integer thumbnail_url: description: |- - The URL to a thumbnail of the image. Only present if the - thumbnail is unencrypted. + The URL (typically `MXC URI`_) to a thumbnail of the image. + Only present if the thumbnail is unencrypted. type: string thumbnail_file: description: |- diff --git a/event-schemas/schema/m.room.message$m.audio b/event-schemas/schema/m.room.message$m.audio index 99e28110..88b459ec 100644 --- a/event-schemas/schema/m.room.message$m.audio +++ b/event-schemas/schema/m.room.message$m.audio @@ -27,7 +27,9 @@ properties: - m.audio type: string url: - description: Required if the file is not encrypted. The URL to the audio clip. + description: |- + Required if the file is not encrypted. The URL (typically `MXC URI`_) + to the audio clip. type: string file: description: |- diff --git a/event-schemas/schema/m.room.message$m.file b/event-schemas/schema/m.room.message$m.file index 2389d8a9..9f4fdf07 100644 --- a/event-schemas/schema/m.room.message$m.file +++ b/event-schemas/schema/m.room.message$m.file @@ -42,7 +42,9 @@ properties: - m.file type: string url: - description: Required if the file is unencrypted. The URL to the file. + description: |- + Required if the file is unencrypted. The URL (typically `MXC URI`_) + to the file. type: string file: description: |- diff --git a/event-schemas/schema/m.room.message$m.image b/event-schemas/schema/m.room.message$m.image index 1e6ebeaa..a466562a 100644 --- a/event-schemas/schema/m.room.message$m.image +++ b/event-schemas/schema/m.room.message$m.image @@ -17,7 +17,9 @@ properties: - m.image type: string url: - description: Required if the file is unencrypted. The URL to the image. + description: |- + Required if the file is unencrypted. The URL (typically `MXC URI`_) + to the image. type: string file: description: |- diff --git a/event-schemas/schema/m.room.message$m.video b/event-schemas/schema/m.room.message$m.video index 2da7e0bc..b23c2392 100644 --- a/event-schemas/schema/m.room.message$m.video +++ b/event-schemas/schema/m.room.message$m.video @@ -28,8 +28,8 @@ properties: type: integer thumbnail_url: description: |- - The URL to an image thumbnail of the video clip. Only present if the - thumbnail is unencrypted. + The URL (typically `MXC URI`_) to an image thumbnail of + the video clip. Only present if the thumbnail is unencrypted. type: string thumbnail_file: description: |- @@ -48,7 +48,9 @@ properties: - m.video type: string url: - description: Required if the file is unencrypted. The URL to the video clip. + description: |- + Required if the file is unencrypted. The URL (typically `MXC URI`_) + to the video clip. type: string file: description: |- diff --git a/specification/modules/content_repo.rst b/specification/modules/content_repo.rst index e7bdb044..1e3d1866 100644 --- a/specification/modules/content_repo.rst +++ b/specification/modules/content_repo.rst @@ -1,4 +1,5 @@ .. Copyright 2016 OpenMarket Ltd +.. Copyright 2019 The Matrix.org Foundation C.I.C. .. .. Licensed under the Apache License, Version 2.0 (the "License"); .. you may not use this file except in compliance with the License. @@ -17,27 +18,36 @@ Content repository .. _module:content: -This module allows users to upload content to their homeserver which is -retrievable from other homeservers. Its' purpose is to allow users to share -attachments in a room. Content locations are represented as Matrix Content (MXC) -URIs. They look like:: +The content repository (or "media repository") allows users to upload +files to their homeserver for later user. For example, files which the +user wants to send to a room would be uploaded here, as would an avatar +the user wants to use. - mxc:/// - - : The name of the homeserver where this content originated, e.g. matrix.org - : An opaque ID which identifies the content. - -Uploads are POSTed to a resource on the user's local homeserver which returns a -token which is used to GET the download. Content is downloaded from the -recipient's local homeserver, which must first transfer the content from the -origin homeserver using the same API (unless the origin and destination -homeservers are the same). +Uploads are POSTed to a resource on the user's local homeserver which +returns a MXC URI which can later be used to GET the download. Content +is downloaded from the recipient's local homeserver, which must first +transfer the content from the origin homeserver using the same API +(unless the origin and destination homeservers are the same). When serving content, the server SHOULD provide a ``Content-Security-Policy`` header. The recommended policy is ``sandbox; default-src 'none'; script-src 'none'; plugin-types application/pdf; style-src 'unsafe-inline'; object-src 'self';``. +Matrix Content (MXC) URIs +------------------------- + +.. _`MXC URI`: + +Content locations are represented as Matrix Content (MXC) URIs. They look +like:: + + mxc:/// + + : The name of the homeserver where this content originated, e.g. matrix.org + : An opaque ID which identifies the content. + + Client behaviour ---------------- @@ -47,6 +57,11 @@ Clients can upload and download content using the following HTTP APIs. Thumbnails ~~~~~~~~~~ +The homeserver SHOULD be able to supply thumbnails for uploaded images and +videos. The exact file types which can be thumbnailed are not currently +specified - see `Issue #1938 `_ +for more information. + The thumbnail methods are "crop" and "scale". "scale" tries to return an image where either the width or the height is smaller than the requested size. The client should then scale and letterbox the image if it needs to @@ -55,18 +70,29 @@ width and height are close to the requested size and the aspect matches the requested size. The client should scale the image if it needs to fit within a given rectangle. +The dimensions given to the thumbnail API are the minimum size the client +would prefer. Servers must never return thumbnails smaller than the client's +requested dimensions, unless the content being thumbnailed is smaller than +the dimensions. When the content is smaller than the requested dimensions, +servers should return the original content rather than thumbnail it. + +Servers SHOULD produce thumbnails with the following dimensions and methods: + +* 32x32, crop +* 96x96, crop +* 320x240, scale +* 640x480, scale +* 800x600, scale + In summary: * "scale" maintains the original aspect ratio of the image * "crop" provides an image in the aspect ratio of the sizes given in the request + * The server will return an image larger than or equal to the dimensions requested + where possible. -Server behaviour ----------------- - -Homeservers may generate thumbnails for content uploaded to remote -homeservers themselves or may rely on the remote homeserver to thumbnail -the content. Homeservers may return thumbnails of a different size to that -requested. However homeservers should provide exact matches where reasonable. -Homeservers must never upscale images. +Servers MUST NOT upscale thumbnails under any circumstance. Servers MUST NOT +return a smaller thumbnail than requested, unless the original content makes +that impossible. Security considerations ----------------------- @@ -88,16 +114,20 @@ UTF-8 encoded traversals, etc). Homeservers have additional content-specific concerns: - Clients may try to upload very large files. Homeservers should not store files - that are too large and should not serve them to clients. + that are too large and should not serve them to clients, returning a HTTP 413 + error with the ``M_TOO_LARGE`` code. - Clients may try to upload very large images. Homeservers should not attempt to - generate thumbnails for images that are too large. + generate thumbnails for images that are too large, returning a HTTP 413 error + with the ``M_TOO_LARGE`` code. - Remote homeservers may host very large files or images. Homeservers should not - proxy or thumbnail large files or images from remote homeservers. + proxy or thumbnail large files or images from remote homeservers, returning a + HTTP 502 error with the ``M_TOO_LARGE`` code. - Clients may try to upload a large number of files. Homeservers should limit the - number and total size of media that can be uploaded by clients. + number and total size of media that can be uploaded by clients, returning a + HTTP 403 error with the ``M_FORBIDDEN`` code. - Clients may try to access a large number of remote files through a homeserver. Homeservers should restrict the number and size of remote files that it caches.