[api-minor] Use the Fetch API, when supported, to load PDF documents in Node.js environments

Given that modern Node.js versions now implement support for a fair number of "browser" APIs, we can utilize the standard Fetch API to load PDF documents that are specified via http/https URLs.

Please find compatibility information at:
 - https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#browser_compatibility
 - https://nodejs.org/dist/latest-v18.x/docs/api/globals.html#fetch
 - https://developer.mozilla.org/en-US/docs/Web/API/Response#browser_compatibility
 - https://nodejs.org/dist/latest-v18.x/docs/api/globals.html#response
This commit is contained in:
Jonas Jenwald 2024-02-21 16:04:13 +01:00
parent 72b8b29147
commit eded037d06
6 changed files with 123 additions and 54 deletions

View file

@ -13,15 +13,16 @@
* limitations under the License.
*/
import { assert, isNodeJS } from "../../src/shared/util.js";
import { NullStream, StringStream } from "../../src/core/stream.js";
import { Page, PDFDocument } from "../../src/core/document.js";
import { isNodeJS } from "../../src/shared/util.js";
import { Ref } from "../../src/core/primitives.js";
let fs;
let fs, http;
if (isNodeJS) {
// Native packages.
fs = await __non_webpack_import__("fs");
http = await __non_webpack_import__("http");
}
const TEST_PDFS_PATH = isNodeJS ? "./test/pdfs/" : "../pdfs/";
@ -144,10 +145,54 @@ function createIdFactory(pageIndex) {
return page._localIdFactory;
}
function createTemporaryNodeServer() {
assert(isNodeJS, "Should only be used in Node.js environments.");
// Create http server to serve pdf data for tests.
const server = http
.createServer((request, response) => {
const filePath = process.cwd() + "/test/pdfs" + request.url;
fs.lstat(filePath, (error, stat) => {
if (error) {
response.writeHead(404);
response.end(`File ${request.url} not found!`);
return;
}
if (!request.headers.range) {
const contentLength = stat.size;
const stream = fs.createReadStream(filePath);
response.writeHead(200, {
"Content-Type": "application/pdf",
"Content-Length": contentLength,
"Accept-Ranges": "bytes",
});
stream.pipe(response);
} else {
const [start, end] = request.headers.range
.split("=")[1]
.split("-")
.map(x => Number(x));
const stream = fs.createReadStream(filePath, { start, end });
response.writeHead(206, {
"Content-Type": "application/pdf",
});
stream.pipe(response);
}
});
})
.listen(0); /* Listen on a random free port */
return {
server,
port: server.address().port,
};
}
export {
buildGetDocumentParams,
CMAP_URL,
createIdFactory,
createTemporaryNodeServer,
DefaultFileReaderFactory,
STANDARD_FONT_DATA_URL,
TEST_PDFS_PATH,