Skip to content

Commit 082ad95

Browse files
Merge pull request #18673 from Snuffleupagus/use-Headers
Use `Headers` consistently in the different `IPDFStream` implementations
2 parents da99f5d + d3a94f1 commit 082ad95

File tree

5 files changed

+82
-57
lines changed

5 files changed

+82
-57
lines changed

src/display/fetch_stream.js

+10-28
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import { AbortException, assert, warn } from "../shared/util.js";
1717
import {
18+
createHeaders,
1819
createResponseStatusError,
1920
extractFilenameFromHeader,
2021
validateRangeRequestCapabilities,
@@ -38,18 +39,6 @@ function createFetchOptions(headers, withCredentials, abortController) {
3839
};
3940
}
4041

41-
function createHeaders(httpHeaders) {
42-
const headers = new Headers();
43-
for (const property in httpHeaders) {
44-
const value = httpHeaders[property];
45-
if (value === undefined) {
46-
continue;
47-
}
48-
headers.append(property, value);
49-
}
50-
return headers;
51-
}
52-
5342
function getArrayBuffer(val) {
5443
if (val instanceof Uint8Array) {
5544
return val.buffer;
@@ -66,7 +55,7 @@ class PDFFetchStream {
6655
constructor(source) {
6756
this.source = source;
6857
this.isHttp = /^https?:/i.test(source.url);
69-
this.httpHeaders = (this.isHttp && source.httpHeaders) || {};
58+
this.headers = createHeaders(this.isHttp, source.httpHeaders);
7059

7160
this._fullRequestReader = null;
7261
this._rangeRequestReaders = [];
@@ -123,17 +112,13 @@ class PDFFetchStreamReader {
123112
this._abortController = new AbortController();
124113
this._isStreamingSupported = !source.disableStream;
125114
this._isRangeSupported = !source.disableRange;
126-
127-
this._headers = createHeaders(this._stream.httpHeaders);
115+
// Always create a copy of the headers.
116+
const headers = new Headers(stream.headers);
128117

129118
const url = source.url;
130119
fetch(
131120
url,
132-
createFetchOptions(
133-
this._headers,
134-
this._withCredentials,
135-
this._abortController
136-
)
121+
createFetchOptions(headers, this._withCredentials, this._abortController)
137122
)
138123
.then(response => {
139124
if (!validateResponseStatus(response.status)) {
@@ -147,7 +132,7 @@ class PDFFetchStreamReader {
147132
const { allowRangeRequests, suggestedLength } =
148133
validateRangeRequestCapabilities({
149134
getResponseHeader,
150-
isHttp: this._stream.isHttp,
135+
isHttp: stream.isHttp,
151136
rangeChunkSize: this._rangeChunkSize,
152137
disableRange: this._disableRange,
153138
});
@@ -222,17 +207,14 @@ class PDFFetchStreamRangeReader {
222207
this._isStreamingSupported = !source.disableStream;
223208

224209
this._abortController = new AbortController();
225-
this._headers = createHeaders(this._stream.httpHeaders);
226-
this._headers.append("Range", `bytes=${begin}-${end - 1}`);
210+
// Always create a copy of the headers.
211+
const headers = new Headers(stream.headers);
212+
headers.append("Range", `bytes=${begin}-${end - 1}`);
227213

228214
const url = source.url;
229215
fetch(
230216
url,
231-
createFetchOptions(
232-
this._headers,
233-
this._withCredentials,
234-
this._abortController
235-
)
217+
createFetchOptions(headers, this._withCredentials, this._abortController)
236218
)
237219
.then(response => {
238220
if (!validateResponseStatus(response.status)) {

src/display/network.js

+7-13
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import { assert, stringToBytes } from "../shared/util.js";
1717
import {
18+
createHeaders,
1819
createResponseStatusError,
1920
extractFilenameFromHeader,
2021
validateRangeRequestCapabilities,
@@ -38,11 +39,11 @@ function getArrayBuffer(xhr) {
3839
}
3940

4041
class NetworkManager {
41-
constructor(url, args = {}) {
42+
constructor({ url, httpHeaders, withCredentials }) {
4243
this.url = url;
4344
this.isHttp = /^https?:/i.test(url);
44-
this.httpHeaders = (this.isHttp && args.httpHeaders) || Object.create(null);
45-
this.withCredentials = args.withCredentials || false;
45+
this.headers = createHeaders(this.isHttp, httpHeaders);
46+
this.withCredentials = withCredentials || false;
4647

4748
this.currXhrId = 0;
4849
this.pendingRequests = Object.create(null);
@@ -70,12 +71,8 @@ class NetworkManager {
7071

7172
xhr.open("GET", this.url);
7273
xhr.withCredentials = this.withCredentials;
73-
for (const property in this.httpHeaders) {
74-
const value = this.httpHeaders[property];
75-
if (value === undefined) {
76-
continue;
77-
}
78-
xhr.setRequestHeader(property, value);
74+
for (const [key, val] of this.headers) {
75+
xhr.setRequestHeader(key, val);
7976
}
8077
if (this.isHttp && "begin" in args && "end" in args) {
8178
xhr.setRequestHeader("Range", `bytes=${args.begin}-${args.end - 1}`);
@@ -194,10 +191,7 @@ class NetworkManager {
194191
class PDFNetworkStream {
195192
constructor(source) {
196193
this._source = source;
197-
this._manager = new NetworkManager(source.url, {
198-
httpHeaders: source.httpHeaders,
199-
withCredentials: source.withCredentials,
200-
});
194+
this._manager = new NetworkManager(source);
201195
this._rangeChunkSize = source.rangeChunkSize;
202196
this._fullRequestReader = null;
203197
this._rangeRequestReaders = [];

src/display/network_utils.js

+16
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,21 @@ import {
2121
import { getFilenameFromContentDispositionHeader } from "./content_disposition.js";
2222
import { isPdfFile } from "./display_utils.js";
2323

24+
function createHeaders(isHttp, httpHeaders) {
25+
const headers = new Headers();
26+
27+
if (!isHttp || !httpHeaders || typeof httpHeaders !== "object") {
28+
return headers;
29+
}
30+
for (const key in httpHeaders) {
31+
const val = httpHeaders[key];
32+
if (val !== undefined) {
33+
headers.append(key, val);
34+
}
35+
}
36+
return headers;
37+
}
38+
2439
function validateRangeRequestCapabilities({
2540
getResponseHeader,
2641
isHttp,
@@ -98,6 +113,7 @@ function validateResponseStatus(status) {
98113
}
99114

100115
export {
116+
createHeaders,
101117
createResponseStatusError,
102118
extractFilenameFromHeader,
103119
validateRangeRequestCapabilities,

src/display/node_stream.js

+10-16
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import { AbortException, assert, MissingPDFException } from "../shared/util.js";
1717
import {
18+
createHeaders,
1819
extractFilenameFromHeader,
1920
validateRangeRequestCapabilities,
2021
} from "./network_utils.js";
@@ -53,7 +54,7 @@ class PDFNodeStream {
5354
this.url.protocol === "http:" || this.url.protocol === "https:";
5455
// Check if url refers to filesystem.
5556
this.isFsUrl = this.url.protocol === "file:";
56-
this.httpHeaders = (this.isHttp && source.httpHeaders) || {};
57+
this.headers = createHeaders(this.isHttp, source.httpHeaders);
5758

5859
this._fullRequestReader = null;
5960
this._rangeRequestReaders = [];
@@ -291,6 +292,9 @@ class PDFNodeStreamFullReader extends BaseFullReader {
291292
constructor(stream) {
292293
super(stream);
293294

295+
// Node.js requires the `headers` to be a regular Object.
296+
const headers = Object.fromEntries(stream.headers);
297+
294298
const handleResponse = response => {
295299
if (response.statusCode === 404) {
296300
const error = new MissingPDFException(`Missing PDF "${this._url}".`);
@@ -321,11 +325,7 @@ class PDFNodeStreamFullReader extends BaseFullReader {
321325
this._filename = extractFilenameFromHeader(getResponseHeader);
322326
};
323327

324-
this._request = createRequest(
325-
this._url,
326-
stream.httpHeaders,
327-
handleResponse
328-
);
328+
this._request = createRequest(this._url, headers, handleResponse);
329329

330330
this._request.on("error", reason => {
331331
this._storedError = reason;
@@ -342,15 +342,9 @@ class PDFNodeStreamRangeReader extends BaseRangeReader {
342342
constructor(stream, start, end) {
343343
super(stream);
344344

345-
this._httpHeaders = {};
346-
for (const property in stream.httpHeaders) {
347-
const value = stream.httpHeaders[property];
348-
if (value === undefined) {
349-
continue;
350-
}
351-
this._httpHeaders[property] = value;
352-
}
353-
this._httpHeaders.Range = `bytes=${start}-${end - 1}`;
345+
// Node.js requires the `headers` to be a regular Object.
346+
const headers = Object.fromEntries(stream.headers);
347+
headers.Range = `bytes=${start}-${end - 1}`;
354348

355349
const handleResponse = response => {
356350
if (response.statusCode === 404) {
@@ -361,7 +355,7 @@ class PDFNodeStreamRangeReader extends BaseRangeReader {
361355
this._setReadableStream(response);
362356
};
363357

364-
this._request = createRequest(this._url, this._httpHeaders, handleResponse);
358+
this._request = createRequest(this._url, headers, handleResponse);
365359

366360
this._request.on("error", reason => {
367361
this._storedError = reason;

test/unit/network_utils_spec.js

+39
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515

1616
import {
17+
createHeaders,
1718
createResponseStatusError,
1819
extractFilenameFromHeader,
1920
validateRangeRequestCapabilities,
@@ -25,6 +26,44 @@ import {
2526
} from "../../src/shared/util.js";
2627

2728
describe("network_utils", function () {
29+
describe("createHeaders", function () {
30+
it("returns empty `Headers` for invalid input", function () {
31+
const headersArr = [
32+
createHeaders(
33+
/* isHttp = */ false,
34+
/* httpHeaders = */ { "Content-Length": 100 }
35+
),
36+
createHeaders(/* isHttp = */ true, /* httpHeaders = */ undefined),
37+
createHeaders(/* isHttp = */ true, /* httpHeaders = */ null),
38+
createHeaders(/* isHttp = */ true, /* httpHeaders = */ "abc"),
39+
createHeaders(/* isHttp = */ true, /* httpHeaders = */ 123),
40+
];
41+
const emptyObj = Object.create(null);
42+
43+
for (const headers of headersArr) {
44+
expect(Object.fromEntries(headers)).toEqual(emptyObj);
45+
}
46+
});
47+
48+
it("returns populated `Headers` for valid input", function () {
49+
const headers = createHeaders(
50+
/* isHttp = */ true,
51+
/* httpHeaders = */ {
52+
"Content-Length": 100,
53+
"Accept-Ranges": "bytes",
54+
"Dummy-null": null,
55+
"Dummy-undefined": undefined,
56+
}
57+
);
58+
59+
expect(Object.fromEntries(headers)).toEqual({
60+
"content-length": "100",
61+
"accept-ranges": "bytes",
62+
"dummy-null": "null",
63+
});
64+
});
65+
});
66+
2867
describe("validateRangeRequestCapabilities", function () {
2968
it("rejects invalid rangeChunkSize", function () {
3069
expect(function () {

0 commit comments

Comments
 (0)