Skip to content

Commit

Permalink
Ensure that a missing/invalid "Content-Range" header is handled in `P…
Browse files Browse the repository at this point in the history
…DFNetworkStream` (issue 19075)

In the event that the "Content-Range" header is missing/invalid, loading will now be aborted rather than hanging indefinitely.
  • Loading branch information
Snuffleupagus committed Nov 27, 2024
1 parent 079eb24 commit ef75d0a
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 9 deletions.
19 changes: 12 additions & 7 deletions src/display/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* limitations under the License.
*/

import { assert, stringToBytes } from "../shared/util.js";
import { assert, stringToBytes, warn } from "../shared/util.js";
import {
createHeaders,
createResponseStatusError,
Expand Down Expand Up @@ -159,12 +159,17 @@ class NetworkManager {

const chunk = getArrayBuffer(xhr);
if (xhrStatus === PARTIAL_CONTENT_RESPONSE) {
const rangeHeader = xhr.getResponseHeader("Content-Range");
const matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
pendingRequest.onDone({
begin: parseInt(matches[1], 10),
chunk,
});
try {
const rangeHeader = xhr.getResponseHeader("Content-Range");
const matches = /bytes (\d+)-(\d+)\/(\d+)/.exec(rangeHeader);
pendingRequest.onDone({
begin: parseInt(matches[1], 10),
chunk,
});
} catch (ex) {
warn(`Missing or invalid "Content-Range" header: "${ex}".`);
pendingRequest.onError?.(0);
}
} else if (chunk) {
pendingRequest.onDone({
begin: 0,
Expand Down
41 changes: 40 additions & 1 deletion test/unit/network_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
* limitations under the License.
*/

import { AbortException } from "../../src/shared/util.js";
import {
AbortException,
UnexpectedResponseException,
} from "../../src/shared/util.js";
import { PDFNetworkStream } from "../../src/display/network.js";

describe("network", function () {
Expand Down Expand Up @@ -115,4 +118,40 @@ describe("network", function () {
expect(isRangeSupported).toEqual(true);
expect(fullReaderCancelled).toEqual(true);
});

it(`handle reading ranges with missing/invalid "Content-Range" header`, async function () {
async function readRanges(mode) {
const rangeSize = 32768;
const stream = new PDFNetworkStream({
url: `${pdf1}?test-network-break-ranges=${mode}`,
length: pdf1Length,
rangeChunkSize: rangeSize,
disableStream: true,
disableRange: false,
});

const fullReader = stream.getFullReader();

await fullReader.headersReady;
// Ensure that range requests are supported.
expect(fullReader.isRangeSupported).toEqual(true);
// We shall be able to close the full reader without issues.
fullReader.cancel(new AbortException("Don't need fullReader."));

const rangeReader = stream.getRangeReader(
pdf1Length - rangeSize,
pdf1Length
);

try {
await rangeReader.read();
} catch (ex) {
expect(ex instanceof UnexpectedResponseException).toEqual(true);
expect(ex.status).toEqual(0);
}
rangeReader.cancel(new AbortException("Don't need rangeReader."));
}

await Promise.all([readRanges("missing"), readRanges("invalid")]);
});
});
13 changes: 12 additions & 1 deletion test/webserver.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ class WebServer {
this.#serveFileRange(
response,
localURL,
url.searchParams
fileSize,
start,
isNaN(end) ? fileSize : end + 1
Expand Down Expand Up @@ -307,7 +308,7 @@ class WebServer {
stream.pipe(response);
}

#serveFileRange(response, fileURL, fileSize, start, end) {
#serveFileRange(response, fileURL, searchParams, fileSize, start, end) {
const stream = fs.createReadStream(fileURL, {
flags: "rs",
start,
Expand All @@ -325,6 +326,16 @@ class WebServer {
"Content-Range",
`bytes ${start}-${end - 1}/${fileSize}`
);

// Support test in `test/unit/network_spec.js`.
switch (searchParams.get("test-network-break-ranges")) {
case "missing":
response.removeHeader("Content-Range");
break;
case "invalid":
response.setHeader("Content-Range", "bytes abc-def/qwerty");
break;
}
response.writeHead(206);
stream.pipe(response);
}
Expand Down

0 comments on commit ef75d0a

Please sign in to comment.