mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-04-10 15:24:03 +02:00
This is an old API-parameter that is now unused within the PDF.js project itself, and its description says that it's (partly) being used for "range requests operations".
Note that the `length` API-parameter is used to set the *initial* `contentLength` in various `BasePDFStreamReader` implementations, however it's always overridden by the "Content-Length" header (sent by the server) when that one exists *and* is a valid number. While we currently fallback to the keep the initial `contentLength` otherwise, note however how in that case range requests will always be *disabled* and thus the only spot in the code-base [where `fullReader.contentLength` is necessary](873378b718/src/core/worker.js (L230-L236)) cannot actually be reached.
Hence the only possible reason to use the `length` API-parameter would be for improved progress reporting[1] during streaming of PDF data in rare cases where the "Content-Length" header is missing/invalid, but the user *somehow* has information from another source about the correct `length` of the PDF document.
That situation feels very much like an edge-case, but it's obviously impossible to know if someone is depending on it. However, please note that there's a work-around available for users affected by this removal:
- Implement a `PDFDataRangeTransport` instance together with custom data-fetching[2], since in that case its `length`-parameter will always be used as-is.
Finally, updates various `BasePDFStreamReader` implementations to only set the `_isRangeSupported` field once the headers are available (since previously we'd just overwrite the "initial" value anyway).
---
[1] I.e. to avoid the "indeterminate" loadingBar being displayed in the viewer.
[2] This is what e.g. the Firefox PDF Viewer uses.
122 lines
3.3 KiB
JavaScript
122 lines
3.3 KiB
JavaScript
/* 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.
|
|
*/
|
|
|
|
import { assert, ResponseException } from "../shared/util.js";
|
|
import { getFilenameFromContentDispositionHeader } from "./content_disposition.js";
|
|
import { isPdfFile } from "./display_utils.js";
|
|
|
|
function createHeaders(isHttp, httpHeaders) {
|
|
const headers = new Headers();
|
|
|
|
if (!isHttp || !httpHeaders || typeof httpHeaders !== "object") {
|
|
return headers;
|
|
}
|
|
for (const key in httpHeaders) {
|
|
const val = httpHeaders[key];
|
|
if (val !== undefined) {
|
|
headers.append(key, val);
|
|
}
|
|
}
|
|
return headers;
|
|
}
|
|
|
|
function getResponseOrigin(url) {
|
|
// Notably, null is distinct from "null" string (e.g. from file:-URLs).
|
|
return URL.parse(url)?.origin ?? null;
|
|
}
|
|
|
|
function validateRangeRequestCapabilities({
|
|
responseHeaders,
|
|
isHttp,
|
|
rangeChunkSize,
|
|
disableRange,
|
|
}) {
|
|
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
|
|
assert(
|
|
Number.isInteger(rangeChunkSize) && rangeChunkSize > 0,
|
|
"rangeChunkSize must be an integer larger than zero."
|
|
);
|
|
}
|
|
const rv = {
|
|
contentLength: 0,
|
|
isRangeSupported: false,
|
|
};
|
|
|
|
const length = parseInt(responseHeaders.get("Content-Length"), 10);
|
|
if (!Number.isInteger(length)) {
|
|
return rv;
|
|
}
|
|
rv.contentLength = length;
|
|
|
|
if (length <= 2 * rangeChunkSize) {
|
|
// The file size is smaller than the size of two chunks, so it does not
|
|
// make any sense to abort the request and retry with a range request.
|
|
return rv;
|
|
}
|
|
if (disableRange || !isHttp) {
|
|
return rv;
|
|
}
|
|
if (responseHeaders.get("Accept-Ranges") !== "bytes") {
|
|
return rv;
|
|
}
|
|
|
|
const contentEncoding = responseHeaders.get("Content-Encoding") || "identity";
|
|
if (contentEncoding === "identity") {
|
|
rv.isRangeSupported = true;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
function extractFilenameFromHeader(responseHeaders) {
|
|
const contentDisposition = responseHeaders.get("Content-Disposition");
|
|
if (contentDisposition) {
|
|
let filename = getFilenameFromContentDispositionHeader(contentDisposition);
|
|
if (filename.includes("%")) {
|
|
try {
|
|
filename = decodeURIComponent(filename);
|
|
} catch {}
|
|
}
|
|
if (isPdfFile(filename)) {
|
|
return filename;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function createResponseError(status, url) {
|
|
return new ResponseException(
|
|
`Unexpected server response (${status}) while retrieving PDF "${url.href}".`,
|
|
status,
|
|
/* missing = */ status === 404 || (status === 0 && url.protocol === "file:")
|
|
);
|
|
}
|
|
|
|
function ensureResponseOrigin(rangeOrigin, origin) {
|
|
if (rangeOrigin !== origin) {
|
|
throw new Error(
|
|
`Expected range response-origin "${rangeOrigin}" to match "${origin}".`
|
|
);
|
|
}
|
|
}
|
|
|
|
export {
|
|
createHeaders,
|
|
createResponseError,
|
|
ensureResponseOrigin,
|
|
extractFilenameFromHeader,
|
|
getResponseOrigin,
|
|
validateRangeRequestCapabilities,
|
|
};
|