diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /toolkit/components/pdfjs/content/PdfJsNetwork.sys.mjs | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/pdfjs/content/PdfJsNetwork.sys.mjs')
-rw-r--r-- | toolkit/components/pdfjs/content/PdfJsNetwork.sys.mjs | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/toolkit/components/pdfjs/content/PdfJsNetwork.sys.mjs b/toolkit/components/pdfjs/content/PdfJsNetwork.sys.mjs new file mode 100644 index 0000000000..06f9e55591 --- /dev/null +++ b/toolkit/components/pdfjs/content/PdfJsNetwork.sys.mjs @@ -0,0 +1,215 @@ +/* Copyright 2012 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. + */ + +// eslint-disable-next-line no-unused-vars +function log(aMsg) { + var msg = "PdfJsNetwork.jsm: " + (aMsg.join ? aMsg.join("") : aMsg); + Services.console.logStringMessage(msg); +} + +function getTypedArray(xhr) { + const data = xhr.response; + if (typeof data !== "string") { + return new Uint8Array(data); + } + return Uint8Array.from(data, ch => ch.charCodeAt(0) & 0xff); +} + +export var NetworkManager = (function NetworkManagerClosure() { + const OK_RESPONSE = 200; + const PARTIAL_CONTENT_RESPONSE = 206; + + class NetworkManagerClass { + 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) { + var args = { + begin, + end, + }; + for (var prop in listeners) { + args[prop] = listeners[prop]; + } + return this.request(args); + } + + requestFull(listeners) { + return this.request(listeners); + } + + request(args) { + var xhr = this.getXhr(); + var xhrId = this.currXhrId++; + var 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]; + 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.channel.QueryInterface(Ci.nsIHttpChannel).redirectionLimit = 0; + } else { + pendingRequest.expectedStatus = 200; + } + + 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; + } + + onProgress(xhrId, evt) { + var pendingRequest = this.pendingRequests[xhrId]; + if (!pendingRequest) { + // Maybe abortRequest was called... + return; + } + + var onProgress = pendingRequest.onProgress; + if (onProgress) { + onProgress(evt); + } + } + + onStateChange(xhrId, evt) { + var pendingRequest = this.pendingRequests[xhrId]; + if (!pendingRequest) { + // Maybe abortRequest was called... + 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)) { + // The XHR request might have been aborted in onHeadersReceived() + // callback, in which case we should abort request + return; + } + + delete this.pendingRequests[xhrId]; + + // 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; + + // 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; + + if ( + !ok_response_on_range_request && + xhrStatus !== pendingRequest.expectedStatus + ) { + if (pendingRequest.onError) { + pendingRequest.onError(xhr.status); + } + return; + } + + const chunk = getTypedArray(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); + pendingRequest.onDone({ + begin, + chunk, + }); + } else if (chunk) { + pendingRequest.onDone({ + begin: 0, + chunk, + }); + } else if (pendingRequest.onError) { + pendingRequest.onError(xhr.status); + } + } + + hasPendingRequests() { + for (var xhrId in this.pendingRequests) { + return true; + } + return false; + } + + abortAllRequests() { + for (var xhrId in this.pendingRequests) { + this.abortRequest(xhrId | 0); + } + } + + abortRequest(xhrId) { + var xhr = this.pendingRequests[xhrId].xhr; + delete this.pendingRequests[xhrId]; + xhr.abort(); + } + } + + return NetworkManagerClass; +})(); |