: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
const length = parseInt(getResponseHeader("Content-Length"), 10);
if (!Number.isInteger(length)) {
returnValues.suggestedLength = length;
if (length <= 2 * rangeChunkSize) {
if (disableRange || !isHttp) {
if (getResponseHeader("Accept-Ranges") !== "bytes") {
const contentEncoding = getResponseHeader("Content-Encoding") || "identity";
if (contentEncoding !== "identity") {
returnValues.allowRangeRequests = true;
function extractFilenameFromHeader(getResponseHeader) {
const contentDisposition = getResponseHeader("Content-Disposition");
if (contentDisposition) {
let filename = getFilenameFromContentDispositionHeader(contentDisposition);
if (filename.includes("%")) {
filename = decodeURIComponent(filename);
if (isPdfFile(filename)) {
function createResponseStatusError(status, url) {
if (status === 404 || status === 0 && url.startsWith("file:")) {
return new MissingPDFException('Missing PDF "' + url + '".');
return new UnexpectedResponseException(`Unexpected server response (${status}) while retrieving PDF "${url}".`, status);
function validateResponseStatus(status) {
return status === 200 || status === 206;
;// CONCATENATED MODULE: ./src/display/fetch_stream.js
function createFetchOptions(headers, withCredentials, abortController) {
signal: abortController.signal,
credentials: withCredentials ? "include" : "same-origin",
function createHeaders(httpHeaders) {
const headers = new Headers();
for (const property in httpHeaders) {
const value = httpHeaders[property];
if (value === undefined) {
headers.append(property, value);
function getArrayBuffer(val) {
if (val instanceof Uint8Array) {
if (val instanceof ArrayBuffer) {
warn(`getArrayBuffer - unexpected data format: ${val}`);
return new Uint8Array(val).buffer;
this.isHttp = /^https?:/i.test(source.url);
this.httpHeaders = this.isHttp && source.httpHeaders || {};
this._fullRequestReader = null;
this._rangeRequestReaders = [];
get _progressiveDataLength() {
return this._fullRequestReader?._loaded ?? 0;
assert(!this._fullRequestReader, "PDFFetchStream.getFullReader can only be called once.");
this._fullRequestReader = new PDFFetchStreamReader(this);
return this._fullRequestReader;
getRangeReader(begin, end) {
if (end <= this._progressiveDataLength) {
const reader = new PDFFetchStreamRangeReader(this, begin, end);
this._rangeRequestReaders.push(reader);
cancelAllRequests(reason) {
this._fullRequestReader?.cancel(reason);
for (const reader of this._rangeRequestReaders.slice(0)) {
class PDFFetchStreamReader {
const source = stream.source;
this._withCredentials = source.withCredentials || false;
this._contentLength = source.length;
this._headersCapability = Promise.withResolvers();
this._disableRange = source.disableRange || false;
this._rangeChunkSize = source.rangeChunkSize;
if (!this._rangeChunkSize && !this._disableRange) {
this._disableRange = true;
this._abortController = new AbortController();
this._isStreamingSupported = !source.disableStream;
this._isRangeSupported = !source.disableRange;
this._headers = createHeaders(this._stream.httpHeaders);
fetch(url, createFetchOptions(this._headers, this._withCredentials, this._abortController)).then(response => {
if (!validateResponseStatus(response.status)) {
throw createResponseStatusError(response.status, url);
this._reader = response.body.getReader();
this._headersCapability.resolve();
const getResponseHeader = name => response.headers.get(name);
} = validateRangeRequestCapabilities({
isHttp: this._stream.isHttp,
rangeChunkSize: this._rangeChunkSize,
disableRange: this._disableRange
this._isRangeSupported = allowRangeRequests;
this._contentLength = suggestedLength || this._contentLength;
this._filename = extractFilenameFromHeader(getResponseHeader);
if (!this._isStreamingSupported && this._isRangeSupported) {
this.cancel(new AbortException("Streaming is disabled."));
}).catch(this._headersCapability.reject);
return this._headersCapability.promise;
return this._contentLength;
return this._isRangeSupported;
get isStreamingSupported() {
return this._isStreamingSupported;
await this._headersCapability.promise;
} = await this._reader.read();
this._loaded += value.byteLength;
total: this._contentLength
value: getArrayBuffer(value),
this._reader?.cancel(reason);
this._abortController.abort();
class PDFFetchStreamRangeReader {
constructor(stream, begin, end) {
const source = stream.source;
this._withCredentials = source.withCredentials || false;
this._readCapability = Promise.withResolvers();
this._isStreamingSupported = !source.disableStream;
this._abortController = new AbortController();
this._headers = createHeaders(this._stream.httpHeaders);
this._headers.append("Range", `bytes=${begin}-${end - 1}`);
fetch(url, createFetchOptions(this._headers, this._withCredentials, this._abortController)).then(response => {
if (!validateResponseStatus(response.status)) {
throw createResponseStatusError(response.status, url);
this._readCapability.resolve();
this._reader = response.body.getReader();
}).catch(this._readCapability.reject);
get isStreamingSupported() {
return this._isStreamingSupported;
await this._readCapability.promise;
} = await this._reader.read();
this._loaded += value.byteLength;
value: getArrayBuffer(value),
this._reader?.cancel(reason);
this._abortController.abort();
;// CONCATENATED MODULE: ./src/display/network.js
const PARTIAL_CONTENT_RESPONSE = 206;
function network_getArrayBuffer(xhr) {
const data = xhr.response;
if (typeof data !== "string") {
return stringToBytes(data).buffer;
constructor(url, args = {}) {
this.isHttp = /^https?:/i.test(url);
this.httpHeaders = this.isHttp && args.httpHeaders || Object.create(null);
this.withCredentials = args.withCredentials || false;
this.pendingRequests = Object.create(null);
requestRange(begin, end, listeners) {
for (const prop in listeners) {
args[prop] = listeners[prop];
return this.request(args);
return this.request(listeners);
const xhr = new XMLHttpRequest();
const xhrId = this.currXhrId++;
const pendingRequest = this.pendingRequests[xhrId] = {
xhr.open("GET", this.url);
xhr.withCredentials = this.withCredentials;
for (const property in this.httpHeaders) {
const value = this.httpHeaders[property];
if (value === undefined) {
xhr.setRequestHeader(property, value);
if (this.isHttp && "begin" in args && "end" in args) {
xhr.setRequestHeader("Range", `bytes=${args.begin}-${args.end - 1}`);
pendingRequest.expectedStatus = PARTIAL_CONTENT_RESPONSE;
pendingRequest.expectedStatus = OK_RESPONSE;
xhr.responseType = "arraybuffer";
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;
const pendingRequest = this.pendingRequests[xhrId];
pendingRequest.onProgress?.(evt);
onStateChange(xhrId, evt) {
const pendingRequest = this.pendingRequests[xhrId];
const xhr = pendingRequest.xhr;
if (xhr.readyState >= 2 && pendingRequest.onHeadersReceived) {
pendingRequest.onHeadersReceived();
delete pendingRequest.onHeadersReceived;
if (xhr.readyState !== 4) {
if (!(xhrId in this.pendingRequests)) {
delete this.pendingRequests[xhrId];
if (xhr.status === 0 && this.isHttp) {
pendingRequest.onError?.(xhr.status);
const xhrStatus = xhr.status || OK_RESPONSE;
const ok_response_on_range_request = xhrStatus === OK_RESPONSE && pendingRequest.expectedStatus === PARTIAL_CONTENT_RESPONSE;
if (!ok_response_on_range_request && xhrStatus !== pendingRequest.expectedStatus) {
pendingRequest.onError?.(xhr.status);
const chunk = network_getArrayBuffer(xhr);
if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
const rangeHeader = xhr.getResponseHeader("Content-Range");
const matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
begin: parseInt(matches[1], 10),
pendingRequest.onError?.(xhr.status);
return this.pendingRequests[xhrId].xhr;
isPendingRequest(xhrId) {
return xhrId in this.pendingRequests;
const xhr = this.pendingRequests[xhrId].xhr;
delete this.pendingRequests[xhrId];
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);
this._rangeRequestReaders.splice(i, 1);
assert(!this._fullRequestReader, "PDFNetworkStream.getFullReader can only be called once.");
this._fullRequestReader = new PDFNetworkStreamFullRequestReader(this._manager, this._source);
return this._fullRequestReader;
getRangeReader(begin, end) {
const reader = new PDFNetworkStreamRangeRequestReader(this._manager, begin, end);
reader.onClosed = this._onRangeRequestReaderClosed.bind(this);
this._rangeRequestReaders.push(reader);
cancelAllRequests(reason) {
this._fullRequestReader?.cancel(reason);
for (const reader of this._rangeRequestReaders.slice(0)) {
class PDFNetworkStreamFullRequestReader {
constructor(manager, source) {
onHeadersReceived: this._onHeadersReceived.bind(this),
onDone: this._onDone.bind(this),
onError: this._onError.bind(this),
onProgress: this._onProgress.bind(this)
this._fullRequestId = manager.requestFull(args);
this._headersReceivedCapability = Promise.withResolvers();
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._storedError = undefined;
const fullRequestXhrId = this._fullRequestId;
const fullRequestXhr = this._manager.getRequestXhr(fullRequestXhrId);
const getResponseHeader = name => fullRequestXhr.getResponseHeader(name);
} = validateRangeRequestCapabilities({
isHttp: this._manager.isHttp,
rangeChunkSize: this._rangeChunkSize,
disableRange: this._disableRange
if (allowRangeRequests) {
this._isRangeSupported = true;
this._contentLength = suggestedLength || this._contentLength;
this._filename = extractFilenameFromHeader(getResponseHeader);
if (this._isRangeSupported) {
this._manager.abortRequest(fullRequestXhrId);
this._headersReceivedCapability.resolve();
if (this._requests.length > 0) {
const requestCapability = this._requests.shift();
requestCapability.resolve({
this._cachedChunks.push(data.chunk);
if (this._cachedChunks.length > 0) {
for (const requestCapability of this._requests) {
requestCapability.resolve({