mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-08-04 05:17:24 +02:00
Merge pull request #21684 from calixteman/fix/quad-regex-headers
Trim the response headers with a backward scan
This commit is contained in:
commit
eb8f6af8cc
@ -25,6 +25,7 @@ import {
|
||||
ensureResponseOrigin,
|
||||
extractFilenameFromHeader,
|
||||
getResponseOrigin,
|
||||
trimHeadersEnd,
|
||||
validateRangeRequestCapabilities,
|
||||
} from "./network_utils.js";
|
||||
import { endRequests } from "./transport_stream.js";
|
||||
@ -208,9 +209,7 @@ class PDFNetworkStreamReader extends BasePDFStreamReader {
|
||||
const rawResponseHeaders = fullRequestXhr.getAllResponseHeaders();
|
||||
const responseHeaders = new Headers(
|
||||
rawResponseHeaders
|
||||
? rawResponseHeaders
|
||||
.trimStart()
|
||||
.replace(/[^\S ]+$/, "") // Not `trimEnd`, to keep regular spaces.
|
||||
? trimHeadersEnd(rawResponseHeaders.trimStart())
|
||||
.split(/[\r\n]+/)
|
||||
.map(x => {
|
||||
const [key, ...val] = x.split(": ");
|
||||
|
||||
@ -32,6 +32,17 @@ function createHeaders(isHttp, httpHeaders) {
|
||||
return headers;
|
||||
}
|
||||
|
||||
// Trim the trailing whitespace of the raw response headers, but keep the
|
||||
// regular spaces (hence no `trimEnd`). Scanning backwards keeps this linear,
|
||||
// whereas a `$`-anchored regex is quadratic in the length of the run.
|
||||
function trimHeadersEnd(str) {
|
||||
let end = str.length;
|
||||
while (end > 0 && str[end - 1] !== " " && /\s/.test(str[end - 1])) {
|
||||
end--;
|
||||
}
|
||||
return str.slice(0, end);
|
||||
}
|
||||
|
||||
function getResponseOrigin(url) {
|
||||
// Notably, null is distinct from "null" string (e.g. from file:-URLs).
|
||||
return URL.parse(url)?.origin ?? null;
|
||||
@ -117,5 +128,6 @@ export {
|
||||
ensureResponseOrigin,
|
||||
extractFilenameFromHeader,
|
||||
getResponseOrigin,
|
||||
trimHeadersEnd,
|
||||
validateRangeRequestCapabilities,
|
||||
};
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
createHeaders,
|
||||
createResponseError,
|
||||
extractFilenameFromHeader,
|
||||
trimHeadersEnd,
|
||||
validateRangeRequestCapabilities,
|
||||
} from "../../src/display/network_utils.js";
|
||||
import { ResponseException } from "../../src/shared/util.js";
|
||||
@ -386,4 +387,38 @@ describe("network_utils", function () {
|
||||
testCreateResponseError(new URL("https://foo.com/bar.pdf"), 0, false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("trimHeadersEnd", function () {
|
||||
it("removes the trailing whitespace", function () {
|
||||
expect(trimHeadersEnd("a: 1\r\nb: 2\r\n")).toEqual("a: 1\r\nb: 2");
|
||||
expect(trimHeadersEnd("a: 1\n\n")).toEqual("a: 1");
|
||||
expect(trimHeadersEnd("a: 1\t\r\n")).toEqual("a: 1");
|
||||
});
|
||||
|
||||
it("keeps the regular spaces", function () {
|
||||
expect(trimHeadersEnd("a: 1 ")).toEqual("a: 1 ");
|
||||
expect(trimHeadersEnd("a: 1\r\n ")).toEqual("a: 1\r\n ");
|
||||
expect(trimHeadersEnd(" ")).toEqual(" ");
|
||||
});
|
||||
|
||||
it("handles strings without trailing whitespace", function () {
|
||||
expect(trimHeadersEnd("")).toEqual("");
|
||||
expect(trimHeadersEnd("a: 1")).toEqual("a: 1");
|
||||
expect(trimHeadersEnd("\r\na: 1")).toEqual("\r\na: 1");
|
||||
});
|
||||
|
||||
it("handles a long run of whitespace efficiently", function () {
|
||||
// Removing the run with a `$`-anchored regex is quadratic in its length,
|
||||
// and a server controls how long the headers are.
|
||||
const run = "\t".repeat(100000);
|
||||
|
||||
const startTime = performance.now();
|
||||
// The run is trailing, hence removed.
|
||||
expect(trimHeadersEnd(`a: 1${run}`)).toEqual("a: 1");
|
||||
// The run is followed by a non-whitespace, hence kept: this is the case
|
||||
// which a regex has to backtrack over.
|
||||
expect(trimHeadersEnd(`a: 1${run}b`)).toEqual(`a: 1${run}b`);
|
||||
expect(performance.now() - startTime).toBeLessThan(1000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user