Skip to content

Commit

Permalink
New: Initial attempt on a backwards compatible fetch implementation w…
Browse files Browse the repository at this point in the history
…ith binary support, see protocolbuffers#661
  • Loading branch information
dcodeIO committed Jan 27, 2017
1 parent 2d81864 commit 276a594
Show file tree
Hide file tree
Showing 14 changed files with 83 additions and 49 deletions.
3 changes: 0 additions & 3 deletions lib/aspromise/.gitignore

This file was deleted.

3 changes: 0 additions & 3 deletions lib/base64/.gitignore

This file was deleted.

3 changes: 0 additions & 3 deletions lib/codegen/.gitignore

This file was deleted.

3 changes: 0 additions & 3 deletions lib/eventemitter/.gitignore

This file was deleted.

3 changes: 0 additions & 3 deletions lib/fetch/.gitignore

This file was deleted.

95 changes: 78 additions & 17 deletions lib/fetch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,99 @@ var fs = inquire("fs");
* @returns {undefined}
*/

/**
* Options as used by {@link util.fetch}.
* @typedef {Object}
* @property {boolean} [binary=false] Whether expecting a binary response or not
*/

/**
* Fetches the contents of a file.
* @memberof util
* @param {string} path File path or url
* @param {FetchCallback} [callback] Callback function
* @returns {Promise<string>} A Promise if `callback` has been omitted, otherwise `undefined`
* @property {function(string, FetchCallback=):Promise<string>} xhr XHR/browser fetch with an identical signature
* @param {string} filename File path or url
* @param {FetchOptions} options Fetch options
* @param {FetchCallback} callback Callback function
* @returns {undefined}
*/
function fetch(path, callback) {
function fetch(filename, options, callback) {
if (typeof options === "function") {
callback = options;
options = {};
} else if (!options)
options = {};

if (!callback)
return asPromise(fetch, this, path); // eslint-disable-line no-invalid-this
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 (fs && fs.readFile)
return fs.readFile(path, "utf8", function fetchReadFileCallback(err, contents) {
return fs.readFile(filename, function fetchReadFileCallback(err, contents) {
return err && typeof XMLHttpRequest !== "undefined"
? fetch.xhr(path, callback)
: callback(err, contents);
? fetch.xhr(filename, options, callback)
: err
? callback(err)
: callback(null, options.binary ? contents : contents.toString("utf8"));
});
return fetch.xhr(path, callback);

// use the XHR version otherwise.
return fetch.xhr(filename, options, callback);
}

fetch.xhr = function fetch_xhr(path, 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() {
return xhr.readyState === 4
? xhr.status === 0 || xhr.status === 200
? callback(null, xhr.responseText)
: callback(Error("status " + xhr.status))
: undefined;

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);
};
xhr.open("GET", path);

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();
};
2 changes: 1 addition & 1 deletion lib/fetch/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@protobufjs/fetch",
"description": "Fetches the contents of a file accross node and browsers.",
"version": "1.0.4",
"version": "1.0.5",
"author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion lib/fetch/tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ tape.test("fetch", function(test) {
test.ok(promise instanceof Promise, "should return a promise if callback has been omitted");
}

// TODO
// TODO - some what to test this properly?

test.end();
});
3 changes: 0 additions & 3 deletions lib/inquire/.gitignore

This file was deleted.

3 changes: 0 additions & 3 deletions lib/path/.gitignore

This file was deleted.

3 changes: 0 additions & 3 deletions lib/pool/.gitignore

This file was deleted.

3 changes: 0 additions & 3 deletions lib/utf8/.gitignore

This file was deleted.

5 changes: 2 additions & 3 deletions scripts/bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ var buffer = require("vinyl-buffer");
var vinylfs = require("vinyl-fs");
var source = require("vinyl-source-stream");

var zopfli = require("node-zopfli");

var pkg = require(__dirname + "/../package.json");

var license = [
Expand Down Expand Up @@ -86,9 +88,6 @@ function bundle(options) {
.on("error", gutil.log);
}

var fs = require("fs");
var zopfli = require("node-zopfli");

/**
* Compresses a file using zopfli gzip.
* @param {string} sourceFile Source file
Expand Down
1 change: 1 addition & 0 deletions tests/node/lib_fetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require("../../lib/fetch/tests");

0 comments on commit 276a594

Please sign in to comment.