diff --git a/src/display/network.js b/src/display/network.js index 1f2dc8a80..8cc6b693b 100644 --- a/src/display/network.js +++ b/src/display/network.js @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* eslint no-var: error */ import { assert, createPromiseCapability, stringToBytes } from '../shared/util'; import { @@ -24,71 +25,70 @@ if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('FIREFOX || MOZCENTRAL')) { 'be used with FIREFOX or MOZCENTRAL build.'); } -var OK_RESPONSE = 200; -var PARTIAL_CONTENT_RESPONSE = 206; - -function NetworkManager(url, args) { - this.url = url; - args = args || {}; - this.isHttp = /^https?:/i.test(url); - this.httpHeaders = (this.isHttp && args.httpHeaders) || {}; - this.withCredentials = args.withCredentials || false; - this.getXhr = args.getXhr || - function NetworkManager_getXhr() { - return new XMLHttpRequest(); - }; - - this.currXhrId = 0; - this.pendingRequests = Object.create(null); -} +const OK_RESPONSE = 200; +const PARTIAL_CONTENT_RESPONSE = 206; function getArrayBuffer(xhr) { - var data = xhr.response; + const data = xhr.response; if (typeof data !== 'string') { return data; } - let array = stringToBytes(data); + const array = stringToBytes(data); return array.buffer; } -NetworkManager.prototype = { - requestRange: function NetworkManager_requestRange(begin, end, listeners) { - var args = { +class NetworkManager { + constructor(url, args) { + this.url = url; + args = args || {}; + this.isHttp = /^https?:/i.test(url); + this.httpHeaders = (this.isHttp && args.httpHeaders) || {}; + this.withCredentials = args.withCredentials || false; + this.getXhr = args.getXhr || + function NetworkManager_getXhr() { + return new XMLHttpRequest(); + }; + + this.currXhrId = 0; + this.pendingRequests = Object.create(null); + } + + requestRange(begin, end, listeners) { + const args = { begin, end, }; - for (var prop in listeners) { + for (const prop in listeners) { args[prop] = listeners[prop]; } return this.request(args); - }, + } - requestFull: function NetworkManager_requestFull(listeners) { + requestFull(listeners) { return this.request(listeners); - }, + } - request: function NetworkManager_request(args) { - var xhr = this.getXhr(); - var xhrId = this.currXhrId++; - var pendingRequest = this.pendingRequests[xhrId] = { + request(args) { + const xhr = this.getXhr(); + const xhrId = this.currXhrId++; + const pendingRequest = this.pendingRequests[xhrId] = { xhr, }; xhr.open('GET', this.url); xhr.withCredentials = this.withCredentials; - for (var property in this.httpHeaders) { - var value = this.httpHeaders[property]; + for (const property in this.httpHeaders) { + const value = this.httpHeaders[property]; if (typeof value === 'undefined') { continue; } xhr.setRequestHeader(property, value); } if (this.isHttp && 'begin' in args && 'end' in args) { - var rangeStr = args.begin + '-' + (args.end - 1); - xhr.setRequestHeader('Range', 'bytes=' + rangeStr); - pendingRequest.expectedStatus = 206; + xhr.setRequestHeader('Range', `bytes=${args.begin}-${args.end - 1}`); + pendingRequest.expectedStatus = PARTIAL_CONTENT_RESPONSE; } else { - pendingRequest.expectedStatus = 200; + pendingRequest.expectedStatus = OK_RESPONSE; } xhr.responseType = 'arraybuffer'; @@ -108,10 +108,10 @@ NetworkManager.prototype = { xhr.send(null); return xhrId; - }, + } - onProgress: function NetworkManager_onProgress(xhrId, evt) { - var pendingRequest = this.pendingRequests[xhrId]; + onProgress(xhrId, evt) { + const pendingRequest = this.pendingRequests[xhrId]; if (!pendingRequest) { // Maybe abortRequest was called... return; @@ -120,16 +120,16 @@ NetworkManager.prototype = { if (pendingRequest.onProgress) { pendingRequest.onProgress(evt); } - }, + } - onStateChange: function NetworkManager_onStateChange(xhrId, evt) { - var pendingRequest = this.pendingRequests[xhrId]; + onStateChange(xhrId, evt) { + const pendingRequest = this.pendingRequests[xhrId]; if (!pendingRequest) { // Maybe abortRequest was called... return; } - var xhr = pendingRequest.xhr; + const xhr = pendingRequest.xhr; if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) { pendingRequest.onHeadersReceived(); delete pendingRequest.onHeadersReceived; @@ -141,27 +141,27 @@ NetworkManager.prototype = { if (!(xhrId in this.pendingRequests)) { // The XHR request might have been aborted in onHeadersReceived() - // callback, in which case we should abort request + // callback, in which case we should abort request. return; } delete this.pendingRequests[xhrId]; - // success status == 0 can be on ftp, file and other protocols + // Success status == 0 can be on ftp, file and other protocols. if (xhr.status === 0 && this.isHttp) { if (pendingRequest.onError) { pendingRequest.onError(xhr.status); } return; } - var xhrStatus = xhr.status || OK_RESPONSE; + const xhrStatus = xhr.status || OK_RESPONSE; // From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2: // "A server MAY ignore the Range header". This means it's possible to // get a 200 rather than a 206 response from a range request. - var ok_response_on_range_request = - xhrStatus === OK_RESPONSE && - pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE; + const ok_response_on_range_request = + xhrStatus === OK_RESPONSE && + pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE; if (!ok_response_on_range_request && xhrStatus !== pendingRequest.expectedStatus) { @@ -171,13 +171,12 @@ NetworkManager.prototype = { return; } - var chunk = getArrayBuffer(xhr); + const chunk = getArrayBuffer(xhr); if (xhrStatus === PARTIAL_CONTENT_RESPONSE) { - var rangeHeader = xhr.getResponseHeader('Content-Range'); - var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader); - var begin = parseInt(matches[1], 10); + const rangeHeader = xhr.getResponseHeader('Content-Range'); + const matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader); pendingRequest.onDone({ - begin, + begin: parseInt(matches[1], 10), chunk, }); } else if (chunk) { @@ -188,125 +187,123 @@ NetworkManager.prototype = { } else if (pendingRequest.onError) { pendingRequest.onError(xhr.status); } - }, + } - hasPendingRequests: function NetworkManager_hasPendingRequests() { - for (var xhrId in this.pendingRequests) { + hasPendingRequests() { + for (const xhrId in this.pendingRequests) { return true; } return false; - }, + } - getRequestXhr: function NetworkManager_getXhr(xhrId) { + getRequestXhr(xhrId) { return this.pendingRequests[xhrId].xhr; - }, + } - isPendingRequest: function NetworkManager_isPendingRequest(xhrId) { + isPendingRequest(xhrId) { return xhrId in this.pendingRequests; - }, + } - abortAllRequests: function NetworkManager_abortAllRequests() { - for (var xhrId in this.pendingRequests) { + abortAllRequests() { + for (const xhrId in this.pendingRequests) { this.abortRequest(xhrId | 0); } - }, + } - abortRequest: function NetworkManager_abortRequest(xhrId) { - var xhr = this.pendingRequests[xhrId].xhr; + abortRequest(xhrId) { + const xhr = this.pendingRequests[xhrId].xhr; delete this.pendingRequests[xhrId]; xhr.abort(); - }, -}; - -/** @implements {IPDFStream} */ -function PDFNetworkStream(source) { - this._source = source; - this._manager = new NetworkManager(source.url, { - httpHeaders: source.httpHeaders, - withCredentials: source.withCredentials, - }); - this._rangeChunkSize = source.rangeChunkSize; - this._fullRequestReader = null; - this._rangeRequestReaders = []; + } } -PDFNetworkStream.prototype = { - _onRangeRequestReaderClosed: - function PDFNetworkStream_onRangeRequestReaderClosed(reader) { - var i = this._rangeRequestReaders.indexOf(reader); +/** @implements {IPDFStream} */ +class PDFNetworkStream { + constructor(source) { + this._source = source; + this._manager = new NetworkManager(source.url, { + httpHeaders: source.httpHeaders, + withCredentials: source.withCredentials, + }); + this._rangeChunkSize = source.rangeChunkSize; + this._fullRequestReader = null; + this._rangeRequestReaders = []; + } + + _onRangeRequestReaderClosed(reader) { + const i = this._rangeRequestReaders.indexOf(reader); if (i >= 0) { this._rangeRequestReaders.splice(i, 1); } - }, + } - getFullReader: function PDFNetworkStream_getFullReader() { + getFullReader() { assert(!this._fullRequestReader); this._fullRequestReader = new PDFNetworkStreamFullRequestReader(this._manager, this._source); return this._fullRequestReader; - }, + } - getRangeReader: function PDFNetworkStream_getRangeReader(begin, end) { - var reader = new PDFNetworkStreamRangeRequestReader(this._manager, - begin, end); + getRangeReader(begin, end) { + const reader = new PDFNetworkStreamRangeRequestReader(this._manager, + begin, end); reader.onClosed = this._onRangeRequestReaderClosed.bind(this); this._rangeRequestReaders.push(reader); return reader; - }, + } - cancelAllRequests: function PDFNetworkStream_cancelAllRequests(reason) { + cancelAllRequests(reason) { if (this._fullRequestReader) { this._fullRequestReader.cancel(reason); } - var readers = this._rangeRequestReaders.slice(0); - readers.forEach(function (reader) { + const readers = this._rangeRequestReaders.slice(0); + readers.forEach(function(reader) { reader.cancel(reason); }); - }, -}; - -/** @implements {IPDFStreamReader} */ -function PDFNetworkStreamFullRequestReader(manager, source) { - this._manager = manager; - - var args = { - onHeadersReceived: this._onHeadersReceived.bind(this), - onDone: this._onDone.bind(this), - onError: this._onError.bind(this), - onProgress: this._onProgress.bind(this), - }; - this._url = source.url; - this._fullRequestId = manager.requestFull(args); - this._headersReceivedCapability = createPromiseCapability(); - this._disableRange = source.disableRange || false; - this._contentLength = source.length; // optional - this._rangeChunkSize = source.rangeChunkSize; - if (!this._rangeChunkSize && !this._disableRange) { - this._disableRange = true; } - - this._isStreamingSupported = false; - this._isRangeSupported = false; - - this._cachedChunks = []; - this._requests = []; - this._done = false; - this._storedError = undefined; - this._filename = null; - - this.onProgress = null; } -PDFNetworkStreamFullRequestReader.prototype = { - _onHeadersReceived: - function PDFNetworkStreamFullRequestReader_onHeadersReceived() { - var fullRequestXhrId = this._fullRequestId; - var fullRequestXhr = this._manager.getRequestXhr(fullRequestXhrId); +/** @implements {IPDFStreamReader} */ +class PDFNetworkStreamFullRequestReader { + constructor(manager, source) { + this._manager = manager; + + const args = { + onHeadersReceived: this._onHeadersReceived.bind(this), + onDone: this._onDone.bind(this), + onError: this._onError.bind(this), + onProgress: this._onProgress.bind(this), + }; + this._url = source.url; + this._fullRequestId = manager.requestFull(args); + this._headersReceivedCapability = createPromiseCapability(); + this._disableRange = source.disableRange || false; + this._contentLength = source.length; // Optional + this._rangeChunkSize = source.rangeChunkSize; + if (!this._rangeChunkSize && !this._disableRange) { + this._disableRange = true; + } + + this._isStreamingSupported = false; + this._isRangeSupported = false; + + this._cachedChunks = []; + this._requests = []; + this._done = false; + this._storedError = undefined; + this._filename = null; + + this.onProgress = null; + } + + _onHeadersReceived() { + const fullRequestXhrId = this._fullRequestId; + const fullRequestXhr = this._manager.getRequestXhr(fullRequestXhrId); const getResponseHeader = (name) => { return fullRequestXhr.getResponseHeader(name); }; - let { allowRangeRequests, suggestedLength, } = + const { allowRangeRequests, suggestedLength, } = validateRangeRequestCapabilities({ getResponseHeader, isHttp: this._manager.isHttp, @@ -331,12 +328,12 @@ PDFNetworkStreamFullRequestReader.prototype = { } this._headersReceivedCapability.resolve(); - }, + } - _onDone: function PDFNetworkStreamFullRequestReader_onDone(args) { + _onDone(args) { if (args) { if (this._requests.length > 0) { - var requestCapability = this._requests.shift(); + const requestCapability = this._requests.shift(); requestCapability.resolve({ value: args.chunk, done: false, }); } else { this._cachedChunks.push(args.chunk); @@ -346,70 +343,70 @@ PDFNetworkStreamFullRequestReader.prototype = { if (this._cachedChunks.length > 0) { return; } - this._requests.forEach(function (requestCapability) { + this._requests.forEach(function(requestCapability) { requestCapability.resolve({ value: undefined, done: true, }); }); this._requests = []; - }, + } - _onError: function PDFNetworkStreamFullRequestReader_onError(status) { - var url = this._url; - var exception = createResponseStatusError(status, url); + _onError(status) { + const url = this._url; + const exception = createResponseStatusError(status, url); this._storedError = exception; this._headersReceivedCapability.reject(exception); - this._requests.forEach(function (requestCapability) { + this._requests.forEach(function(requestCapability) { requestCapability.reject(exception); }); this._requests = []; this._cachedChunks = []; - }, + } - _onProgress: function PDFNetworkStreamFullRequestReader_onProgress(data) { + _onProgress(data) { if (this.onProgress) { this.onProgress({ loaded: data.loaded, total: data.lengthComputable ? data.total : this._contentLength, }); } - }, + } get filename() { return this._filename; - }, + } get isRangeSupported() { return this._isRangeSupported; - }, + } get isStreamingSupported() { return this._isStreamingSupported; - }, + } get contentLength() { return this._contentLength; - }, + } get headersReady() { return this._headersReceivedCapability.promise; - }, + } async read() { if (this._storedError) { throw this._storedError; } if (this._cachedChunks.length > 0) { - var chunk = this._cachedChunks.shift(); + const chunk = this._cachedChunks.shift(); return { value: chunk, done: false, }; } if (this._done) { return { value: undefined, done: true, }; } - var requestCapability = createPromiseCapability(); + const requestCapability = createPromiseCapability(); this._requests.push(requestCapability); return requestCapability.promise; - }, + } - cancel: function PDFNetworkStreamFullRequestReader_cancel(reason) { + cancel(reason) { this._done = true; this._headersReceivedCapability.reject(reason); this._requests.forEach(function (requestCapability) { @@ -420,75 +417,75 @@ PDFNetworkStreamFullRequestReader.prototype = { this._manager.abortRequest(this._fullRequestId); } this._fullRequestReader = null; - }, -}; - -/** @implements {IPDFStreamRangeReader} */ -function PDFNetworkStreamRangeRequestReader(manager, begin, end) { - this._manager = manager; - var args = { - onDone: this._onDone.bind(this), - onProgress: this._onProgress.bind(this), - }; - this._requestId = manager.requestRange(begin, end, args); - this._requests = []; - this._queuedChunk = null; - this._done = false; - - this.onProgress = null; - this.onClosed = null; + } } -PDFNetworkStreamRangeRequestReader.prototype = { - _close: function PDFNetworkStreamRangeRequestReader_close() { +/** @implements {IPDFStreamRangeReader} */ +class PDFNetworkStreamRangeRequestReader { + constructor(manager, begin, end) { + this._manager = manager; + const args = { + onDone: this._onDone.bind(this), + onProgress: this._onProgress.bind(this), + }; + this._requestId = manager.requestRange(begin, end, args); + this._requests = []; + this._queuedChunk = null; + this._done = false; + + this.onProgress = null; + this.onClosed = null; + } + + _close() { if (this.onClosed) { this.onClosed(this); } - }, + } - _onDone: function PDFNetworkStreamRangeRequestReader_onDone(data) { - var chunk = data.chunk; + _onDone(data) { + const chunk = data.chunk; if (this._requests.length > 0) { - var requestCapability = this._requests.shift(); + const requestCapability = this._requests.shift(); requestCapability.resolve({ value: chunk, done: false, }); } else { this._queuedChunk = chunk; } this._done = true; - this._requests.forEach(function (requestCapability) { + this._requests.forEach(function(requestCapability) { requestCapability.resolve({ value: undefined, done: true, }); }); this._requests = []; this._close(); - }, + } - _onProgress: function PDFNetworkStreamRangeRequestReader_onProgress(evt) { + _onProgress(evt) { if (!this.isStreamingSupported && this.onProgress) { this.onProgress({ loaded: evt.loaded, }); } - }, + } get isStreamingSupported() { - return false; // TODO allow progressive range bytes loading - }, + return false; + } async read() { if (this._queuedChunk !== null) { - var chunk = this._queuedChunk; + const chunk = this._queuedChunk; this._queuedChunk = null; return { value: chunk, done: false, }; } if (this._done) { return { value: undefined, done: true, }; } - var requestCapability = createPromiseCapability(); + const requestCapability = createPromiseCapability(); this._requests.push(requestCapability); return requestCapability.promise; - }, + } - cancel: function PDFNetworkStreamRangeRequestReader_cancel(reason) { + cancel(reason) { this._done = true; this._requests.forEach(function (requestCapability) { requestCapability.resolve({ value: undefined, done: true, }); @@ -498,10 +495,9 @@ PDFNetworkStreamRangeRequestReader.prototype = { this._manager.abortRequest(this._requestId); } this._close(); - }, -}; + } +} export { PDFNetworkStream, - NetworkManager, };