/** * @licstart The following is the entire license notice for the * Javascript code in this page * * Copyright 2019 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @licend The above is the entire license notice for the * Javascript code in this page */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PDFNetworkStream = void 0; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _util = require("../shared/util"); var _network_utils = require("./network_utils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } ; var OK_RESPONSE = 200; var PARTIAL_CONTENT_RESPONSE = 206; function getArrayBuffer(xhr) { var data = xhr.response; if (typeof data !== 'string') { return data; } var array = (0, _util.stringToBytes)(data); return array.buffer; } var NetworkManager = /*#__PURE__*/ function () { function NetworkManager(url, args) { _classCallCheck(this, NetworkManager); 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); } _createClass(NetworkManager, [{ key: "requestRange", value: function requestRange(begin, end, listeners) { var args = { begin: begin, end: end }; for (var prop in listeners) { args[prop] = listeners[prop]; } return this.request(args); } }, { key: "requestFull", value: function requestFull(listeners) { return this.request(listeners); } }, { key: "request", value: function request(args) { var xhr = this.getXhr(); var xhrId = this.currXhrId++; var pendingRequest = this.pendingRequests[xhrId] = { xhr: xhr }; xhr.open('GET', this.url); xhr.withCredentials = this.withCredentials; for (var property in this.httpHeaders) { var value = this.httpHeaders[property]; if (typeof value === 'undefined') { continue; } xhr.setRequestHeader(property, value); } if (this.isHttp && 'begin' in args && 'end' in args) { xhr.setRequestHeader('Range', "bytes=".concat(args.begin, "-").concat(args.end - 1)); pendingRequest.expectedStatus = PARTIAL_CONTENT_RESPONSE; } else { pendingRequest.expectedStatus = OK_RESPONSE; } xhr.responseType = 'arraybuffer'; if (args.onError) { xhr.onerror = function (evt) { args.onError(xhr.status); }; } xhr.onreadystatechange = this.onStateChange.bind(this, xhrId); xhr.onprogress = this.onProgress.bind(this, xhrId); pendingRequest.onHeadersReceived = args.onHeadersReceived; pendingRequest.onDone = args.onDone; pendingRequest.onError = args.onError; pendingRequest.onProgress = args.onProgress; xhr.send(null); return xhrId; } }, { key: "onProgress", value: function onProgress(xhrId, evt) { var pendingRequest = this.pendingRequests[xhrId]; if (!pendingRequest) { return; } if (pendingRequest.onProgress) { pendingRequest.onProgress(evt); } } }, { key: "onStateChange", value: function onStateChange(xhrId, evt) { var pendingRequest = this.pendingRequests[xhrId]; if (!pendingRequest) { return; } var xhr = pendingRequest.xhr; if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) { pendingRequest.onHeadersReceived(); delete pendingRequest.onHeadersReceived; } if (xhr.readyState !== 4) { return; } if (!(xhrId in this.pendingRequests)) { return; } delete this.pendingRequests[xhrId]; if (xhr.status === 0 && this.isHttp) { if (pendingRequest.onError) { pendingRequest.onError(xhr.status); } return; } var xhrStatus = xhr.status || OK_RESPONSE; var ok_response_on_range_request = xhrStatus === OK_RESPONSE && pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE; if (!ok_response_on_range_request && xhrStatus !== pendingRequest.expectedStatus) { if (pendingRequest.onError) { pendingRequest.onError(xhr.status); } return; } var chunk = getArrayBuffer(xhr); if (xhrStatus === PARTIAL_CONTENT_RESPONSE) { var rangeHeader = xhr.getResponseHeader('Content-Range'); var matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader); pendingRequest.onDone({ begin: parseInt(matches[1], 10), chunk: chunk }); } else if (chunk) { pendingRequest.onDone({ begin: 0, chunk: chunk }); } else if (pendingRequest.onError) { pendingRequest.onError(xhr.status); } } }, { key: "hasPendingRequests", value: function hasPendingRequests() { for (var xhrId in this.pendingRequests) { return true; } return false; } }, { key: "getRequestXhr", value: function getRequestXhr(xhrId) { return this.pendingRequests[xhrId].xhr; } }, { key: "isPendingRequest", value: function isPendingRequest(xhrId) { return xhrId in this.pendingRequests; } }, { key: "abortAllRequests", value: function abortAllRequests() { for (var xhrId in this.pendingRequests) { this.abortRequest(xhrId | 0); } } }, { key: "abortRequest", value: function abortRequest(xhrId) { var xhr = this.pendingRequests[xhrId].xhr; delete this.pendingRequests[xhrId]; xhr.abort(); } }]); return NetworkManager; }(); var PDFNetworkStream = /*#__PURE__*/ function () { function PDFNetworkStream(source) { _classCallCheck(this, PDFNetworkStream); this._source = source; this._manager = new NetworkManager(source.url, { httpHeaders: source.httpHeaders, withCredentials: source.withCredentials }); this._rangeChunkSize = source.rangeChunkSize; this._fullRequestReader = null; this._rangeRequestReaders = []; } _createClass(PDFNetworkStream, [{ key: "_onRangeRequestReaderClosed", value: function _onRangeRequestReaderClosed(reader) { var i = this._rangeRequestReaders.indexOf(reader); if (i >= 0) { this._rangeRequestReaders.splice(i, 1); } } }, { key: "getFullReader", value: function getFullReader() { (0, _util.assert)(!this._fullRequestReader); this._fullRequestReader = new PDFNetworkStreamFullRequestReader(this._manager, this._source); return this._fullRequestReader; } }, { key: "getRangeReader", value: function getRangeReader(begin, end) { var reader = new PDFNetworkStreamRangeRequestReader(this._manager, begin, end); reader.onClosed = this._onRangeRequestReaderClosed.bind(this); this._rangeRequestReaders.push(reader); return reader; } }, { key: "cancelAllRequests", value: function cancelAllRequests(reason) { if (this._fullRequestReader) { this._fullRequestReader.cancel(reason); } var readers = this._rangeRequestReaders.slice(0); readers.forEach(function (reader) { reader.cancel(reason); }); } }]); return PDFNetworkStream; }(); exports.PDFNetworkStream = PDFNetworkStream; var PDFNetworkStreamFullRequestReader = /*#__PURE__*/ function () { function PDFNetworkStreamFullRequestReader(manager, source) { _classCallCheck(this, PDFNetworkStreamFullRequestReader); 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 = (0, _util.createPromiseCapability)(); this._disableRange = source.disableRange || false; this._contentLength = source.length; 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; } _createClass(PDFNetworkStreamFullRequestReader, [{ key: "_onHeadersReceived", value: function _onHeadersReceived() { var fullRequestXhrId = this._fullRequestId; var fullRequestXhr = this._manager.getRequestXhr(fullRequestXhrId); var getResponseHeader = function getResponseHeader(name) { return fullRequestXhr.getResponseHeader(name); }; var _validateRangeRequest = (0, _network_utils.validateRangeRequestCapabilities)({ getResponseHeader: getResponseHeader, isHttp: this._manager.isHttp, rangeChunkSize: this._rangeChunkSize, disableRange: this._disableRange }), allowRangeRequests = _validateRangeRequest.allowRangeRequests, suggestedLength = _validateRangeRequest.suggestedLength; if (allowRangeRequests) { this._isRangeSupported = true; } this._contentLength = suggestedLength || this._contentLength; this._filename = (0, _network_utils.extractFilenameFromHeader)(getResponseHeader); if (this._isRangeSupported) { this._manager.abortRequest(fullRequestXhrId); } this._headersReceivedCapability.resolve(); } }, { key: "_onDone", value: function _onDone(args) { if (args) { if (this._requests.length > 0) { var requestCapability = this._requests.shift(); requestCapability.resolve({ value: args.chunk, done: false }); } else { this._cachedChunks.push(args.chunk); } } this._done = true; if (this._cachedChunks.length > 0) { return; } this._requests.forEach(function (requestCapability) { requestCapability.resolve({ value: undefined, done: true }); }); this._requests = []; } }, { key: "_onError", value: function _onError(status) { var url = this._url; var exception = (0, _network_utils.createResponseStatusError)(status, url); this._storedError = exception; this._headersReceivedCapability.reject(exception); this._requests.forEach(function (requestCapability) { requestCapability.reject(exception); }); this._requests = []; this._cachedChunks = []; } }, { key: "_onProgress", value: function _onProgress(data) { if (this.onProgress) { this.onProgress({ loaded: data.loaded, total: data.lengthComputable ? data.total : this._contentLength }); } } }, { key: "read", value: function () { var _read = _asyncToGenerator( /*#__PURE__*/ _regenerator["default"].mark(function _callee() { var chunk, requestCapability; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: if (!this._storedError) { _context.next = 2; break; } throw this._storedError; case 2: if (!(this._cachedChunks.length > 0)) { _context.next = 5; break; } chunk = this._cachedChunks.shift(); return _context.abrupt("return", { value: chunk, done: false }); case 5: if (!this._done) { _context.next = 7; break; } return _context.abrupt("return", { value: undefined, done: true }); case 7: requestCapability = (0, _util.createPromiseCapability)(); this._requests.push(requestCapability); return _context.abrupt("return", requestCapability.promise); case 10: case "end": return _context.stop(); } } }, _callee, this); })); function read() { return _read.apply(this, arguments); } return read; }() }, { key: "cancel", value: function cancel(reason) { this._done = true; this._headersReceivedCapability.reject(reason); this._requests.forEach(function (requestCapability) { requestCapability.resolve({ value: undefined, done: true }); }); this._requests = []; if (this._manager.isPendingRequest(this._fullRequestId)) { this._manager.abortRequest(this._fullRequestId); } this._fullRequestReader = null; } }, { key: "filename", get: function get() { return this._filename; } }, { key: "isRangeSupported", get: function get() { return this._isRangeSupported; } }, { key: "isStreamingSupported", get: function get() { return this._isStreamingSupported; } }, { key: "contentLength", get: function get() { return this._contentLength; } }, { key: "headersReady", get: function get() { return this._headersReceivedCapability.promise; } }]); return PDFNetworkStreamFullRequestReader; }(); var PDFNetworkStreamRangeRequestReader = /*#__PURE__*/ function () { function PDFNetworkStreamRangeRequestReader(manager, begin, end) { _classCallCheck(this, PDFNetworkStreamRangeRequestReader); 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; } _createClass(PDFNetworkStreamRangeRequestReader, [{ key: "_close", value: function _close() { if (this.onClosed) { this.onClosed(this); } } }, { key: "_onDone", value: function _onDone(data) { var chunk = data.chunk; if (this._requests.length > 0) { var requestCapability = this._requests.shift(); requestCapability.resolve({ value: chunk, done: false }); } else { this._queuedChunk = chunk; } this._done = true; this._requests.forEach(function (requestCapability) { requestCapability.resolve({ value: undefined, done: true }); }); this._requests = []; this._close(); } }, { key: "_onProgress", value: function _onProgress(evt) { if (!this.isStreamingSupported && this.onProgress) { this.onProgress({ loaded: evt.loaded }); } } }, { key: "read", value: function () { var _read2 = _asyncToGenerator( /*#__PURE__*/ _regenerator["default"].mark(function _callee2() { var chunk, requestCapability; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: if (!(this._queuedChunk !== null)) { _context2.next = 4; break; } chunk = this._queuedChunk; this._queuedChunk = null; return _context2.abrupt("return", { value: chunk, done: false }); case 4: if (!this._done) { _context2.next = 6; break; } return _context2.abrupt("return", { value: undefined, done: true }); case 6: requestCapability = (0, _util.createPromiseCapability)(); this._requests.push(requestCapability); return _context2.abrupt("return", requestCapability.promise); case 9: case "end": return _context2.stop(); } } }, _callee2, this); })); function read() { return _read2.apply(this, arguments); } return read; }() }, { key: "cancel", value: function cancel(reason) { this._done = true; this._requests.forEach(function (requestCapability) { requestCapability.resolve({ value: undefined, done: true }); }); this._requests = []; if (this._manager.isPendingRequest(this._requestId)) { this._manager.abortRequest(this._requestId); } this._close(); } }, { key: "isStreamingSupported", get: function get() { return false; } }]); return PDFNetworkStreamRangeRequestReader; }();