Skip to content

Commit d2506ee

Browse files
author
Marius
authored
Add support for IETF resumable upload draft (#609)
* Add support for IETF resumable upload draft * Fix linting * Update to draft -03 * Add documentation
1 parent f9e1e5f commit d2506ee

File tree

3 files changed

+34
-2
lines changed

3 files changed

+34
-2
lines changed

demos/browser/demo.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ function startUpload() {
7171
filename: file.name,
7272
filetype: file.type,
7373
},
74+
protocol: 'ietf-draft-01',
7475
onError(error) {
7576
if (error.originalRequest) {
7677
if (window.confirm(`Failed because: ${error}\nDo you want to retry?`)) {

docs/api.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,12 @@ interface SliceResult {
399399
}
400400
```
401401

402+
#### protocol
403+
404+
_Default value:_ `'tus-v1'`
405+
406+
tus-js-client uses the [tus v1.0.0 upload protocol](https://tus.io/protocols/resumable-upload) by default. It also includes experimental support for [the draft of Resumable Uploads For HTTP](https://datatracker.ietf.org/doc/draft-ietf-httpbis-resumable-upload/) developed in the HTTP working group of the IETF. By setting the `protocol` option to `'ietf-draft-03'`, tus-js-client will use the protocol as defined in the draft version 03. Please be aware that this feature is experimental and that this option might change in breaking ways in non-major releases.
407+
402408
## tus.Upload(file, options)
403409

404410
The constructor for the `tus.Upload` class. The upload will not be started automatically, use `start` to do so.

lib/upload.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import DetailedError from './error.js'
44
import { log } from './logger.js'
55
import uuid from './uuid.js'
66

7+
const PROTOCOL_TUS_V1 = 'tus-v1'
8+
const PROTOCOL_IETF_DRAFT_03 = 'ietf-draft-03'
9+
710
const defaultOptions = {
811
endpoint: null,
912

@@ -37,6 +40,8 @@ const defaultOptions = {
3740
urlStorage: null,
3841
fileReader: null,
3942
httpStack: null,
43+
44+
protocol: PROTOCOL_TUS_V1,
4045
}
4146

4247
class BaseUpload {
@@ -171,6 +176,11 @@ class BaseUpload {
171176
return
172177
}
173178

179+
if (![PROTOCOL_TUS_V1, PROTOCOL_IETF_DRAFT_03].includes(this.options.protocol)) {
180+
this._emitError(new Error(`tus: unsupported protocol ${this.options.protocol}`))
181+
return
182+
}
183+
174184
if (!this.options.endpoint && !this.options.uploadUrl && !this.url) {
175185
this._emitError(new Error('tus: neither an endpoint or an upload URL is provided'))
176186
return
@@ -585,6 +595,9 @@ class BaseUpload {
585595
this._offset = 0
586596
promise = this._addChunkToRequest(req)
587597
} else {
598+
if (this.options.protocol === PROTOCOL_IETF_DRAFT_03) {
599+
req.setHeader('Upload-Complete', '?0')
600+
}
588601
promise = this._sendRequest(req, null)
589602
}
590603

@@ -683,7 +696,11 @@ class BaseUpload {
683696
}
684697

685698
const length = parseInt(res.getHeader('Upload-Length'), 10)
686-
if (Number.isNaN(length) && !this.options.uploadLengthDeferred) {
699+
if (
700+
Number.isNaN(length) &&
701+
!this.options.uploadLengthDeferred &&
702+
this.options.protocol === PROTOCOL_TUS_V1
703+
) {
687704
this._emitHttpError(req, res, 'tus: invalid or missing length value')
688705
return
689706
}
@@ -810,6 +827,10 @@ class BaseUpload {
810827
if (value === null) {
811828
return this._sendRequest(req)
812829
}
830+
831+
if (this.options.protocol === PROTOCOL_IETF_DRAFT_03) {
832+
req.setHeader('Upload-Complete', done ? '?1' : '?0')
833+
}
813834
this._emitProgress(this._offset, this._size)
814835
return this._sendRequest(req, value)
815836
})
@@ -941,7 +962,11 @@ function inStatusCategory(status, category) {
941962
function openRequest(method, url, options) {
942963
const req = options.httpStack.createRequest(method, url)
943964

944-
req.setHeader('Tus-Resumable', '1.0.0')
965+
if (options.protocol === PROTOCOL_IETF_DRAFT_03) {
966+
req.setHeader('Upload-Draft-Interop-Version', '5')
967+
} else {
968+
req.setHeader('Tus-Resumable', '1.0.0')
969+
}
945970
const headers = options.headers || {}
946971

947972
Object.entries(headers).forEach(([name, value]) => {

0 commit comments

Comments
 (0)