Skip to content

Commit 283c587

Browse files
authored
Spec asynchronous uploads (#1499)
Spec for matrix-org/matrix-spec-proposals#2246
1 parent 6150f71 commit 283c587

File tree

3 files changed

+262
-21
lines changed

3 files changed

+262
-21
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add new endpoints `POST /_matrix/media/v1/create` and `PUT /_matrix/media/v3/upload/{serverName}/{mediaId}`, and other changes for asynchronous media upload, as per [MSC2246](https://github.com/matrix-org/matrix-spec-proposals/pull/2246).
2+

content/client-server-api/_index.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@ recommended outside test environments.
2222
Clients are authenticated using opaque `access_token` strings (see [Client
2323
Authentication](#client-authentication) for details).
2424

25-
All `POST` and `PUT` endpoints, with the exception of
26-
[`POST /_matrix/media/v3/upload`](#post_matrixmediav3upload), require the
27-
client to supply a request body containing a (potentially empty) JSON object.
28-
Clients should supply a `Content-Type` header of `application/json` for all requests with JSON bodies,
29-
but this is not required.
25+
All `POST` and `PUT` endpoints, with the exception of [`POST
26+
/_matrix/media/v3/upload`](#post_matrixmediav3upload) and [`PUT
27+
/_matrix/media/v3/upload/{serverName}/{mediaId}`](http://localhost:1313/client-server-api/#put_matrixmediav3uploadservernamemediaid),
28+
require the client to supply a request body containing a (potentially empty)
29+
JSON object. Clients should supply a `Content-Type` header of
30+
`application/json` for all requests with JSON bodies, but this is not required.
3031

3132
Similarly, all endpoints require the server to return a JSON object,
3233
with the exception of 200 responses to

data/api/client-server/content-repo.yaml

Lines changed: 254 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ host: localhost:8008
2020
schemes:
2121
- https
2222
- http
23-
basePath: /_matrix/media/v3
23+
basePath: /_matrix
2424
consumes:
2525
- application/json
2626
- "*/*"
@@ -30,7 +30,7 @@ produces:
3030
securityDefinitions:
3131
$ref: definitions/security.yaml
3232
paths:
33-
"/upload":
33+
"/media/v3/upload":
3434
post:
3535
summary: Upload some content to the content repository.
3636
operationId: uploadContent
@@ -101,7 +101,170 @@ paths:
101101
"$ref": "definitions/errors/rate_limited.yaml"
102102
tags:
103103
- Media
104-
"/download/{serverName}/{mediaId}":
104+
"/media/v3/upload/{serverName}/{mediaId}":
105+
put:
106+
summary: Upload content to an `mxc://` URI that was created earlier.
107+
description: |-
108+
This endpoint permits uploading content to an `mxc://` URI that was created
109+
earlier via [POST /_matrix/media/v1/create](/client-server-api/#post_matrixmediav1create).
110+
operationId: uploadContentToMXC
111+
x-addedInMatrixVersion: "1.7"
112+
parameters:
113+
- in: path
114+
type: string
115+
name: serverName
116+
x-example: matrix.org
117+
required: true
118+
description: |
119+
The server name from the `mxc://` URI returned by `POST /_matrix/media/v1/create` (the authoritory component).
120+
- in: path
121+
type: string
122+
name: mediaId
123+
x-example: ascERGshawAWawugaAcauga
124+
required: true
125+
description: |
126+
The media ID from the `mxc://` URI returned by `POST /_matrix/media/v1/create` (the path component).
127+
- in: header
128+
name: Content-Type
129+
type: string
130+
description: The content type of the file being uploaded
131+
x-example: "application/pdf"
132+
- in: query
133+
type: string
134+
x-example: "War and Peace.pdf"
135+
name: filename
136+
description: The name of the file being uploaded
137+
- in: body
138+
name: "content"
139+
description: The content to be uploaded.
140+
required: true
141+
x-example: "<bytes>" # so the spec shows "<bytes>" without quotes.
142+
schema:
143+
type: string
144+
example: "<bytes>"
145+
format: byte
146+
responses:
147+
200:
148+
description: The upload was successful.
149+
schema:
150+
type: object
151+
examples:
152+
application/json: {}
153+
403:
154+
description: |-
155+
The user does not have permission to upload the content. Some reasons for this error include:
156+
157+
- The server does not permit the file type.
158+
- The user has reached a quota for uploaded content.
159+
- The request comes from a different user than the one that called
160+
[POST /_matrix/media/v1/create](/client-server-api/#post_matrixmediav1create).
161+
162+
A [standard error response](/client-server-api/#standard-error-response)
163+
will be returned with the `errcode` `M_FORBIDDEN`.
164+
examples:
165+
application/json: {
166+
"errcode": "M_FORBIDDEN",
167+
"error": "Cannot upload this content"
168+
}
169+
schema:
170+
"$ref": "definitions/errors/error.yaml"
171+
409:
172+
description: |-
173+
The endpoint was called with a media ID that already has content. A
174+
[standard error response](/client-server-api/#standard-error-response)
175+
will be returned with the `errcode` `M_CANNOT_OVERWRITE_MEDIA`.
176+
examples:
177+
application/json: {
178+
"errcode": "M_CANNOT_OVERWRITE_MEDIA",
179+
"error": "Media already uploaded"
180+
}
181+
schema:
182+
"$ref": "definitions/errors/error.yaml"
183+
413:
184+
description: |-
185+
The uploaded content is too large for the server.
186+
examples:
187+
application/json: {
188+
"errcode": "M_TOO_LARGE",
189+
"error": "Cannot upload files larger than 100mb"
190+
}
191+
schema:
192+
"$ref": "definitions/errors/error.yaml"
193+
429:
194+
description: This request was rate-limited.
195+
schema:
196+
"$ref": "definitions/errors/rate_limited.yaml"
197+
tags:
198+
- Media
199+
"/media/v1/create":
200+
post:
201+
summary: Create a new `mxc://` URI without uploading the content.
202+
description: |-
203+
Creates a new `mxc://` URI, independently of the content being uploaded. The content must be provided later
204+
via [`PUT /_matrix/media/v3/upload/{serverName}/{mediaId}`](http://localhost:1313/client-server-api/#put_matrixmediav3uploadservernamemediaid).
205+
206+
The server may optionally enforce a maximum age for unused IDs,
207+
and delete media IDs when the client doesn't start the upload in time,
208+
or when the upload was interrupted and not resumed in time. The server
209+
should include the maximum POSIX millisecond timestamp to complete the
210+
upload in the `unused_expires_at` field in the response JSON. The
211+
recommended default expiration is 24 hours which should be enough time
212+
to accommodate users on poor connection who find a better connection to
213+
complete the upload.
214+
215+
As well as limiting the rate of requests to create `mxc://` URIs, the server
216+
should limit the number of concurrent *pending media uploads* a given
217+
user can have. A pending media upload is a created `mxc://` URI where (a)
218+
the media has not yet been uploaded, and (b) has not yet expired (the
219+
`unused_expires_at` timestamp has not yet passed). In both cases, the
220+
server should respond with an HTTP 429 error with an errcode of
221+
`M_LIMIT_EXCEEDED`.
222+
operationId: createContent
223+
consumes: ["application/json"]
224+
produces: ["application/json"]
225+
x-addedInMatrixVersion: "1.7"
226+
security:
227+
- accessToken: []
228+
# empty json object
229+
parameters: []
230+
responses:
231+
200:
232+
description: The [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris) for the uploaded content.
233+
schema:
234+
type: object
235+
required: ["content_uri"]
236+
properties:
237+
content_uri:
238+
type: string
239+
format: uri
240+
description: |-
241+
The [`mxc://` URI](/client-server-api/#matrix-content-mxc-uris) at
242+
which the content will be available, once it is uploaded.
243+
example: "mxc://example.com/AQwafuaFswefuhsfAFAgsw"
244+
unused_expires_at:
245+
type: integer
246+
format: int64
247+
description: |-
248+
The timestamp (in milliseconds since the unix epoch) when the
249+
generated media id will expire, if media is not uploaded.
250+
example: 1647257217083
251+
403:
252+
description: |-
253+
The user does not have permission to upload the content.
254+
examples:
255+
application/json: {
256+
"errcode": "M_FORBIDDEN",
257+
"error": "Cannot upload this content"
258+
}
259+
schema:
260+
"$ref": "definitions/errors/error.yaml"
261+
429:
262+
description: This request was rate-limited.
263+
schema:
264+
"$ref": "definitions/errors/rate_limited.yaml"
265+
tags:
266+
- Media
267+
"/media/v3/download/{serverName}/{mediaId}":
105268
get:
106269
summary: "Download content from the content repository."
107270
operationId: getContent
@@ -131,6 +294,20 @@ paths:
131294
Indicates to the server that it should not attempt to fetch the media if it is deemed
132295
remote. This is to prevent routing loops where the server contacts itself. Defaults to
133296
true if not provided.
297+
- in: query
298+
type: integer
299+
format: int64
300+
name: timeout_ms
301+
x-example: 5000
302+
x-addedInMatrixVersion: "1.7"
303+
default: 20000
304+
description: |
305+
The maximum number of milliseconds that the client is willing to
306+
wait to start receiving data, in the case that the content has not
307+
yet been uploaded. The default value is 20000 (20 seconds). The
308+
content repository can and should impose a maximum value for this
309+
parameter. The content repository may also choose to respond before
310+
the timeout.
134311
responses:
135312
200:
136313
description: "The content that was previously uploaded."
@@ -146,6 +323,10 @@ paths:
146323
type: file
147324
# This is a workaround for us not being able to say the response is required.
148325
description: "**Required.** The bytes for the uploaded file."
326+
429:
327+
description: This request was rate-limited.
328+
schema:
329+
"$ref": "definitions/errors/rate_limited.yaml"
149330
502:
150331
description: |-
151332
The content is too large for the server to serve.
@@ -156,13 +337,20 @@ paths:
156337
}
157338
schema:
158339
"$ref": "definitions/errors/error.yaml"
159-
429:
160-
description: This request was rate-limited.
340+
504:
341+
description: |-
342+
The content is not yet available. A [standard error response](/client-server-api/#standard-error-response)
343+
will be returned with the `errcode` `M_NOT_YET_UPLOADED`.
344+
examples:
345+
application/json: {
346+
"errcode": "M_NOT_YET_UPLOADED",
347+
"error": "Content has not yet been uploaded"
348+
}
161349
schema:
162-
"$ref": "definitions/errors/rate_limited.yaml"
350+
"$ref": "definitions/errors/error.yaml"
163351
tags:
164352
- Media
165-
"/download/{serverName}/{mediaId}/{fileName}":
353+
"/media/v3/download/{serverName}/{mediaId}/{fileName}":
166354
get:
167355
summary: Download content from the content repository overriding the file name
168356
description: |-
@@ -202,6 +390,20 @@ paths:
202390
Indicates to the server that it should not attempt to fetch the media if it is deemed
203391
remote. This is to prevent routing loops where the server contacts itself. Defaults to
204392
true if not provided.
393+
- in: query
394+
type: integer
395+
format: int64
396+
name: timeout_ms
397+
x-example: 5000
398+
x-addedInMatrixVersion: "1.7"
399+
default: 20000
400+
description: |
401+
The maximum number of milliseconds that the client is willing to
402+
wait to start receiving data, in the case that the content has not
403+
yet been uploaded. The default value is 20000 (20 seconds). The
404+
content repository can and should impose a maximum value for this
405+
parameter. The content repository may also choose to respond before
406+
the timeout.
205407
responses:
206408
200:
207409
description: "The content that was previously uploaded."
@@ -218,6 +420,10 @@ paths:
218420
type: file
219421
# This is a workaround for us not being able to say the response is required.
220422
description: "**Required.** The bytes for the uploaded file."
423+
429:
424+
description: This request was rate-limited.
425+
schema:
426+
"$ref": "definitions/errors/rate_limited.yaml"
221427
502:
222428
description: |-
223429
The content is too large for the server to serve.
@@ -228,13 +434,20 @@ paths:
228434
}
229435
schema:
230436
"$ref": "definitions/errors/error.yaml"
231-
429:
232-
description: This request was rate-limited.
437+
504:
438+
description: |-
439+
The content is not yet available. A [standard error response](/client-server-api/#standard-error-response)
440+
will be returned with the `errcode` `M_NOT_YET_UPLOADED`.
441+
examples:
442+
application/json: {
443+
"errcode": "M_NOT_YET_UPLOADED",
444+
"error": "Content has not yet been uploaded"
445+
}
233446
schema:
234-
"$ref": "definitions/errors/rate_limited.yaml"
447+
"$ref": "definitions/errors/error.yaml"
235448
tags:
236449
- Media
237-
"/thumbnail/{serverName}/{mediaId}":
450+
"/media/v3/thumbnail/{serverName}/{mediaId}":
238451
get:
239452
summary: Download a thumbnail of content from the content repository
240453
description: |-
@@ -291,6 +504,20 @@ paths:
291504
Indicates to the server that it should not attempt to fetch
292505
the media if it is deemed remote. This is to prevent routing loops
293506
where the server contacts itself. Defaults to true if not provided.
507+
- in: query
508+
type: integer
509+
format: int64
510+
name: timeout_ms
511+
x-example: 5000
512+
x-addedInMatrixVersion: "1.7"
513+
default: 20000
514+
description: |
515+
The maximum number of milliseconds that the client is willing to
516+
wait to start receiving data, in the case that the content has not
517+
yet been uploaded. The default value is 20000 (20 seconds). The
518+
content repository can and should impose a maximum value for this
519+
parameter. The content repository may also choose to respond before
520+
the timeout.
294521
responses:
295522
200:
296523
description: "A thumbnail of the requested content."
@@ -325,6 +552,10 @@ paths:
325552
}
326553
schema:
327554
"$ref": "definitions/errors/error.yaml"
555+
429:
556+
description: This request was rate-limited.
557+
schema:
558+
"$ref": "definitions/errors/rate_limited.yaml"
328559
502:
329560
description: |-
330561
The remote content is too large for the server to thumbnail.
@@ -335,13 +566,20 @@ paths:
335566
}
336567
schema:
337568
"$ref": "definitions/errors/error.yaml"
338-
429:
339-
description: This request was rate-limited.
569+
504:
570+
description: |-
571+
The content is not yet available. A [standard error response](/client-server-api/#standard-error-response)
572+
will be returned with the `errcode` `M_NOT_YET_UPLOADED`.
573+
examples:
574+
application/json: {
575+
"errcode": "M_NOT_YET_UPLOADED",
576+
"error": "Content has not yet been uploaded"
577+
}
340578
schema:
341-
"$ref": "definitions/errors/rate_limited.yaml"
579+
"$ref": "definitions/errors/error.yaml"
342580
tags:
343581
- Media
344-
"/preview_url":
582+
"/media/v3/preview_url":
345583
get:
346584
summary: "Get information about a URL for a client"
347585
description: |-
@@ -410,7 +648,7 @@ paths:
410648
"$ref": "definitions/errors/rate_limited.yaml"
411649
tags:
412650
- Media
413-
"/config":
651+
"/media/v3/config":
414652
get:
415653
summary: Get the configuration for the content repository.
416654
description: |-

0 commit comments

Comments
 (0)