|
|
"use strict"; module.exports = fetch;
var asPromise = require("@protobufjs/aspromise"), inquire = require("@protobufjs/inquire");
var fs = inquire("fs");
/** * Node-style callback as used by {@link util.fetch}. * @typedef FetchCallback * @type {function} * @param {?Error} error Error, if any, otherwise `null` * @param {string} [contents] File contents, if there hasn't been an error * @returns {undefined} */
/** * Options as used by {@link util.fetch}. * @typedef FetchOptions * @type {Object} * @property {boolean} [binary=false] Whether expecting a binary response * @property {boolean} [xhr=false] If `true`, forces the use of XMLHttpRequest */
/** * Fetches the contents of a file. * @memberof util * @param {string} filename File path or url * @param {FetchOptions} options Fetch options * @param {FetchCallback} callback Callback function * @returns {undefined} */ function fetch(filename, options, callback) { if (typeof options === "function") { callback = options; options = {}; } else if (!options) options = {};
if (!callback) return asPromise(fetch, this, filename, options); // eslint-disable-line no-invalid-this
// if a node-like filesystem is present, try it first but fall back to XHR if nothing is found.
if (!options.xhr && fs && fs.readFile) return fs.readFile(filename, function fetchReadFileCallback(err, contents) { return err && typeof XMLHttpRequest !== "undefined" ? fetch.xhr(filename, options, callback) : err ? callback(err) : callback(null, options.binary ? contents : contents.toString("utf8")); });
// use the XHR version otherwise.
return fetch.xhr(filename, options, callback); }
/** * Fetches the contents of a file. * @name util.fetch * @function * @param {string} path File path or url * @param {FetchCallback} callback Callback function * @returns {undefined} * @variation 2 */
/** * Fetches the contents of a file. * @name util.fetch * @function * @param {string} path File path or url * @param {FetchOptions} [options] Fetch options * @returns {Promise<string|Uint8Array>} Promise * @variation 3 */
/**/ fetch.xhr = function fetch_xhr(filename, options, callback) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange /* works everywhere */ = function fetchOnReadyStateChange() {
if (xhr.readyState !== 4) return undefined;
// local cors security errors return status 0 / empty string, too. afaik this cannot be
// reliably distinguished from an actually empty file for security reasons. feel free
// to send a pull request if you are aware of a solution.
if (xhr.status !== 0 && xhr.status !== 200) return callback(Error("status " + xhr.status));
// if binary data is expected, make sure that some sort of array is returned, even if
// ArrayBuffers are not supported. the binary string fallback, however, is unsafe.
if (options.binary) { var buffer = xhr.response; if (!buffer) { buffer = []; for (var i = 0; i < xhr.responseText.length; ++i) buffer.push(xhr.responseText.charCodeAt(i) & 255); } return callback(null, typeof Uint8Array !== "undefined" ? new Uint8Array(buffer) : buffer); } return callback(null, xhr.responseText); };
if (options.binary) { // ref: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data#Receiving_binary_data_in_older_browsers
if ("overrideMimeType" in xhr) xhr.overrideMimeType("text/plain; charset=x-user-defined"); xhr.responseType = "arraybuffer"; }
xhr.open("GET", filename); xhr.send(); };
|