aboutsummaryrefslogtreecommitdiff
path: root/utilities/hash_script/node_modules/node-fetch/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'utilities/hash_script/node_modules/node-fetch/index.js')
-rw-r--r--utilities/hash_script/node_modules/node-fetch/index.js271
1 files changed, 271 insertions, 0 deletions
diff --git a/utilities/hash_script/node_modules/node-fetch/index.js b/utilities/hash_script/node_modules/node-fetch/index.js
new file mode 100644
index 0000000..8f6730d
--- /dev/null
+++ b/utilities/hash_script/node_modules/node-fetch/index.js
@@ -0,0 +1,271 @@
+
+/**
+ * index.js
+ *
+ * a request API compatible with window.fetch
+ */
+
+var parse_url = require('url').parse;
+var resolve_url = require('url').resolve;
+var http = require('http');
+var https = require('https');
+var zlib = require('zlib');
+var stream = require('stream');
+
+var Body = require('./lib/body');
+var Response = require('./lib/response');
+var Headers = require('./lib/headers');
+var Request = require('./lib/request');
+var FetchError = require('./lib/fetch-error');
+
+// commonjs
+module.exports = Fetch;
+// es6 default export compatibility
+module.exports.default = module.exports;
+
+/**
+ * Fetch class
+ *
+ * @param Mixed url Absolute url or Request instance
+ * @param Object opts Fetch options
+ * @return Promise
+ */
+function Fetch(url, opts) {
+
+ // allow call as function
+ if (!(this instanceof Fetch))
+ return new Fetch(url, opts);
+
+ // allow custom promise
+ if (!Fetch.Promise) {
+ throw new Error('native promise missing, set Fetch.Promise to your favorite alternative');
+ }
+
+ Body.Promise = Fetch.Promise;
+
+ var self = this;
+
+ // wrap http.request into fetch
+ return new Fetch.Promise(function(resolve, reject) {
+ // build request object
+ var options = new Request(url, opts);
+
+ if (!options.protocol || !options.hostname) {
+ throw new Error('only absolute urls are supported');
+ }
+
+ if (options.protocol !== 'http:' && options.protocol !== 'https:') {
+ throw new Error('only http(s) protocols are supported');
+ }
+
+ var send;
+ if (options.protocol === 'https:') {
+ send = https.request;
+ } else {
+ send = http.request;
+ }
+
+ // normalize headers
+ var headers = new Headers(options.headers);
+
+ if (options.compress) {
+ headers.set('accept-encoding', 'gzip,deflate');
+ }
+
+ if (!headers.has('user-agent')) {
+ headers.set('user-agent', 'node-fetch/1.0 (+https://github.com/bitinn/node-fetch)');
+ }
+
+ if (!headers.has('connection') && !options.agent) {
+ headers.set('connection', 'close');
+ }
+
+ if (!headers.has('accept')) {
+ headers.set('accept', '*/*');
+ }
+
+ // detect form data input from form-data module, this hack avoid the need to pass multipart header manually
+ if (!headers.has('content-type') && options.body && typeof options.body.getBoundary === 'function') {
+ headers.set('content-type', 'multipart/form-data; boundary=' + options.body.getBoundary());
+ }
+
+ // bring node-fetch closer to browser behavior by setting content-length automatically
+ if (!headers.has('content-length') && /post|put|patch|delete/i.test(options.method)) {
+ if (typeof options.body === 'string') {
+ headers.set('content-length', Buffer.byteLength(options.body));
+ // detect form data input from form-data module, this hack avoid the need to add content-length header manually
+ } else if (options.body && typeof options.body.getLengthSync === 'function') {
+ // for form-data 1.x
+ if (options.body._lengthRetrievers && options.body._lengthRetrievers.length == 0) {
+ headers.set('content-length', options.body.getLengthSync().toString());
+ // for form-data 2.x
+ } else if (options.body.hasKnownLength && options.body.hasKnownLength()) {
+ headers.set('content-length', options.body.getLengthSync().toString());
+ }
+ // this is only necessary for older nodejs releases (before iojs merge)
+ } else if (options.body === undefined || options.body === null) {
+ headers.set('content-length', '0');
+ }
+ }
+
+ options.headers = headers.raw();
+
+ // http.request only support string as host header, this hack make custom host header possible
+ if (options.headers.host) {
+ options.headers.host = options.headers.host[0];
+ }
+
+ // send request
+ var req = send(options);
+ var reqTimeout;
+
+ if (options.timeout) {
+ req.once('socket', function(socket) {
+ reqTimeout = setTimeout(function() {
+ req.abort();
+ reject(new FetchError('network timeout at: ' + options.url, 'request-timeout'));
+ }, options.timeout);
+ });
+ }
+
+ req.on('error', function(err) {
+ clearTimeout(reqTimeout);
+ reject(new FetchError('request to ' + options.url + ' failed, reason: ' + err.message, 'system', err));
+ });
+
+ req.on('response', function(res) {
+ clearTimeout(reqTimeout);
+
+ // handle redirect
+ if (self.isRedirect(res.statusCode) && options.redirect !== 'manual') {
+ if (options.redirect === 'error') {
+ reject(new FetchError('redirect mode is set to error: ' + options.url, 'no-redirect'));
+ return;
+ }
+
+ if (options.counter >= options.follow) {
+ reject(new FetchError('maximum redirect reached at: ' + options.url, 'max-redirect'));
+ return;
+ }
+
+ if (!res.headers.location) {
+ reject(new FetchError('redirect location header missing at: ' + options.url, 'invalid-redirect'));
+ return;
+ }
+
+ // per fetch spec, for POST request with 301/302 response, or any request with 303 response, use GET when following redirect
+ if (res.statusCode === 303
+ || ((res.statusCode === 301 || res.statusCode === 302) && options.method === 'POST'))
+ {
+ options.method = 'GET';
+ delete options.body;
+ delete options.headers['content-length'];
+ }
+
+ options.counter++;
+
+ resolve(Fetch(resolve_url(options.url, res.headers.location), options));
+ return;
+ }
+
+ // normalize location header for manual redirect mode
+ var headers = new Headers(res.headers);
+ if (options.redirect === 'manual' && headers.has('location')) {
+ headers.set('location', resolve_url(options.url, headers.get('location')));
+ }
+
+ // prepare response
+ var body = res.pipe(new stream.PassThrough());
+ var response_options = {
+ url: options.url
+ , status: res.statusCode
+ , statusText: res.statusMessage
+ , headers: headers
+ , size: options.size
+ , timeout: options.timeout
+ };
+
+ // response object
+ var output;
+
+ // in following scenarios we ignore compression support
+ // 1. compression support is disabled
+ // 2. HEAD request
+ // 3. no content-encoding header
+ // 4. no content response (204)
+ // 5. content not modified response (304)
+ if (!options.compress || options.method === 'HEAD' || !headers.has('content-encoding') || res.statusCode === 204 || res.statusCode === 304) {
+ output = new Response(body, response_options);
+ resolve(output);
+ return;
+ }
+
+ // otherwise, check for gzip or deflate
+ var name = headers.get('content-encoding');
+
+ // for gzip
+ if (name == 'gzip' || name == 'x-gzip') {
+ body = body.pipe(zlib.createGunzip());
+ output = new Response(body, response_options);
+ resolve(output);
+ return;
+
+ // for deflate
+ } else if (name == 'deflate' || name == 'x-deflate') {
+ // handle the infamous raw deflate response from old servers
+ // a hack for old IIS and Apache servers
+ var raw = res.pipe(new stream.PassThrough());
+ raw.once('data', function(chunk) {
+ // see http://stackoverflow.com/questions/37519828
+ if ((chunk[0] & 0x0F) === 0x08) {
+ body = body.pipe(zlib.createInflate());
+ } else {
+ body = body.pipe(zlib.createInflateRaw());
+ }
+ output = new Response(body, response_options);
+ resolve(output);
+ });
+ return;
+ }
+
+ // otherwise, use response as-is
+ output = new Response(body, response_options);
+ resolve(output);
+ return;
+ });
+
+ // accept string, buffer or readable stream as body
+ // per spec we will call tostring on non-stream objects
+ if (typeof options.body === 'string') {
+ req.write(options.body);
+ req.end();
+ } else if (options.body instanceof Buffer) {
+ req.write(options.body);
+ req.end();
+ } else if (typeof options.body === 'object' && options.body.pipe) {
+ options.body.pipe(req);
+ } else if (typeof options.body === 'object') {
+ req.write(options.body.toString());
+ req.end();
+ } else {
+ req.end();
+ }
+ });
+
+};
+
+/**
+ * Redirect code matching
+ *
+ * @param Number code Status code
+ * @return Boolean
+ */
+Fetch.prototype.isRedirect = function(code) {
+ return code === 301 || code === 302 || code === 303 || code === 307 || code === 308;
+}
+
+// expose Promise
+Fetch.Promise = global.Promise;
+Fetch.Response = Response;
+Fetch.Headers = Headers;
+Fetch.Request = Request;