TUS resumable upload#
plone.restapi
supports the TUS Open Protocol for resumable file uploads.
There is a @tus-upload
endpoint to upload a file, and a @tus-replace
endpoint to replace an existing file.
Creating an Upload URL#
Note
POST
requests to the @tus-upload
endpoint are allowed on all IFolderish
content types, for example, Folder
.
To create a new upload, send a POST
request to the @tus-upload
endpoint:
POST /plone/folder/@tus-upload HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Tus-Resumable: 1.0.0
Upload-Length: 8
Upload-Metadata: filename dGVzdC50eHQ=,content-type dGV4dC9wbGFpbg==
curl -i -X POST http://nohost/plone/folder/@tus-upload -H "Accept: application/json" -H "Tus-Resumable: 1.0.0" -H "Upload-Length: 8" -H "Upload-Metadata: filename dGVzdC50eHQ=,content-type dGV4dC9wbGFpbg==" --user admin:secret
http POST http://nohost/plone/folder/@tus-upload Accept:application/json Tus-Resumable:1.0.0 Upload-Length:8 Upload-Metadata:"filename dGVzdC50eHQ=,content-type dGV4dC9wbGFpbg==" -a admin:secret
requests.post('http://nohost/plone/folder/@tus-upload', headers={'Accept': 'application/json', 'Tus-Resumable': '1.0.0', 'Upload-Length': '8', 'Upload-Metadata': 'filename dGVzdC50eHQ=,content-type dGV4dC9wbGFpbg=='}, auth=('admin', 'secret'))
The server will return a temporary upload URL in the Location
header of the response:
HTTP/1.1 201 Created
Location: http://localhost:55001/plone/folder/@tus-upload/032803b64ad746b3ab46d9223ea3d90f
Tus-Resumable: 1.0.0
The file can then be uploaded in the next step to that temporary URL.
Uploading a File#
Note
PATCH requests to the @tus-upload
endpoint are allowed on all IContentish content types.
Once a temporary upload URL has been created, a client can send a PATCH
request to upload a file.
The file content should be sent in the body of the request:
PATCH /plone/folder/@tus-upload/032803b64ad746b3ab46d9223ea3d90f HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Tus-Resumable: 1.0.0
Upload-Offset: 3
Content-Type: application/offset+octet-stream
defgh
When just a single file is uploaded at once, the server will respond with a 204 No Content response after a successful upload.
The HTTP Location
header contains he URL of the newly created content object:
HTTP/1.1 204 No Content
Location: http://localhost:55001/plone/folder/document-2016-10-21
Tus-Resumable: 1.0.0
Upload-Offset: 8
Partial Upload#
TUS allows partial upload of files.
A partial file is also uploaded by sending a PATCH
request to the temporary URL:
PATCH /plone/folder/@tus-upload/032803b64ad746b3ab46d9223ea3d90f HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Tus-Resumable: 1.0.0
Upload-Offset: 0
Content-Type: application/offset+octet-stream
abc
The server will also respond with a 204 No content response.
Though instead of providing the final file URL in the Location
header, the server provides an updated Upload-Offset
value, telling the client the new offset:
HTTP/1.1 204 No Content
Tus-Resumable: 1.0.0
Upload-Offset: 3
When the last partial file has been uploaded, the server will contain the final file URL in the Location
header.
Replacing Existing Files#
TUS can also be used to replace an existing file by sending a POST
request to the @tus-replace
endpoint instead:
POST /plone/myfile/@tus-replace HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Tus-Resumable: 1.0.0
Upload-Length: 8
Upload-Metadata: filename dGVzdC50eHQ=,content-type dGV4dC9wbGFpbg==
The server will respond with a 201 Created status and return the URL of the temporarily created upload resource in the Location
header of the response:
HTTP/1.1 201 Created
Location: http://localhost:55001/plone/folder/@tus-upload/032803b64ad746b3ab46d9223ea3d90f
Tus-Resumable: 1.0.0
The file can then be uploaded to that URL using the PATCH
method in the same way as creating a new file:
PATCH /plone/myfile/@tus-upload/4e465958b24a46ec8657e6f3be720991 HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Tus-Resumable: 1.0.0
Upload-Offset: 0
Content-Type: application/offset+octet-stream
abcdefgh
The server will respond with a 204 No Content response and the final file URL in the HTTP Location
header:
HTTP/1.1 204 No Content
Location: http://localhost:55001/plone/myfile
Tus-Resumable: 1.0.0
Upload-Offset: 8
Asking for the Current File Offset#
To ask the server for the current file offset, the client can send a HEAD
request to the upload URL:
HEAD /plone/folder/@tus-upload/032803b64ad746b3ab46d9223ea3d90f HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Tus-Resumable: 1.0.0
curl -i -X HEAD http://nohost/plone/folder/@tus-upload/032803b64ad746b3ab46d9223ea3d90f -H "Accept: application/json" -H "Tus-Resumable: 1.0.0" --user admin:secret
http HEAD http://nohost/plone/folder/@tus-upload/032803b64ad746b3ab46d9223ea3d90f Accept:application/json Tus-Resumable:1.0.0 -a admin:secret
requests.head('http://nohost/plone/folder/@tus-upload/032803b64ad746b3ab46d9223ea3d90f', headers={'Accept': 'application/json', 'Tus-Resumable': '1.0.0'}, auth=('admin', 'secret'))
The server will respond with a 200 OK status and the current file offset in the Upload-Offset
header:
HTTP/1.1 200 OK
Tus-Resumable: 1.0.0
Upload-Length: 8
Upload-Offset: 3
Configuration and Options#
The current TUS configuration and a list of supported options can be retrieved sending an OPTIONS
request to the @tus-upload
endpoint:
OPTIONS /plone/folder/@tus-upload HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
curl -i -X OPTIONS http://nohost/plone/folder/@tus-upload -H "Accept: application/json" --user admin:secret
http OPTIONS http://nohost/plone/folder/@tus-upload Accept:application/json -a admin:secret
requests.options('http://nohost/plone/folder/@tus-upload', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
The server will respond with a 204 No content status and HTTP headers containing information about the available extensions and the TUS version:
HTTP/1.1 204 No Content
Tus-Extension: creation,expiration
Tus-Resumable: 1.0.0
Tus-Version: 1.0.0
CORS Configuration#
If you use CORS and want to make it work with TUS, you have to make sure the TUS-specific HTTP headers are allowed by your CORS policy:
<plone:CORSPolicy
allow_origin="http://localhost"
allow_methods="DELETE,GET,OPTIONS,PATCH,POST,PUT"
allow_credentials="true"
allow_headers="Accept,Authorization,Origin,X-Requested-With,Content-Type,Upload-Length,Upload-Offset,Tus-Resumable,Upload-Metadata,Lock-Token"
expose_headers="Upload-Offset,Location,Upload-Length,Tus-Version,Tus-Resumable,Tus-Max-Size,Tus-Extension,Upload-Metadata"
max_age="3600"
/>
See the plone.rest
documentation for more information on how to configure CORS policies.
See https://tus.io/protocols/resumable-upload.html#headers for a list and description of the individual headers.
Temporary Upload Directory#
During upload, files are stored in a temporary directory that by default is located in the CLIENT_HOME
directory.
If you are using a multi ZEO client setup without session stickiness you must configure this to a directory shared by all ZEO clients by setting the TUS_TMP_FILE_DIR
environment variable, for example TUS_TMP_FILE_DIR=/tmp/tus-uploads
.