版本: 1.0.0 (SemVer)
日期: 2016年3月25日
作者: Felix Geisendörfer, Kevin van Zonneveld, Tim Koschützki, Naren Venkataraman, Marius Kleidl
贡献者:
Bruno de Carvalho,
James Butler,
Øystein Steimler,
Sam Rijs,
Khang Toh,
Jacques Boscq,
Jérémy FRERE,
Pieter Hintjens,
Stephan Seidt,
Aran Wilkinson,
Svein Ove Aas,
Oliver Anan,
Tim,
j4james,
Julian Reschke,
Evert Pot,
Jochen Kupperschmidt,
Andrew Fenn,
Kevin Swiber,
Jan Kohlhof,
eno,
Luke Arduini,
Jim Schmid,
Jeffrey 'jf' Lim,
Daniel Lopretto,
Mark Murphy,
Peter Darrow,
Gargaj,
Tomasz Rydzyński,
Tino de Bruijn,
Jonas mg,
Christian Ulbrich,
Jon Gjengset,
Michael Elovskikh,
Rick Olson,
J. Ryan Stinnett,
Ifedapo Olarewaju,
Robert Nagy
文档中的关键词必须(MUST)、不得(MUST NOT)、需要(REQUIRED)、应(SHALL)、不应(SHALL NOT)、应该(SHOULD)、不应该(SHOULD NOT)、推荐(RECOMMENDED)、可以(MAY)和可选(OPTIONAL)应按照RFC 2119进行解释。
根据SemVer,1.0.0版本表示tus协议已可用于生产环境。我们预计不会做破坏性变更,如有必要将在2.0.0版本进行。新增扩展或向后兼容的功能更新将提升MINOR版本号。
本协议由tus社区维护,欢迎通过GitHub提交修改建议。所有贡献者将列于协议头部。
请通过此链接告知您的实现方案(开源或商业),我们将在实现方案页面列出。
本协议通过HTTP/1.1(RFC 7230)和HTTP/2(RFC 7540)提供可恢复文件上传机制。
方括号中的字符表示占位符(如[size])。
术语space、comma和semicolon指其ASCII字符。
核心协议描述如何恢复中断的上传。通常通过创建扩展生成上传URL后使用。
所有客户端和服务端必须(MUST)实现核心协议。
本规范不规定URL结构,由具体实现决定。文档中所有URL均为示例。
认证和授权机制由服务端实现。
HEAD 请求用于确定应从哪个偏移量继续上传。
下面的示例显示了一个 100 字节上传的中断后的继续,该中断发生在传输了 70 字节之后。
请求:
HEAD /files/24e533e02ec3bc40c387f1a0e460e216 HTTP/1.1
Host: tus.example.org
Tus-Resumable: 1.0.0
响应:
HTTP/1.1 200 OK
Upload-Offset: 70
Tus-Resumable: 1.0.0
给定偏移量,客户端使用 PATCH 方法来恢复上传:
请求:
PATCH /files/24e533e02ec3bc40c387f1a0e460e216 HTTP/1.1
Host: tus.example.org
Content-Type: application/offset+octet-stream
Content-Length: 30
Upload-Offset: 70
Tus-Resumable: 1.0.0
[剩余30字节]
响应:
HTTP/1.1 204 No Content
Tus-Resumable: 1.0.0
Upload-Offset: 100
Upload-Offset 请求和响应头部指示资源中的字节偏移量。该值必须(MUST)是一个非负整数。
Upload-Length 请求和响应头部指示整个上传的大小(以字节为单位)。该值必须(MUST)是一个非负整数。
Tus-Version 响应头部必须(MUST)是由服务器支持的协议版本组成的逗号分隔列表。该列表必须(MUST)按照服务器的偏好排序,其中第一个是最优选的版本。
Tus-Resumable头部必须(MUST)包含在所有请求和响应中(OPTIONS请求除外),其值必须(MUST)为客户端或服务端使用的协议版本。
如果服务端不支持客户端指定的版本,必须(MUST)返回412 Precondition Failed状态码,并必须(MUST)在响应中包含Tus-Version头部。
此外,服务端不得(MUST NOT)处理该请求。
Tus-Extension响应头部必须(MUST)为服务端支持的扩展列表(逗号分隔)。若无支持的扩展,必须(MUST)省略该头部。
Tus-Max-Size响应头部必须(MUST)为非负整数,表示允许的最大上传字节数。若存在已知硬性限制,服务端应该(SHOULD)设置该头部。
X-HTTP-Method-Override请求头部必须(MUST)为字符串,若存在则该值必须(MUST)被服务端解释为请求方法,实际请求方法必须(MUST)被忽略。当客户端环境不支持PATCH或DELETE方法时,应该(SHOULD)使用此头部。
服务器必须(MUST)始终在 HEAD 请求的响应中包含 Upload-Offset 头部,即使偏移量为 0,或者上传已经被认为是已完成的。如果上传的大小已知,服务器必须(MUST)在响应中包含 Upload-Length 头部。如果未找到资源,服务器应该(SHOULD)返回 404 Not Found、410 Gone 或 403 Forbidden 状态,而不包含 Upload-Offset 头部。
服务器应该(SHOULD)使用 200 OK 或 204 No Content 状态确认成功的 HEAD 请求。
服务器必须(MUST)将 Cache-Control: no-store 头部添加到响应中,来阻止客户端和/或代理缓存响应。
服务器应该(SHOULD)接受针对任何上传 URL 的 PATCH 请求,并将消息中包含的字节应用到由 Upload-Offset 头部指定的给定偏移量。所有 PATCH 请求必须(MUST)使用 Content-Type: application/offset+octet-stream,否则服务器应该(SHOULD)返回 415 Unsupported Media Type 状态。
Upload-Offset 头部的值必须(MUST)等于资源的当前偏移量。为了实现并行上传,可以(MAY)使用连接扩展。如果偏移量不匹配,服务器必须(MUST)以 409 Conflict 状态响应,而不修改上传资源。
客户端应该(SHOULD)在单个 PATCH 请求中发送上传的所有剩余字节,但可以(MAY)为了某些需要的场景,连续使用多个小请求。这些情况的一个例子是当使用Checksum扩展时。
服务器必须(MUST)使用 204 No Content 状态确认成功的 PATCH 请求。它必须(MUST)包含 Upload-Offset 头部,其中包含新的偏移量。新的偏移量必须(MUST)是 PATCH 请求之前的偏移量与当前 PATCH 请求期间接收、处理或存储的字节数之和。
如果服务器收到针对不存在资源的 PATCH 请求,它应该(SHOULD)返回 404 Not Found 状态。
客户端和服务器都应该(SHOULD)尝试以可预测的方式检测和处理网络错误。它们可以(MAY)通过检查读/写套接字错误以及设置读/写超时来实现。超时应该(SHOULD)通过关闭底层连接来处理。
服务器应该(SHOULD)始终尝试存储尽可能多的接收数据。
一个 OPTIONS 请求可以(MAY)用于收集关于服务器当前配置的信息。一个成功的响应,由 204 No Content 或 200 OK 状态指示,必须(MUST)包含 Tus-Version 头部。它可以(MAY)包含 Tus-Extension 和 Tus-Max-Size 头部。
客户端不应该(SHOULD NOT)在请求中包含 Tus-Resumable 头部,服务器必须(MUST)忽略该头部。
此示例阐明了 OPTIONS 请求的响应。响应中使用的版本是 1.0.0,而服务器也能够处理 0.2.2 和 0.2.1。允许总大小高达 1GB 的上传,并且启用了创建和过期扩展。
请求:
OPTIONS /files HTTP/1.1
Host: tus.example.org
响应:
HTTP/1.1 204 No Content
Tus-Resumable: 1.0.0
Tus-Version: 1.0.0,0.2.2,0.2.1
Tus-Max-Size: 1073741824
Tus-Extension: creation,expiration
鼓励客户端和服务器尽可能多地实现扩展。客户端应该(SHOULD)通过发送 OPTIONS 请求,服务器通过 Tus-Extension 头部响应来实现特性检测。
客户端和服务器应该(SHOULD)实现上传创建扩展。如果服务器支持此扩展,它必须(MUST)将 creation 添加到 Tus-Extension 头部。
使用空的 POST 请求来创建一个新的上传资源。Upload-Length 头部表示整个上传的大小(以字节为单位)。
请求:
POST /files HTTP/1.1
Host: tus.example.org
Content-Length: 0
Upload-Length: 100
Tus-Resumable: 1.0.0
Upload-Metadata: filename d29ybGRfZG9taW5hdGlvbl9wbGFuLnBkZg==,is_confidential
响应:
HTTP/1.1 201 Created
Location: https://tus.example.org/files/24e533e02ec3bc40c387f1a0e460e216
Tus-Resumable: 1.0.0
新的资源具有隐式的偏移量 0,允许客户端使用核心协议来执行实际的上传。
Upload-Defer-Length 请求和响应头部表明当前不知道上传的大小,稍后会传输。它的值必须(MUST)是 1。如果上传的长度没有被延迟,则必须(MUST)省略此头部。
Upload-Metadata 请求和响应头部必须(MUST)由一个或多个逗号分隔的键值对组成。键和值必须(MUST)用空格分隔。键不得(MUST NOT)包含空格和逗号,并且不得(MUST NOT)为空。键应该(SHOULD)是 ASCII 编码的,值必须(MUST)是 Base64 编码的。所有键必须(MUST)是唯一的。值可以(MAY)为空。在这些情况下,通常分隔键和值的空格可以(MAY)省略。
由于元数据可能包含任意二进制值,服务器应该(SHOULD)仔细验证元数据值或在使用它们作为头部值之前对其进行清理,以避免头部注入攻击。
客户端必须(MUST)向已知的上传创建 URL 发送一个 POST 请求,以请求一个新的上传资源。该请求必须(MUST)包含以下头部之一:
a) Upload-Length,用于指示整个上传的大小(以字节为单位)。
b) Upload-Defer-Length: 1,如果客户端不知道要上传多大。
如果 Upload-Defer-Length 头部不为1,服务器应返回 400 Bad Request 状态。
如果使用 Upload-Defer-Length: 1 延迟了长度,则客户端必须(MUST)在下一个 PATCH 请求中设置 Upload-Length 头部,一旦知道长度。一旦设置,长度不得(MUST NOT)更改。只要不知道上传的长度,服务器必须(MUST)在对 HEAD 请求的所有响应中设置 Upload-Defer-Length: 1。
如果服务器支持延迟长度,它必须(MUST)将 creation-defer-length 添加到 Tus-Extension 头部。
Upload-Length 头部可以(MAY)设置为 0,表示客户端想要上传一个空文件。这样的上传在创建后立即完成,而无需使用 PATCH 请求传输数据。
客户端可以(MAY)提供 Upload-Metadata 头部,以向上传创建请求添加额外的元数据。服务器可以(MAY)决定忽略或使用此信息来进一步处理请求或拒绝它。如果上传包含额外的元数据,则对 HEAD 请求的响应必须(MUST)包含 Upload-Metadata 头部及其值,如客户端在创建期间指定的那样。
如果上传的长度超过了最大值,这可以(MAY)使用 Tus-Max-Size 头部指定,服务器必须(MUST)响应 413 Request Entity Too Large 状态。
服务器必须(MUST)使用 201 Created 状态确认成功的上传创建。服务器必须(MUST)将 Location 头部设置为已创建资源的 URL。此 URL可以(MAY)是绝对的或相对的。
客户端必须(MUST)使用核心协议执行实际的上传。
客户端可以(MAY)使用带上传的创建扩展在初始创建请求中包含上传的部分内容。
如果服务器支持此扩展,它必须(MUST)通过在 Tus-Extension 头部中包含 creation-with-upload 来声明这一点。此外,此扩展直接依赖于创建扩展。因此,如果服务器不提供创建扩展,它不得(MUST NOT)提供带上传的创建扩展。
客户端可以(MAY)在 POST 请求的正文中包含整个或一部分上传数据。在这种情况下,与 PATCH 请求和响应类似的规则适用。客户端必须(MUST)包含 Content-Type: application/offset+octet-stream 头部。服务器应该(SHOULD)接受尽可能多的字节,并且必须(MUST)在响应中包含 Upload-Offset 头部,并且必须(MUST)将其值设置为应用接受的字节后的上传偏移量。
如果客户端想要使用此扩展,客户端应该(SHOULD)在发送 POST 请求之前验证服务器是否支持它。此外,客户端应该(SHOULD)在请求中包含 Expect: 100-continue 头部,以接收来自服务器的早期反馈,了解它是否会接受创建请求,然后再尝试传输第一个块。
使用非空的 POST 请求来创建一个新的上传资源。响应中的 Upload-Offset 头部指示已接受了多少数据。
请求:
POST /files HTTP/1.1
Host: tus.example.org
Content-Length: 5
Upload-Length: 100
Tus-Resumable: 1.0.0
Content-Type: application/offset+octet-stream
hello
响应:
HTTP/1.1 201 Created
Location: https://tus.example.org/files/24e533e02ec3bc40c387f1a0e460e216
Tus-Resumable: 1.0.0
Upload-Offset: 5
服务器可以(MAY)在未完成的上传过期后将其删除。为了向客户端表明此行为,服务器必须(MUST)将 expiration 添加到 Tus-Extension 头部。
未完成的上传在 Upload-Expires 中指定的时间之前可用。在此日期之后,无法恢复上传。
请求:
PATCH /files/24e533e02ec3bc40c387f1a0e460e216 HTTP/1.1
Host: tus.example.org
Content-Type: application/offset+octet-stream
Content-Length: 30
Upload-Offset: 70
Tus-Resumable: 1.0.0
[remaining 30 bytes]
响应:
HTTP/1.1 204 No Content
Upload-Expires: Wed, 25 Jun 2014 16:00:00 GMT
Tus-Resumable: 1.0.0
Upload-Offset: 100
Upload-Expires 响应头部指示未完成的上传过期后的时间。服务器可以(MAY)希望在给定的时间段后删除未完成的上传,以防止废弃的上传占用额外的存储空间。客户端应该(SHOULD)使用此头部来确定上传在尝试恢复上传之前是否仍然有效。
如果上传将要过期,则必须(MUST)在每个 PATCH 响应中包含此头部。如果在创建时已知过期时间,则必须(MUST)在对初始 POST 请求的响应中包含 Upload-Expires 头部。它的值可以(MAY)随时间变化。
如果客户端确实尝试恢复已被服务器删除的上传,则服务器应该(SHOULD)响应 404 Not Found 或 410 Gone 状态。如果服务器正在跟踪过期的上传,则应该(SHOULD)使用后者。在这两种情况下,客户端应该(SHOULD)开始新的上传。
Upload-Expires 头部的值必须(MUST)采用RFC 7231日期时间格式。
客户端和服务器可以(MAY)实现和使用此扩展来验证每个 PATCH 请求的数据完整性。如果支持,服务器必须(MUST)将 checksum 添加到 Tus-Extension 头部。
客户端可以(MAY)在 PATCH 请求中包含 Upload-Checksum 头部。一旦收到整个请求,服务器必须(MUST)使用指定的算法针对提供的校验和验证上传的块。根据结果,服务器可以(MAY)响应以下状态代码之一:
400 Bad Request,如果服务器不支持校验和算法,460 Checksum Mismatch,如果校验和不匹配,或者204 No Content,如果校验和匹配并且数据的处理成功。 在前两种情况下,必须(MUST)丢弃上传的块,并且不得(MUST NOT)更新上传及其偏移量。
服务器必须(MUST)至少支持由 sha1 标识的 SHA1 校验和算法。校验和算法的名称必须(MUST)仅由 ASCII 字符组成,但排除大写字符的修改除外。
Tus-Checksum-Algorithm 头部必须(MUST)包含在对 OPTIONS 请求的响应中。
如果在上传开始时无法计算哈希值,可以(MAY)将其作为尾部包含。如果服务器可以处理尾部,则必须(MUST)通过将 checksum-trailer 添加到 Tus-Extension 头部来声明此行为。尾部,也称为尾随头部,是在请求的正文已经传输之后发送的头部。按照RFC 7230的规定,它们必须(MUST)使用 Trailer 头部声明,并且只允许在分块传输中使用。
Tus-Checksum-Algorithm 响应头部必须(MUST)是服务器支持的校验和算法的逗号分隔列表。
Upload-Checksum 请求头部包含有关当前正文有效负载的校验和的信息。头部必须(MUST)由使用的校验和算法的名称和 Base64 编码的校验和组成,两者之间用空格分隔。
请求:
OPTIONS /files HTTP/1.1
Host: tus.example.org
响应:
HTTP/1.1 204 No Content
Tus-Resumable: 1.0.0
Tus-Version: 1.0.0
Tus-Extension: checksum
Tus-Checksum-Algorithm: md5,sha1,crc32
请求:
PATCH /files/17f44dbe1c4bace0e18ab850cf2b3a83 HTTP/1.1
Content-Length: 11
Upload-Offset: 0
Tus-Resumable: 1.0.0
Upload-Checksum: sha1 Kq5sNclPz7QV2+lfQIuc6R7oRu0=
hello world
响应:
HTTP/1.1 204 No Content
Tus-Resumable: 1.0.0
Upload-Offset: 11
此扩展定义了一种客户端终止已完成和未完成的上传的方式,允许服务器释放已使用的资源。
如果服务器支持此扩展,则必须(MUST)通过将 termination 添加到 Tus-Extension 头部来声明它。
当收到对现有上传的 DELETE 请求时,服务器应该(SHOULD)释放关联的资源,并且必须(MUST)响应 204 No Content 状态,确认上传已终止。对于将来对此 URL 的所有请求,服务器应该(SHOULD)响应 404 Not Found 或 410 Gone 状态。
请求:
DELETE /files/24e533e02ec3bc40c387f1a0e460e216 HTTP/1.1
Host: tus.example.org
Content-Length: 0
Tus-Resumable: 1.0.0
响应:
HTTP/1.1 204 No Content
Tus-Resumable: 1.0.0
此扩展可用于将多个上传连接成一个,使客户端能够执行并行上传和上传非连续的块。如果服务器支持此扩展,则必须(MUST)将 concatenation 添加到 Tus-Extension 头部来声明它。
部分上传表示文件的一个块。它通过在创建新上传时包含 Upload-Concat: partial 头部来构造,使用创建扩展。多个部分上传按指定的顺序连接成一个最终上传。服务器不应该(SHOULD NOT)处理这些部分上传,直到它们被连接成一个最终上传。最终上传的长度**必须%(MUST)是所有部分上传的长度之和。
为了创建一个新的最终上传,客户端 必须*(MUST)将 Upload-Concat 头部添加到上传创建请求。该值必须是 final,后跟一个分号和一个空格分隔的需要连接的部分上传 URL 列表。部分上传必须 按照列表中指定的顺序进行连接。此连接请求应该(SHOULD)在所有相应的部分上传完成后发生。客户端不得(MUST NOT)最终上传创建中包含 Upload-Length 头部。
客户端可以(MAY)在部分上传仍在进行中时发送连接请求。服务器必须(MUST)通过将 concatenation-unfinished 添加到 Tus-Extension 头部来显式声明此功能。
当创建一个新的最终上传时,部分上传的元数据不应(SHALL NOT)传输到新的最终上传。所有元数据应该(SHOULD)使用 Upload-Metadata 头部包含在连接请求中。
服务器可以(MAY)在连接后删除部分上传。但是,客户端可以(MAY)尝试多次使用部分上传。同一个部分上传可以(MAY)在一次上传创建请求中的 Upload-Concat 头部中多次出现,或者可以(MAY)在多个上传创建请求中使用。
服务器必须(MUST)响应 403 Forbidden 状态,以针对最终上传URL的PATCH请求,并且不得(MUST NOT)修改最终上传或其部分上传。
对最终上传的HEAD请求的响应不应该(SHOULD NOT)包含Upload-Offset头部,除非已成功完成连接。成功连接后必须(MUST)设置Upload-Offset 和 Upload-Length,并且它们的值必须(MUST)相等。在连接之前,未定义最终上传的 Upload-Offset 头部的值。
对部分上传的HEAD请求的响应必须(MUST)包含 Upload-Offset 头部。
如果可以在请求时计算最终资源的长度,则必须(MUST)包含 Upload-Length 头部。对部分或最终上传的HEAD请求的响应必须(MUST)包含Upload-Concat 头部及其在上传创建请求中收到的值。
Upload-Concat 请求和响应头部必须(MUST)在部分和最终上传创建请求中设置。它指示上传是部分上传还是最终上传。如果上传是部分上传,则头部值必须(MUST)是 partial。在最终上传的情况下,其值必须 是 final,后跟一个分号和一个空格分隔的将要连接的部分上传 URL 列表。部分上传 URL可以(MAY)是绝对的或相对的,并且不得(MUST NOT)包含空格,如RFC 3986中定义的那样。
在以下示例中,为了便于阅读,省略了 Host 和 Tus-Resumable 头部,尽管规范要求它们。
首先创建两个部分上传:
POST /files HTTP/1.1
Upload-Concat: partial
Upload-Length: 5
HTTP/1.1 201 Created
Location: https://tus.example.org/files/a
POST /files HTTP/1.1
Upload-Concat: partial
Upload-Length: 6
HTTP/1.1 201 Created
Location: https://tus.example.org/files/b
现在可以使用 PATCH 请求将数据上传到两个部分资源:
PATCH /files/a HTTP/1.1
Upload-Offset: 0
Content-Length: 5
hello
HTTP/1.1 204 No Content
PATCH /files/b HTTP/1.1
Upload-Offset: 0
Content-Length: 6
world
HTTP/1.1 204 No Content
在第一个请求中,上传了字符串 hello,而第二个文件现在包含 world,带有一个前导空格。
下一步是创建由两个先前生成的部分上传组成的最终上传。在以下请求中,没有提供 Upload-Length 头部。
POST /files HTTP/1.1
Upload-Concat: final;/files/a /files/b
HTTP/1.1 201 Created
Location: https://tus.example.org/files/ab
最终资源的长度现在为 11 字节,由字符串 hello world 组成。
HEAD /files/ab HTTP/1.1
HTTP/1.1 200 OK
Upload-Length: 11
Upload-Concat: final;/files/a /files/b
常见问题解答可在 https://tus.io/faq.html 上在线获取。
根据 MIT 许可证授权,请参见LICENSE.txt。
版权所有 (c)2013-2016 Transloadit Ltd 及贡献者。