New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

httpinvoke

Package Overview
Dependencies
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

httpinvoke - npm Package Compare versions

Comparing version 1.0.4 to 1.1.1

.editorconfig

4

bower.json
{
"name": "httpinvoke",
"version": "1.0.4",
"version": "1.1.1",
"main": "httpinvoke-browser.js",
"description": "a small, no-dependencies HTTP client library for browsers and Node.js with a promise-based or Node.js-style callback-based API to progress events, text and binary file upload and download, request and response headers, status code.",
"description": "A small, no-dependencies HTTP client library for browsers and Node.js with a promise-based or Node.js-style callback-based API to progress events, text and binary file upload and download, partial response body, request and response headers, status code.",
"ignore": [

@@ -7,0 +7,0 @@ "node_modules",

{
"name": "httpinvoke",
"repo": "jakutis/httpinvoke",
"version": "1.0.4",
"description": "a small, no-dependencies HTTP client library for browsers and Node.js with a promise-based or Node.js-style callback-based API to progress events, text and binary file upload and download, request and response headers, status code.",
"version": "1.1.1",
"description": "A small, no-dependencies HTTP client library for browsers and Node.js with a promise-based or Node.js-style callback-based API to progress events, text and binary file upload and download, partial response body, request and response headers, status code.",
"keywords": [

@@ -7,0 +7,0 @@ "http",

@@ -5,2 +5,3 @@ var http = require('http');

var serveFile = function(res, filename, mimeType) {
'use strict';
fs.readFile(filename, function(err, file) {

@@ -21,5 +22,7 @@ if(err) {

var noop = function() {
'use strict';
};
http.createServer(function (req, res) {
'use strict';
console.log(req.method + ' ' + req.url);

@@ -26,0 +29,0 @@ if(req.method === 'GET') {

@@ -11,2 +11,3 @@ var http = require('http');

var compress = function(output, encoding, cb) {
'use strict';
if(encoding === 'gzip') {

@@ -27,25 +28,4 @@ zlib.gzip(output, cb);

var bigslowHello = function(res) {
var entity = 'This School Is Not Falling Apart.\n';
var n = 100;
res.writeHead(200, {
'Content-Type': 'text/plain; charset=UTF-8',
'Content-Length': entity.length * n * 100
});
var i = 0;
var interval = setInterval(function() {
if(i < n) {
for(var j = 0; j < 100; j+=1) {
res.write(entity);
}
i += 1;
} else {
clearInterval(interval);
res.end();
}
}, 1000);
};
var readEntityBody = function(req, text, cb) {
'use strict';
var chunks = [];

@@ -66,2 +46,3 @@ req.on('data', function(chunk) {

var endsWith = function(str, substr) {
'use strict';
return str.substr(str.length - substr.length) === substr;

@@ -71,2 +52,3 @@ };

var beginsWith = function(str, substr) {
'use strict';
return str.substr(0, substr.length) === substr;

@@ -82,2 +64,3 @@ };

var corsHeaders = function(headers, req) {
'use strict';
headers['Access-Control-Allow-Credentials'] = 'true';

@@ -100,2 +83,3 @@ headers['Access-Control-Allow-Origin'] = '*';

var entityHeaders = function(headers) {
'use strict';
// workaround for #2: avoiding cache

@@ -108,3 +92,28 @@ headers.Pragma = 'no-cache';

var bigHello = function(req, res, interval) {
'use strict';
var entity = 'This School Is Not Falling Apart.\n';
var n = 100, headers = {
'Content-Type': 'text/plain; charset=UTF-8',
'Content-Length': entity.length * n * 100
};
corsHeaders(headers, req);
res.writeHead(200, headers);
var i = 0;
var id = setInterval(function() {
if(i < n) {
for(var j = 0; j < 100; j+=1) {
res.write(entity);
}
i += 1;
} else {
clearInterval(id);
res.end();
}
}, interval);
};
var outputStatus = function(req, res) {
'use strict';
var code, i, max = 0;

@@ -130,30 +139,32 @@ Object.keys(cfg.status).forEach(function(code) {

if(typeof cfg.status[code][req.method] !== 'undefined') {
var params = cfg.status[code][req.method][i];
var headers = {};
corsHeaders(headers, req);
if(params.location) {
headers.Location = 'http://' + req.headers.host + req.proxyPath + '/';
res.writeHead(Number(code), headers);
res.end();
} else if(params.responseEntity) {
entityHeaders(headers);
headers['Content-Type'] = 'text/plain';
if(params.partialResponse) {
headers['Accept-Ranges'] = 'bytes';
headers['Content-Range'] = 'bytes 0-4/' + hello.length;
headers['Content-Length'] = '5';
readEntityBody(req, false, function() {
var params = cfg.status[code][req.method][i];
var headers = {};
corsHeaders(headers, req);
if(params.location) {
headers.Location = 'http://' + req.headers.host + req.proxyPath + '/';
res.writeHead(Number(code), headers);
res.end(hello.slice(0, 5));
res.end();
} else if(params.responseEntity) {
entityHeaders(headers);
headers['Content-Type'] = 'text/plain';
if(params.partialResponse) {
headers['Accept-Ranges'] = 'bytes';
headers['Content-Range'] = 'bytes 0-4/' + hello.length;
headers['Content-Length'] = '5';
res.writeHead(Number(code), headers);
res.end(hello.slice(0, 5));
} else {
headers['Content-Length'] = String(hello.length);
res.writeHead(Number(code), headers);
res.end(hello);
}
} else {
headers['Content-Length'] = String(hello.length);
if(code === '407') {
headers['Proxy-Authenticate'] = 'Basic realm="httpinvoke"';
}
res.writeHead(Number(code), headers);
res.end(hello);
res.end();
}
} else {
if(code === '407') {
headers['Proxy-Authenticate'] = 'Basic realm="httpinvoke"';
}
res.writeHead(Number(code), headers);
res.end();
}
});
}

@@ -166,2 +177,5 @@ return true;

var listen = function (req, res) {
'use strict';
var headers;
req.proxyPath = req.url.substr(0, cfg.proxyPath.length) === cfg.proxyPath ? cfg.proxyPath : '';

@@ -233,6 +247,22 @@ res.useChunkedEncodingByDefault = false;

} else if(req.method === 'GET') {
if(req.url === req.proxyPath + '/') {
if(req.url === req.proxyPath + '/noentity') {
output(204, null, false);
} else if(req.url === req.proxyPath + '/') {
output(200, hello, false, 'text/plain; charset=UTF-8');
} else if(req.url === req.proxyPath + '/immediateEnd') {
res.socket.destroy();
} else if(req.url === req.proxyPath + '/endAfterHeaders') {
headers = {
'Content-Length': '1024',
'Content-Type': 'text/plain'
};
entityHeaders(headers);
corsHeaders(headers, req);
res.writeHead(200, headers);
res.write(new Buffer('test'));
res.socket.destroy();
} else if(req.url === req.proxyPath + '/big') {
bigHello(req, res, 10);
} else if(req.url === req.proxyPath + '/bigslow') {
bigslowHello(res);
bigHello(req, res, 1000);
} else if(beginsWith(req.url, req.proxyPath + '/contentEncoding/')) {

@@ -252,8 +282,24 @@ contentEncoding(req.url.substr((req.proxyPath + '/contentEncoding/').length));

output(200, new Buffer([]), false, 'application/octet-stream');
} else if(req.url === req.proxyPath + '/tenseconds') {
} else if(req.url === req.proxyPath + '/onesecondDownload') {
headers = {
'Content-Length': '10244',
'Content-Type': 'text/plain'
};
entityHeaders(headers);
corsHeaders(headers, req);
res.writeHead(200, headers);
res.write(new Buffer(new Array(10241).join('.')));
setTimeout(function() {
res.end(new Buffer('test'));
}, 1000);
} else if(req.url === req.proxyPath + '/onesecondUpload') {
setTimeout(function() {
output(200, hello, false, 'text/plain; charset=UTF-8');
}, 10000);
}, 1000);
} else {
fs.realpath(__dirname + req.url.substr(req.proxyPath.length), function(err, path) {
var url = req.url.substr(req.proxyPath.length);
if(url.lastIndexOf('?') >= 0) {
url = url.substr(0, url.lastIndexOf('?'));
}
fs.realpath(__dirname + url, function(err, path) {
if(err || path.substr(0, __dirname.length) !== __dirname) {

@@ -260,0 +306,0 @@ return output(404, null, false);

var fs = require('fs');
var replace = function(contents, replacements) {
var replace = function(contents, separator, replacements) {
'use strict';
replacements.forEach(function(replacement) {
contents = contents.split(replacement.from);
contents = contents[0] + ';' + replacement.to + ';' + contents[1];
contents = contents[0] + separator + replacement.to + separator + contents[1];
});

@@ -12,8 +13,9 @@ return contents;

var processCommon = function(globalVar) {
'use strict';
return function(contents) {
return replace(contents, [{
from: 'var pass, isArray, isArrayBufferView, _undefined, nextTick;',
return replace(contents, ';', [{
from: 'var mixInPromise, pass, isArray, isArrayBufferView, _undefined, nextTick, isFormData;',
to: globalVar + ';' + fs.readFileSync('./src/common/static.js').toString()
}, {
from: 'var mixInPromise, promise, failWithoutRequest, uploadProgressCb, inputLength, noData, timeout, inputHeaders, statusCb, initDownload, updateDownload, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter;',
from: 'var promise, failWithoutRequest, uploadProgressCb, downloadProgressCb, inputLength, inputHeaders, statusCb, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter, partialOutputMode;',
to: fs.readFileSync('./src/common/closures.js').toString()

@@ -24,6 +26,137 @@ }]);

var processBrowser = function() {
'use strict';
var pc = processCommon('global = window;');
return function(contents) {
return replace(fs.readFileSync('./src/umd.js').toString(), '', [{
from: '__factory__',
to: pc(contents)
}]);
};
};
module.exports = function(grunt) {
'use strict';
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
jshint: {
options: {
/* enforcing */
'bitwise' : true,
'camelcase' : true,
'curly' : true,
'eqeqeq' : true,
'es3' : true,
'forin' : true,
'freeze' : true,
'immed' : true,
'indent' : 4,
'latedef' : true,
'newcap' : true,
'noarg' : true,
'noempty' : true,
'nonew' : true,
'plusplus' : true,
'quotmark' : 'single',
'undef' : true,
'unused' : true,
'strict' : true,
'trailing' : true,
'maxparams' : 0,
'maxdepth' : 0,
'maxstatements' : 0,
'maxcomplexity' : 0,
'maxlen' : 0,
/* relaxing */
'asi' : false,
'boss' : false,
'debug' : false,
'eqnull' : false,
'esnext' : false,
'evil' : false,
'expr' : false,
'funcscope' : false,
'globalstrict' : false,
'iterator' : false,
'lastsemic' : false,
'laxbreak' : false,
'laxcomma' : false,
'loopfunc' : false,
'moz' : false,
'multistr' : false,
'notypeof' : false,
'proto' : false,
'scripturl' : false,
'smarttabs' : false,
'shadow' : false,
'sub' : false,
'supernew' : false,
'validthis' : false,
/* environmnents */
'browser' : false,
'couch' : false,
'devel' : false,
'dojo' : false,
'jquery' : false,
'mootools' : false,
'node' : false,
'nonstandard' : false,
'phantom' : false,
'prototypejs' : false,
'rhino' : false,
'worker' : false,
'wsh' : false,
'yui' : false
},
test: {
options: {
globals: {
it: true,
describe: true,
global: true,
require: true
}
},
src: ['./test/*.js']
},
node: {
options: {
node: true
},
src: ['./Gruntfile.js', './karma.conf.js', './dummyserver.js', './demo/index.js', './src/node.js', './src/commonjs.js']
},
hack: {
options: {
browser: true,
node: true
},
src: ['./karma-mocha-requireHack.js']
},
browser: {
options: {
browser: true,
plusplus: false,
globals: {
XDomainRequest: true,
ActiveXObject: true,
execScript: true,
httpinvoke0: true,
httpinvoke1: true
}
},
src: ['./src/browser.js']
},
common: {
options: {
strict: false,
plusplus: false,
unused: false,
globals: {
global: true
}
},
src: ['./src/common/*.js']
}
},
mochaTest: {

@@ -50,3 +183,3 @@ test: {

options: {
process: processCommon('global = window;')
process: processBrowser()
},

@@ -66,3 +199,3 @@ src: ['./src/browser.js'],

process: function(contents) {
return replace(contents, [{
return replace(contents, ';', [{
from: 'var node;',

@@ -84,6 +217,7 @@ to: fs.readFileSync('./httpinvoke-node.js').toString()

grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-mocha-test');
grunt.registerTask('default', ['concat', 'uglify']);
grunt.registerTask('test', ['concat', 'mochaTest']);
grunt.registerTask('test', ['concat', 'jshint', 'mochaTest']);
};

@@ -9,5 +9,68 @@ (function (root, factory) {

}
}(this, function () {
}(this, /* jshint -W030 */
/* jshint -W033 */
/* jshint -W068 */
(function() {
/* jshint +W030 */
/* jshint +W033 */
/* jshint +W068 */
'use strict';
var global;
;global = window;;var isArrayBufferView = function(input) {
/* jshint unused:true */
;global = window;;var resolve = 0, reject = 1, progress = 2, chain = function(a, b) {
/* jshint expr:true */
a && a.then && a.then(function() {
b[resolve].apply(null, arguments);
}, function() {
b[reject].apply(null, arguments);
}, function() {
b[progress].apply(null, arguments);
});
/* jshint expr:false */
}, nextTick = (global.process && global.process.nextTick) || global.setImmediate || global.setTimeout, mixInPromise = function(o) {
var value, queue = [], state = progress;
var makeState = function(newstate) {
o[newstate] = function(newvalue) {
var i, p;
if(queue) {
value = newvalue;
state = newstate;
for(i = 0; i < queue.length; i++) {
if(typeof queue[i][state] === 'function') {
try {
p = queue[i][state].call(null, value);
if(state < progress) {
chain(p, queue[i]._);
}
} catch(err) {
queue[i]._[reject](err);
}
} else if(state < progress) {
queue[i]._[state](value);
}
}
if(state < progress) {
queue = null;
}
}
};
};
makeState(progress);
makeState(resolve);
makeState(reject);
o.then = function() {
var item = [].slice.call(arguments);
item._ = mixInPromise({});
if(queue) {
queue.push(item);
} else if(typeof item[state] === 'function') {
nextTick(function() {
chain(item[state](value), item._);
});
}
return item._;
};
return o;
}, isArrayBufferView = /* jshint undef:false */function(input) {
return typeof input === 'object' && input !== null && (

@@ -25,5 +88,8 @@ (global.ArrayBufferView && input instanceof ArrayBufferView) ||

);
}, isArray = function(object) {
}/* jshint undef:true */, isArray = function(object) {
return Object.prototype.toString.call(object) === '[object Array]';
}, isByteArray = function(input) {
}, isFormData = function(input) {
return typeof input === 'object' && input !== null && global.FormData &&
input instanceof global.FormData;
}, isByteArray = /* jshint undef:false */function(input) {
return typeof input === 'object' && input !== null && (

@@ -37,6 +103,7 @@ (global.Buffer && input instanceof Buffer) ||

);
}, bytearrayMessage = 'an instance of Buffer, nor Blob, nor File, nor ArrayBuffer, nor ArrayBufferView, nor Int8Array, nor Uint8Array, nor Uint8ClampedArray, nor Int16Array, nor Uint16Array, nor Int32Array, nor Uint32Array, nor Float32Array, nor Float64Array, nor Array', supportedMethods = ',GET,HEAD,PATCH,POST,PUT,DELETE,', pass = function(value) {
}/* jshint undef:true */, bytearrayMessage = 'an instance of Buffer, nor Blob, nor File, nor ArrayBuffer, nor ArrayBufferView, nor Int8Array, nor Uint8Array, nor Uint8ClampedArray, nor Int16Array, nor Uint16Array, nor Int32Array, nor Uint32Array, nor Float32Array, nor Float64Array, nor Array', supportedMethods = ',GET,HEAD,PATCH,POST,PUT,DELETE,', pass = function(value) {
return value;
}, nextTick = (global.process && global.process.nextTick) || global.setImmediate || global.setTimeout, _undefined;
}, _undefined;
;
/* jshint unused:false */
// this could be a simple map, but with this "compression" we save about 100 bytes, if minified (50 bytes, if also gzipped)

@@ -57,15 +124,29 @@ var statusTextToCode = (function() {

);
var bufferSlice = function(buffer, begin, end) {
if(begin === 0 && end === buffer.byteLength) {
return buffer;
var upgradeByteArray = global.Uint8Array ? function(array) {
return new Uint8Array(array);
} : pass;
var binaryStringToByteArray = function(str, bytearray) {
for(var i = bytearray.length; i < str.length;) {
/* jshint bitwise:false */
bytearray.push(str.charCodeAt(i++) & 255);
/* jshint bitwise:true */
}
return buffer.slice ? buffer.slice(begin, end) : new Uint8Array(Array.prototype.slice.call(new Uint8Array(buffer), begin, end)).buffer;
return bytearray;
};
var countStringBytes = function(string) {
for(var c, n = 0, i = string.length;i--;) {
c = string.charCodeAt(i);
n += c < 128 ? 1 : (c < 2048 ? 2 : 3);
}
return n;
};
var responseBodyToBytes, responseBodyLength;
try {
execScript('Function httpinvoke0(B,A)\r\nDim i\r\nFor i=1 to LenB(B)\r\nA.push(AscB(MidB(B,i,1)))\r\nNext\r\nEnd Function\r\nFunction httpinvoke1(B)\r\nhttpinvoke1=LenB(B)\r\nEnd Function', 'vbscript');
responseBodyToBytes = function(binary) {
var bytes = [];
httpinvoke0(binary, bytes);
return bytes;
/* jshint evil:true */
execScript('Function httpinvoke0(B,A,C)\r\nDim i\r\nFor i=C to LenB(B)\r\nA.push(AscB(MidB(B,i,1)))\r\nNext\r\nEnd Function\r\nFunction httpinvoke1(B)\r\nhttpinvoke1=LenB(B)\r\nEnd Function', 'vbscript');
/* jshint evil:false */
responseBodyToBytes = function(binary, bytearray) {
// that vbscript counts from 1, not from 0
httpinvoke0(binary, bytearray, bytearray.length + 1);
return bytearray;
};

@@ -78,49 +159,12 @@ // cannot just assign the function, because httpinvoke1 is not a javascript 'function'

}
var getOutputText = function(xhr) {
return xhr.response || xhr.responseText;
var responseByteArray = function(xhr, bytearray) {
// If response body has bytes out of printable ascii character range, then
// accessing xhr.responseText on Internet Explorer throws "Could not complete the operation due to error c00ce514".
// Therefore, try getting the bytearray from xhr.responseBody.
// Also responseBodyToBytes on some Internet Explorers is not defined, because of removed vbscript support.
return 'responseBody' in xhr && responseBodyToBytes ? responseBodyToBytes(xhr.responseBody, bytearray) : binaryStringToByteArray(xhr.responseText, bytearray);
};
var binaryStringToByteArray = function(str) {
for(var n = str.length, bytearray = new Array(n);n--;) {
bytearray[n] = str.charCodeAt(n) & 255;
}
return bytearray;
var responseByteArrayLength = function(xhr) {
return 'responseBody' in xhr && responseBodyLength ? responseBodyLength(xhr.responseBody) : xhr.responseText.length;
};
var getOutputBinary = function(xhr) {
if('response' in xhr) {
return new Uint8Array(xhr.response || []);
}
// responseBody must be checked this way, because otherwise
// it is falsy and then accessing responseText for binary data
// results in the "c00ce514" error
if('responseBody' in xhr) {
return responseBodyToBytes(xhr.responseBody);
}
var bytearray = binaryStringToByteArray(xhr.responseText);
// firefox 4 supports typed arrays but not xhr2
return global.Uint8Array ? new global.Uint8Array(bytearray) : bytearray;
};
var getOutputLengthText = function(xhr) {
return countStringBytes(getOutputText(xhr));
};
var getOutputLengthBinary = function(xhr) {
if('response' in xhr) {
return xhr.response ? xhr.response.byteLength : 0;
}
// responseBody must be checked this way, because otherwise
// it is falsy and then accessing responseText for binary data
// results in the "c00ce514" error
if('responseBody' in xhr) {
return responseBodyLength(xhr.responseBody);
}
return xhr.responseText.length;
};
var countStringBytes = function(string) {
for(var c, n = 0, i = string.length;i--;) {
c = string.charCodeAt(i);
n += c < 128 ? 1 : (c < 2048 ? 2 : 3);
}
return n;
};
var fillOutputHeaders = function(xhr, outputHeaders) {

@@ -146,4 +190,11 @@ var headers = xhr.getAllResponseHeaders().split(/\r?\n/);

var httpinvoke = function(uri, method, options, cb) {
;var mixInPromise, promise, failWithoutRequest, uploadProgressCb, inputLength, noData, timeout, inputHeaders, statusCb, initDownload, updateDownload, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter;
/* jshint unused:true */
;/* global httpinvoke, url, method, options, cb */
/* global nextTick, mixInPromise, pass, progress, reject, resolve, supportedMethods, isArray, isArrayBufferView, isFormData, isByteArray, bytearrayMessage, _undefined */
/* global setTimeout */
/* global crossDomain */// this one is a hack, because when in nodejs this is not really defined, but it is never needed
/* jshint -W020 */
var promise, failWithoutRequest, uploadProgressCb, downloadProgressCb, inputLength, inputHeaders, statusCb, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter;
/*************** COMMON initialize parameters **************/
var downloadTimeout, uploadTimeout, timeout;
if(!method) {

@@ -188,69 +239,11 @@ // 1 argument

}
var safeCallback = function(name, aspect) {
if(name in options) {
return function(a, b, c, d) {
try {
options[name](a, b, c, d);
} catch(_) {
}
aspect(a, b, c, d);
};
}
return aspect;
};
var chain = function(a, b) {
a && a.then && a.then(function() {
b[resolve].apply(null, arguments);
}, function() {
b[reject].apply(null, arguments);
}, function() {
b[progress].apply(null, arguments);
});
};
var resolve = 0, reject = 1, progress = 2;
mixInPromise = function(o) {
var value, queue = [], state = progress;
var makeState = function(newstate) {
o[newstate] = function(newvalue) {
var i, p;
if(queue) {
value = newvalue;
state = newstate;
for(i = 0; i < queue.length; i++) {
if(typeof queue[i][state] === 'function') {
try {
p = queue[i][state].call(null, value);
if(state < progress) {
chain(p, queue[i]._);
}
} catch(err) {
queue[i]._[reject](err);
}
} else if(state < progress) {
queue[i]._[state](value);
}
}
if(state < progress) {
queue = null;
}
}
};
};
makeState(progress);
makeState(resolve);
makeState(reject);
o.then = function() {
var item = [].slice.call(arguments);
item._ = mixInPromise({});
if(queue) {
queue.push(item);
} else if(typeof item[state] === 'function') {
nextTick(function() {
chain(item[state](value), item._);
});
var safeCallback = function(name, aspectBefore, aspectAfter) {
return function(a, b, c, d) {
aspectBefore(a, b, c, d);
try {
options[name](a, b, c, d);
} catch(_) {
}
return item._;
aspectAfter(a, b, c, d);
};
return o;
};

@@ -269,3 +262,3 @@ failWithoutRequest = function(cb, err) {

uploadProgressCb = safeCallback('uploading', function(current, total) {
uploadProgressCb = safeCallback('uploading', pass, function(current, total) {
promise[progress]({

@@ -277,10 +270,21 @@ type: 'upload',

});
var downloadProgressCb = safeCallback('downloading', function(current, total) {
downloadProgressCb = safeCallback('downloading', pass, function(current, total, partial) {
promise[progress]({
type: 'download',
current: current,
total: total
total: total,
partial: partial
});
});
statusCb = safeCallback('gotStatus', function(statusCode, headers) {
statusCb = safeCallback('gotStatus', function() {
statusCb = null;
if(downloadTimeout) {
setTimeout(function() {
if(cb) {
cb(new Error('download timeout'));
promise();
}
}, downloadTimeout);
}
}, function(statusCode, headers) {
promise[progress]({

@@ -292,3 +296,6 @@ type: 'headers',

});
cb = safeCallback('finished', function(err, body, statusCode, headers) {
cb = safeCallback('finished', function() {
cb = null;
promise();
}, function(err, body, statusCode, headers) {
if(err) {

@@ -303,53 +310,74 @@ return promise[reject](err);

});
timeout = options.timeout || 0;
var fixPositiveOpt = function(opt) {
if(options[opt] === _undefined) {
options[opt] = 0;
} else if(typeof options[opt] === 'number') {
if(options[opt] < 0) {
return failWithoutRequest(cb, new Error('Option "' + opt + '" is less than zero'));
}
} else {
return failWithoutRequest(cb, new Error('Option "' + opt + '" is not a number'));
}
};
var converters = options.converters || {};
var inputConverter;
inputLength = 0;
inputHeaders = options.headers || {};
outputHeaders = {};
exposedHeaders = options.corsExposedHeaders || [];
exposedHeaders.push.apply(exposedHeaders, ['Cache-Control', 'Content-Language', 'Content-Type', 'Content-Length', 'Expires', 'Last-Modified', 'Pragma', 'Content-Range']);
exposedHeaders.push.apply(exposedHeaders, ['Cache-Control', 'Content-Language', 'Content-Type', 'Content-Length', 'Expires', 'Last-Modified', 'Pragma', 'Content-Range', 'Content-Encoding']);
/*************** COMMON convert and validate parameters **************/
var partialOutputMode = options.partialOutputMode || 'disabled';
if(partialOutputMode.indexOf(',') >= 0 || ',disabled,chunked,joined,'.indexOf(',' + partialOutputMode + ',') < 0) {
return failWithoutRequest(cb, new Error('Option "partialOutputMode" is neither "disabled", nor "chunked", nor "joined"'));
}
if(method.indexOf(',') >= 0 || supportedMethods.indexOf(',' + method + ',') < 0) {
return failWithoutRequest(cb, new Error('Unsupported method ' + method));
}
outputBinary = options.outputType === 'bytearray';
if(!options.outputType || options.outputType === 'text' || outputBinary) {
var optionsOutputType = options.outputType;
outputBinary = optionsOutputType === 'bytearray';
if(!optionsOutputType || optionsOutputType === 'text' || outputBinary) {
outputConverter = pass;
} else if(converters['text ' + options.outputType]) {
outputConverter = converters['text ' + options.outputType];
} else if(converters['text ' + optionsOutputType]) {
outputConverter = converters['text ' + optionsOutputType];
outputBinary = false;
} else if(converters['bytearray ' + options.outputType]) {
outputConverter = converters['bytearray ' + options.outputType];
} else if(converters['bytearray ' + optionsOutputType]) {
outputConverter = converters['bytearray ' + optionsOutputType];
outputBinary = true;
} else {
return failWithoutRequest(cb, new Error('Unsupported outputType ' + options.outputType));
return failWithoutRequest(cb, new Error('Unsupported outputType ' + optionsOutputType));
}
inputConverter = pass;
if('input' in options) {
input = options.input;
if(!options.inputType || options.inputType === 'auto') {
if(typeof input !== 'string' && !isByteArray(input)) {
return failWithoutRequest(cb, new Error('inputType is undefined or auto and input is neither string, nor ' + bytearrayMessage));
var optionsInputType = options.inputType;
input = options.input;
if(input !== _undefined) {
if(!optionsInputType || optionsInputType === 'auto') {
if(typeof input !== 'string' && !isByteArray(input) && !isFormData(input)) {
return failWithoutRequest(cb, new Error('inputType is undefined or auto and input is neither string, nor FormData, nor ' + bytearrayMessage));
}
} else if(options.inputType === 'text') {
} else if(optionsInputType === 'text') {
if(typeof input !== 'string') {
return failWithoutRequest(cb, new Error('inputType is text, but input is not a string'));
}
} else if (options.inputType === 'bytearray') {
} else if (optionsInputType === 'formdata') {
if(!isFormData(input)) {
return failWithoutRequest(cb, new Error('inputType is formdata, but input is not an instance of FormData'));
}
} else if (optionsInputType === 'bytearray') {
if(!isByteArray(input)) {
return failWithoutRequest(cb, new Error('inputType is bytearray, but input is neither ' + bytearrayMessage));
}
} else if(converters[options.inputType + ' text']) {
inputConverter = converters[options.inputType + ' text'];
} else if(converters[options.inputType + ' bytearray']) {
inputConverter = converters[options.inputType + ' bytearray'];
} else if(converters[optionsInputType + ' text']) {
inputConverter = converters[optionsInputType + ' text'];
} else if(converters[optionsInputType + ' bytearray']) {
inputConverter = converters[optionsInputType + ' bytearray'];
} else if(converters[optionsInputType + ' formdata']) {
inputConverter = converters[optionsInputType + ' formdata'];
} else {
return failWithoutRequest(cb, new Error('There is no converter for specified inputType'));
}
if(typeof input === 'object') {
if(global.ArrayBuffer && input instanceof ArrayBuffer) {
input = new Uint8Array(input);
if(typeof input === 'object' && !isFormData(input)) {
if(global.ArrayBuffer && input instanceof global.ArrayBuffer) {
input = new global.Uint8Array(input);
} else if(isArrayBufferView(input)) {
input = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
input = new global.Uint8Array(input.buffer, input.byteOffset, input.byteLength);
}

@@ -363,3 +391,3 @@ }

} else {
if(options.inputType) {
if(optionsInputType && optionsInputType !== 'auto') {
return failWithoutRequest(cb, new Error('"input" is undefined, but inputType is defined'));

@@ -371,28 +399,57 @@ }

}
/*************** COMMON initialize helper variables **************/
var downloaded;
initDownload = function(total) {
if(typeof outputLength === 'undefined') {
downloadProgressCb(downloaded, outputLength = total);
}
var isValidTimeout = function(timeout) {
return timeout > 0 && timeout < 1073741824;
};
updateDownload = function(value) {
if(value !== downloaded) {
downloadProgressCb(downloaded = value, outputLength);
var optionsTimeout = options.timeout;
if(optionsTimeout !== _undefined) {
if(typeof optionsTimeout === 'number' && isValidTimeout(optionsTimeout)) {
timeout = optionsTimeout;
} else if(isArray(optionsTimeout) && optionsTimeout.length === 2 && isValidTimeout(optionsTimeout[0]) && isValidTimeout(optionsTimeout[1])) {
if(httpinvoke.corsFineGrainedTimeouts || !crossDomain) {
uploadTimeout = optionsTimeout[0];
downloadTimeout = optionsTimeout[1];
} else {
timeout = optionsTimeout[0] + optionsTimeout[1];
}
} else {
return failWithoutRequest(cb, new Error('"timeout" value is not valid'));
}
};
noData = function() {
initDownload(0);
if(cb) {
cb(null, _undefined, status, outputHeaders);
cb = null;
}
};
}
if(uploadTimeout) {
setTimeout(function() {
if(statusCb) {
cb(new Error('upload timeout'));
promise();
}
}, uploadTimeout);
}
if(timeout) {
setTimeout(function() {
if(cb) {
cb(new Error('timeout'));
promise();
}
}, timeout);
}
;
/* jshint unused:false */
/*************** initialize helper variables **************/
var xhr, i, j, currentLocation, crossDomain, output,
getOutput = outputBinary ? getOutputBinary : getOutputText,
getOutputLength = outputBinary ? getOutputLengthBinary : getOutputLengthText,
uploadProgressCbCalled = false;
uploadProgressCbCalled = false,
partialPosition = 0,
partialBuffer = partialOutputMode === 'disabled' ? _undefined : (outputBinary ? [] : ''),
partial = partialBuffer,
partialUpdate = function() {
if(partialOutputMode === 'disabled') {
return;
}
if(outputBinary) {
responseByteArray(xhr, partialBuffer);
} else {
partialBuffer = xhr.responseText;
}
partial = partialOutputMode === 'joined' ? partialBuffer : partialBuffer.slice(partialPosition);
partialPosition = partialBuffer.length;
};
var uploadProgress = function(uploaded) {

@@ -427,4 +484,4 @@ if(!uploadProgressCb) {

/*************** start XHR **************/
if(typeof input === 'object' && httpinvoke.requestTextOnly) {
return failWithoutRequest(cb, new Error('bytearray inputType is not supported on this platform, please always test using requestTextOnly feature flag'));
if(typeof input === 'object' && !isFormData(input) && httpinvoke.requestTextOnly) {
return failWithoutRequest(cb, new Error('bytearray inputType is not supported on this platform, please always test using requestTextOnly feature flag - hint - you may want to try sending FormData (formdata type)'));
}

@@ -439,2 +496,5 @@ if(crossDomain && !httpinvoke.cors) {

}
if(method === 'PATCH' && !httpinvoke.PATCH) {
return failWithoutRequest(cb, new Error('PATCH method is not supported in this browser'));
}
if(!createXHR) {

@@ -444,12 +504,6 @@ return failWithoutRequest(cb, new Error('unable to construct XMLHttpRequest object'));

xhr = createXHR(crossDomain);
xhr.open(method, uri, true);
if(timeout > 0) {
if('timeout' in xhr) {
xhr.timeout = timeout;
} else {
setTimeout(function() {
cb(new Error('download timeout'));
cb = null;
}, timeout);
}
try {
xhr.open(method, uri, true);
} catch(e) {
return failWithoutRequest(cb, e);
}

@@ -471,19 +525,19 @@ if(options.corsCredentials && httpinvoke.corsCredentials && typeof xhr.withCredentials === 'boolean') {

/*************** bind XHR event listeners **************/
var makeErrorCb = function(message) {
return function() {
// must check, because some callbacks are called synchronously, thus throwing exceptions and breaking code
if(cb) {
cb(new Error(message));
cb = null;
}
};
};
var onuploadprogress = function(progressEvent) {
if(cb && progressEvent.lengthComputable) {
uploadProgress(progressEvent.loaded);
if(inputLength === _undefined) {
inputLength = progressEvent.total || progressEvent.totalSize || 0;
uploadProgress(0);
}
uploadProgress(progressEvent.loaded || progressEvent.position || 0);
}
};
if('upload' in xhr) {
xhr.upload.ontimeout = makeErrorCb('upload timeout');
xhr.upload.onerror = makeErrorCb('upload error');
xhr.upload.onerror = function() {
received.error = true;
// must check, because some callbacks are called synchronously, thus throwing exceptions and breaking code
/* jshint expr:true */
cb && cb(new Error('network error'));
/* jshint expr:false */
};
xhr.upload.onprogress = onuploadprogress;

@@ -494,7 +548,5 @@ } else if('onuploadprogress' in xhr) {

if('ontimeout' in xhr) {
xhr.ontimeout = makeErrorCb('download timeout');
}
if('onerror' in xhr) {
xhr.onerror = function() {
received.error = true;
//inspect('onerror', arguments[0]);

@@ -506,43 +558,30 @@ //dbg('onerror');

}
var ondownloadprogress = function(progressEvent) {
onHeadersReceived(false);
// There is a bug in Chrome 10 on 206 response with Content-Range=0-4/12 - total must be 5
// 'total', 12, 'totalSize', 12, 'loaded', 5, 'position', 5, 'lengthComputable', true, 'status', 206
// console.log('total', progressEvent.total, 'totalSize', progressEvent.totalSize, 'loaded', progressEvent.loaded, 'position', progressEvent.position, 'lengthComputable', progressEvent.lengthComputable, 'status', status);
// httpinvoke does not work around this bug, because Chrome 10 is practically not used at all, as Chrome agressively auto-updates itself to latest version
try {
var current = progressEvent.loaded || progressEvent.position || 0;
if(progressEvent.lengthComputable) {
outputLength = progressEvent.total || progressEvent.totalSize || 0;
}
// Opera 12 progress events has a bug - .loaded can be higher than .total
// see http://dev.opera.com/articles/view/xhr2/#comment-96081222
/* jshint expr:true */
cb && current <= outputLength && !statusCb && (partialUpdate(), downloadProgressCb(current, outputLength, partial));
/* jshint expr:false */
} catch(_) {
}
};
if('onloadstart' in xhr) {
xhr.onloadstart = function() {
//dbg('onloadstart');
onHeadersReceived(false);
};
xhr.onloadstart = ondownloadprogress;
}
if('onloadend' in xhr) {
xhr.onloadend = function() {
//dbg('onloadend');
onHeadersReceived(false);
};
xhr.onloadend = ondownloadprogress;
}
if('onprogress' in xhr) {
xhr.onprogress = function(progressEvent) {
//dbg('onprogress');
if(!cb) {
return;
}
onHeadersReceived(false);
if(statusCb) {
return;
}
// There is a bug in Chrome 10 on 206 response with Content-Range=0-4/12 - total must be 5
// 'total', 12, 'totalSize', 12, 'loaded', 5, 'position', 5, 'lengthComputable', true, 'status', 206
// console.log('total', progressEvent.total, 'totalSize', progressEvent.totalSize, 'loaded', progressEvent.loaded, 'position', progressEvent.position, 'lengthComputable', progressEvent.lengthComputable, 'status', status);
// httpinvoke does not work around this bug, because Chrome 10 is practically not used at all, as Chrome agressively auto-updates itself to latest version
var total = progressEvent.total || progressEvent.totalSize || 0,
current = progressEvent.loaded || progressEvent.position || 0;
if(progressEvent.lengthComputable) {
initDownload(total);
}
if(!cb) {
return;
}
if(current > total) {
// Opera 12 progress events has a bug - .loaded can be higher than .total
// see http://dev.opera.com/articles/view/xhr2/#comment-96081222
return;
}
updateDownload(current);
};
xhr.onprogress = ondownloadprogress;
}

@@ -576,13 +615,5 @@ /*

*/
var received = {
success: false,
status: false,
entity: false,
headers: false
};
var onHeadersReceived = function(lastTry) {
if(!cb) {
return;
}
var received = {};
var mustBeIdentity;
var tryHeadersAndStatus = function(lastTry) {
try {

@@ -612,2 +643,8 @@ if(xhr.status) {

}
try {
if(responseBodyLength(xhr.responseBody)) {
received.entity = true;
}
} catch(_) {
}

@@ -619,3 +656,3 @@ if(!statusCb) {

if(received.status || received.entity || received.success || lastTry) {
if(typeof xhr.contentType === 'string') {
if(typeof xhr.contentType === 'string' && xhr.contentType) {
if(xhr.contentType !== 'text/html' || xhr.responseText !== '') {

@@ -629,6 +666,8 @@ // When no entity body and/or no Content-Type header is sent,

}
for(var i = 0; i < exposedHeaders.length; i += 1) {
for(var i = 0; i < exposedHeaders.length; i++) {
var header;
try {
/* jshint boss:true */
if(header = xhr.getResponseHeader(exposedHeaders[i])) {
/* jshint boss:false */
outputHeaders[exposedHeaders[i].toLowerCase()] = header;

@@ -648,2 +687,7 @@ received.headers = true;

mustBeIdentity = outputHeaders['content-encoding'] === 'identity' || (!crossDomain && !outputHeaders['content-encoding']);
if(mustBeIdentity && 'content-length' in outputHeaders) {
outputLength = Number(outputHeaders['content-length']);
}
if(!status && (!crossDomain || httpinvoke.corsStatus)) {

@@ -667,9 +711,28 @@ // Sometimes on IE 9 accessing .status throws an error, but .statusText does not.

}
// IE (at least version 6) returns various detailed network
// connection error codes (concretely - WinInet Error Codes).
// For references of their meaning, see http://support.microsoft.com/kb/193625
if(status >= 12001 && status <= 12156) {
status = _undefined;
}
}
}
};
var onHeadersReceived = function(lastTry) {
if(!cb) {
return;
}
if(!lastTry && !(received.status && received.headers)) {
if(!lastTry) {
tryHeadersAndStatus(false);
}
if(!statusCb || (!lastTry && !(received.status && received.headers))) {
return;
}
if(inputLength === _undefined) {
inputLength = 0;
uploadProgress(0);
}
uploadProgress(inputLength);

@@ -681,3 +744,2 @@ if(!cb) {

statusCb(status, outputHeaders);
statusCb = null;
if(!cb) {

@@ -687,16 +749,9 @@ return;

if(method === 'HEAD') {
return noData();
}
updateDownload(0);
downloadProgressCb(0, outputLength, partial);
if(!cb) {
return;
}
if('content-length' in outputHeaders && (!crossDomain || 'content-encoding' in outputHeaders) && (!outputHeaders['content-encoding'] || outputHeaders['content-encoding'] === 'identity')) {
initDownload(Number(outputHeaders['content-length']));
if(!cb) {
return;
}
if(method === 'HEAD') {
downloadProgressCb(0, 0, partial);
return cb && cb(null, _undefined, status, outputHeaders);
}

@@ -709,27 +764,53 @@ };

onHeadersReceived(true);
if(!cb) {
return;
}
tryHeadersAndStatus(true);
if(!received.success && !status) {
// 'finished in onerror and status code is undefined'
cb(new Error('download error'));
cb = null;
return;
}
var length;
try {
length = getOutputLength(xhr);
length =
partialOutputMode !== 'disabled' ?
responseByteArrayLength(xhr) :
(
outputBinary ?
(
'response' in xhr ?
(
xhr.response ?
xhr.response.byteLength :
0
) :
responseByteArrayLength(xhr)
) :
countStringBytes(xhr.responseText)
);
} catch(_) {
return noData();
length = 0;
}
if(!outputLength) {
initDownload(length);
} else if(length !== outputLength) {
// 'output length ' + outputLength + ' is not equal to actually received entity length ' + length
cb(new Error('download error'));
cb = null;
if(outputLength !== _undefined) {
if(mustBeIdentity) {
if(length !== outputLength && method !== 'HEAD') {
return cb(new Error('network error'));
}
} else {
if(received.error) {
return cb(new Error('network error'));
}
}
} else {
outputLength = length;
}
var noentity = !received.entity && outputLength === 0 && outputHeaders['content-type'] === _undefined;
if((noentity && status === 200) || (!received.success && !status && (received.error || ('onreadystatechange' in xhr && !received.readyStateLOADING)))) {
/*
* Note: on Opera 10.50, TODO there is absolutely no difference
* between a non 2XX response and an immediate socket closing on
* server side - both give no headers, no status, no entity, and
* end up in 'onload' event. Thus some network errors will end
* up calling "finished" without Error.
*/
return cb(new Error('network error'));
}
onHeadersReceived(true);
if(!cb) {

@@ -739,3 +820,9 @@ return;

updateDownload(outputLength);
if(noentity) {
downloadProgressCb(0, 0, partial);
return cb(null, _undefined, status, outputHeaders);
}
partialUpdate();
downloadProgressCb(outputLength, outputLength, partial);
if(!cb) {

@@ -746,11 +833,21 @@ return;

try {
cb(null, !received.entity && outputLength === 0 && typeof outputHeaders['content-type'] === 'undefined' ? _undefined : outputConverter(getOutput(xhr)), status, outputHeaders);
// If XHR2 (there is xhr.response), then there must also be Uint8Array.
// But Uint8Array might exist even if not XHR2 (on Firefox 4).
cb(null, outputConverter(
partialBuffer || (
outputBinary ?
upgradeByteArray(
'response' in xhr ?
xhr.response || [] :
responseByteArray(xhr, [])
) :
xhr.responseText
)
), status, outputHeaders);
} catch(err) {
cb(err);
}
cb = null;
};
var onloadBound = false;
if(typeof xhr.onload !== 'undefined') {
onloadBound = true;
var onloadBound = 'onload' in xhr;
if(onloadBound) {
xhr.onload = function() {

@@ -762,3 +859,3 @@ received.success = true;

}
if(typeof xhr.onreadystatechange !== 'undefined') {
if('onreadystatechange' in xhr) {
xhr.onreadystatechange = function() {

@@ -771,11 +868,4 @@ //dbg('onreadystatechange ' + xhr.readyState);

// LOADING
received.success = true;
received.readyStateLOADING = true;
onHeadersReceived(false);
if(statusCb) {
return;
}
try {
updateDownload(getOutputLength(xhr));
} catch(err) {
}
// Instead of 'typeof xhr.onload === "undefined"', we must use

@@ -809,17 +899,20 @@ // onloadBound variable, because otherwise Firefox 3.5 synchronously

}
if('response' in xhr) {
if(outputBinary) {
try {
xhr.responseType = outputBinary ? 'arraybuffer' : 'text';
} catch(err) {
if(partialOutputMode === 'disabled' && 'response' in xhr) {
xhr.responseType = 'arraybuffer';
} else {
// mime type override must be done before receiving headers - at least for Safari 5.0.4
xhr.overrideMimeType('text/plain; charset=x-user-defined');
}
} catch(_) {
}
} else {
}
if(isFormData(input)) {
try {
// mime type override must be done before receiving headers - at least for Safari 5.0.4
if(outputBinary) {
xhr.overrideMimeType('text/plain; charset=x-user-defined');
}
xhr.send(input);
} catch(err) {
return failWithoutRequest(cb, new Error('Unable to send'));
}
}
if(typeof input === 'object') {
} else if(typeof input === 'object') {
var triedSendArrayBufferView = false;

@@ -863,10 +956,22 @@ var triedSendBlob = false;

} else {
inputLength = input.byteLength;
try {
inputLength = input.byteLength;
// if there is ArrayBufferView, then the browser supports sending instances of subclasses of ArayBufferView, otherwise we must send an ArrayBuffer
xhr.send(global.ArrayBufferView ? input : bufferSlice(input.buffer, input.byteOffset, input.byteOffset + input.byteLength));
xhr.send(
global.ArrayBufferView ?
input :
(
input.byteOffset === 0 && input.length === input.buffer.byteLength ?
input.buffer :
(
input.buffer.slice ?
input.buffer.slice(input.byteOffset, input.byteOffset + input.length) :
new Uint8Array([].slice.call(new Uint8Array(input.buffer), input.byteOffset, input.byteOffset + input.length)).buffer
)
)
);
return;
} catch(_) {
triedSendArrayBufferView = true;
}
triedSendArrayBufferView = true;
}

@@ -925,3 +1030,3 @@ } else if(global.Blob && input instanceof Blob) {

try {
input = binaryStringToByteArray(input);
input = binaryStringToByteArray(input, []);
} catch(_) {

@@ -946,2 +1051,3 @@ triedSendArrayBufferView = true;

go();
uploadProgress(0);
} else {

@@ -953,11 +1059,10 @@ try {

} else {
inputLength = 0;
xhr.send(null);
}
} catch(err) {
var _cb = cb;
cb = null;
return failWithoutRequest(cb, new Error('Unable to send'));
}
uploadProgress(0);
}
uploadProgress(0);
});

@@ -967,11 +1072,5 @@

promise = function() {
if(!cb) {
return;
}
// these statements are in case "abort" is called in "finished" callback
var _cb = cb;
cb = null;
_cb(new Error('abort'));
/* jshint expr:true */
cb && cb(new Error('abort'));
/* jshint expr:false */
try {

@@ -994,2 +1093,3 @@ xhr.abort();

httpinvoke.corsResponseTextOnly = false;
httpinvoke.corsFineGrainedTimeouts = true;
httpinvoke.requestTextOnly = false;

@@ -1002,3 +1102,3 @@ (function() {

var tmpxhr = createXHR();
httpinvoke.requestTextOnly = typeof Uint8Array === 'undefined' && typeof tmpxhr.sendAsBinary === 'undefined';
httpinvoke.requestTextOnly = !global.Uint8Array && !tmpxhr.sendAsBinary;
httpinvoke.cors = 'withCredentials' in tmpxhr;

@@ -1018,3 +1118,3 @@ if(httpinvoke.cors) {

try {
if(typeof XDomainRequest === 'undefined') {
if(global.XDomainRequest === _undefined) {
createXHR = function() {

@@ -1032,2 +1132,3 @@ return new XMLHttpRequest();

httpinvoke.corsResponseTextOnly = true;
httpinvoke.corsFineGrainedTimeouts = false;
}

@@ -1045,5 +1146,7 @@ return;

try {
/* jshint loopfunc:true */
createXHR = function() {
return new ActiveXObject(candidates[i]);
};
/* jshint loopfunc:true */
createXHR();

@@ -1054,8 +1157,15 @@ httpinvoke.requestTextOnly = true;

}
i -= 1;
}
createXHR = _undefined;
})();
httpinvoke.PATCH = !!(function() {
try {
createXHR().open('PATCH', location.href, true);
return 1;
} catch(_) {
}
})();
return httpinvoke;
}));
})
));

@@ -1,2 +0,2 @@

/*! httpinvoke 2013-10-09 */
!function(a,b){"function"==typeof define&&define.amd?define(b):"object"==typeof exports?module.exports=b():a.httpinvoke=b()}(this,function(){var a;a=window;var b,c,d,e=function(b){return"object"==typeof b&&null!==b&&(a.ArrayBufferView&&b instanceof ArrayBufferView||a.Int8Array&&b instanceof Int8Array||a.Uint8Array&&b instanceof Uint8Array||a.Uint8ClampedArray&&b instanceof Uint8ClampedArray||a.Int16Array&&b instanceof Int16Array||a.Uint16Array&&b instanceof Uint16Array||a.Int32Array&&b instanceof Int32Array||a.Uint32Array&&b instanceof Uint32Array||a.Float32Array&&b instanceof Float32Array||a.Float64Array&&b instanceof Float64Array)},f=function(a){return"[object Array]"===Object.prototype.toString.call(a)},g=function(b){return"object"==typeof b&&null!==b&&(a.Buffer&&b instanceof Buffer||a.Blob&&b instanceof Blob||a.File&&b instanceof File||a.ArrayBuffer&&b instanceof ArrayBuffer||e(b)||f(b))},h="an instance of Buffer, nor Blob, nor File, nor ArrayBuffer, nor ArrayBufferView, nor Int8Array, nor Uint8Array, nor Uint8ClampedArray, nor Int16Array, nor Uint16Array, nor Int32Array, nor Uint32Array, nor Float32Array, nor Float64Array, nor Array",i=",GET,HEAD,PATCH,POST,PUT,DELETE,",j=function(a){return a},k=a.process&&a.process.nextTick||a.setImmediate||a.setTimeout,l=function(){for(var a=arguments.length,b={};a--;)for(var c=arguments[a].split(","),d=c.length;d--;)b[c[d]]=100*(a+1)+d;return b}("Continue,Switching Protocols","OK,Created,Accepted,Non-Authoritative Information,No Content,Reset Content,Partial Content","Multiple Choices,Moved Permanently,Found,See Other,Not Modified,Use Proxy,_,Temporary Redirect","Bad Request,Unauthorized,Payment Required,Forbidden,Not Found,Method Not Allowed,Not Acceptable,Proxy Authentication Required,Request Timeout,Conflict,Gone,Length Required,Precondition Failed,Request Entity Too Large,Request-URI Too Long,Unsupported Media Type,Requested Range Not Satisfiable,Expectation Failed","Internal Server Error,Not Implemented,Bad Gateway,Service Unavailable,Gateway Time-out,HTTP Version Not Supported"),m=function(a,b,c){return 0===b&&c===a.byteLength?a:a.slice?a.slice(b,c):new Uint8Array(Array.prototype.slice.call(new Uint8Array(a),b,c)).buffer};try{execScript("Function httpinvoke0(B,A)\r\nDim i\r\nFor i=1 to LenB(B)\r\nA.push(AscB(MidB(B,i,1)))\r\nNext\r\nEnd Function\r\nFunction httpinvoke1(B)\r\nhttpinvoke1=LenB(B)\r\nEnd Function","vbscript"),c=function(a){var b=[];return httpinvoke0(a,b),b},d=function(a){return httpinvoke1(a)}}catch(n){}var o,p=function(a){return a.response||a.responseText},q=function(a){for(var b=a.length,c=new Array(b);b--;)c[b]=255&a.charCodeAt(b);return c},r=function(b){if("response"in b)return new Uint8Array(b.response||[]);if("responseBody"in b)return c(b.responseBody);var d=q(b.responseText);return a.Uint8Array?new a.Uint8Array(d):d},s=function(a){return u(p(a))},t=function(a){return"response"in a?a.response?a.response.byteLength:0:"responseBody"in a?d(a.responseBody):a.responseText.length},u=function(a){for(var b,c=0,d=a.length;d--;)b=a.charCodeAt(d),c+=128>b?1:2048>b?2:3;return c},v=function(a,b){for(var c,d=a.getAllResponseHeaders().split(/\r?\n/),e=!1,f=d.length;f--;)(c=d[f].indexOf(":"))>=0&&(b[d[f].substr(0,c).toLowerCase()]=d[f].substr(c+2),e=!0);return e},w=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,x=function(a,b){return b=w.exec(b.toLowerCase()),a=w.exec(a.toLowerCase())||[],!(!b||b[1]===a[1]&&b[2]===a[2]&&(b[3]||("http:"===b[1]?"80":"443"))===(a[3]||("http:"===a[1]?"80":"443")))},y=function(c,d,n,w){var z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q;d?n?w?n.finished=w:"object"==typeof d?(d.finished=n,n=d,d="GET"):"function"==typeof n&&(n={finished:n}):"string"==typeof d?n={}:"object"==typeof d?(n=d,d="GET"):(n={finished:d},d="GET"):(d="GET",n={});var R=function(a,b){return a in n?function(c,d,e,f){try{n[a](c,d,e,f)}catch(g){}b(c,d,e,f)}:b},S=function(a,b){a&&a.then&&a.then(function(){b[T].apply(null,arguments)},function(){b[U].apply(null,arguments)},function(){b[V].apply(null,arguments)})},T=0,U=1,V=2;z=function(a){var b,c=[],d=V,e=function(e){a[e]=function(a){var f,g;if(c){for(b=a,d=e,f=0;f<c.length;f++)if("function"==typeof c[f][d])try{g=c[f][d].call(null,b),V>d&&S(g,c[f]._)}catch(h){c[f]._[U](h)}else V>d&&c[f]._[d](b);V>d&&(c=null)}}};return e(V),e(T),e(U),a.then=function(){var a=[].slice.call(arguments);return a._=z({}),c?c.push(a):"function"==typeof a[d]&&k(function(){S(a[d](b),a._)}),a._},a},B=function(a,b){return k(function(){null!==a&&a(b)}),A=function(){},z(A)},C=R("uploading",function(a,b){A[V]({type:"upload",current:a,total:b})});var W=R("downloading",function(a,b){A[V]({type:"download",current:a,total:b})});H=R("gotStatus",function(a,b){A[V]({type:"headers",statusCode:a,headers:b})}),w=R("finished",function(a,b,c,d){return a?A[U](a):(A[T]({body:b,statusCode:c,headers:d}),void 0)}),F=n.timeout||0;var X,Y=n.converters||{};if(D=0,G=n.headers||{},K={},L=n.corsExposedHeaders||[],L.push.apply(L,["Cache-Control","Content-Language","Content-Type","Content-Length","Expires","Last-Modified","Pragma","Content-Range"]),d.indexOf(",")>=0||i.indexOf(","+d+",")<0)return B(w,new Error("Unsupported method "+d));if(N="bytearray"===n.outputType,!n.outputType||"text"===n.outputType||N)Q=j;else if(Y["text "+n.outputType])Q=Y["text "+n.outputType],N=!1;else{if(!Y["bytearray "+n.outputType])return B(w,new Error("Unsupported outputType "+n.outputType));Q=Y["bytearray "+n.outputType],N=!0}if(X=j,"input"in n){if(O=n.input,n.inputType&&"auto"!==n.inputType)if("text"===n.inputType){if("string"!=typeof O)return B(w,new Error("inputType is text, but input is not a string"))}else if("bytearray"===n.inputType){if(!g(O))return B(w,new Error("inputType is bytearray, but input is neither "+h))}else if(Y[n.inputType+" text"])X=Y[n.inputType+" text"];else{if(!Y[n.inputType+" bytearray"])return B(w,new Error("There is no converter for specified inputType"));X=Y[n.inputType+" bytearray"]}else if("string"!=typeof O&&!g(O))return B(w,new Error("inputType is undefined or auto and input is neither string, nor "+h));"object"==typeof O&&(a.ArrayBuffer&&O instanceof ArrayBuffer?O=new Uint8Array(O):e(O)&&(O=new Uint8Array(O.buffer,O.byteOffset,O.byteLength)));try{O=X(O)}catch(Z){return B(w,Z)}}else{if(n.inputType)return B(w,new Error('"input" is undefined, but inputType is defined'));if(G["Content-Type"])return B(w,new Error('"input" is undefined, but Content-Type request header is defined'))}var $;I=function(a){"undefined"==typeof P&&W($,P=a)},J=function(a){a!==$&&W($=a,P)},E=function(){I(0),w&&(w(null,b,M,K),w=null)};var _,ab,bb,cb,db,eb=N?r:p,fb=N?t:s,gb=!1,hb=function(a){C&&(gb||(gb=!0,C(0,D),w))&&(C(a,D),a===D&&(C=null))};try{cb=location.href}catch(ib){cb=document.createElement("a"),cb.href="",cb=cb.href}if(db=x(cb,c),"object"==typeof O&&y.requestTextOnly)return B(w,new Error("bytearray inputType is not supported on this platform, please always test using requestTextOnly feature flag"));if(db&&!y.cors)return B(w,new Error("Cross-origin requests are not supported"));for(bb=["DELETE","PATCH","PUT","HEAD"],ab=bb.length;ab-->0;)if(db&&d===bb[ab]&&!y["cors"+bb[ab]])return B(w,new Error(bb[ab]+" method in cross-origin requests is not supported in this browser"));if(!o)return B(w,new Error("unable to construct XMLHttpRequest object"));_=o(db),_.open(d,c,!0),F>0&&("timeout"in _?_.timeout=F:setTimeout(function(){w(new Error("download timeout")),w=null},F)),n.corsCredentials&&y.corsCredentials&&"boolean"==typeof _.withCredentials&&(_.withCredentials=!0),db&&n.corsOriginHeader&&(G[n.corsOriginHeader]=location.protocol+"//"+location.host);var jb=function(a){return function(){w&&(w(new Error(a)),w=null)}},kb=function(a){w&&a.lengthComputable&&hb(a.loaded)};"upload"in _?(_.upload.ontimeout=jb("upload timeout"),_.upload.onerror=jb("upload error"),_.upload.onprogress=kb):"onuploadprogress"in _&&(_.onuploadprogress=kb),"ontimeout"in _&&(_.ontimeout=jb("download timeout")),"onerror"in _&&(_.onerror=function(){nb()}),"onloadstart"in _&&(_.onloadstart=function(){mb(!1)}),"onloadend"in _&&(_.onloadend=function(){mb(!1)}),"onprogress"in _&&(_.onprogress=function(a){if(w&&(mb(!1),!H)){var b=a.total||a.totalSize||0,c=a.loaded||a.position||0;a.lengthComputable&&I(b),w&&(c>b||J(c))}});var lb={success:!1,status:!1,entity:!1,headers:!1},mb=function(a){if(w){try{_.status&&(lb.status=!0)}catch(b){}try{_.statusText&&(lb.status=!0)}catch(b){}try{_.responseText&&(lb.entity=!0)}catch(b){}try{_.response&&(lb.entity=!0)}catch(b){}if(H){if(lb.status||lb.entity||lb.success||a){"string"==typeof _.contentType&&("text/html"!==_.contentType||""!==_.responseText)&&(K["content-type"]=_.contentType,lb.headers=!0);for(var c=0;c<L.length;c+=1){var e;try{(e=_.getResponseHeader(L[c]))&&(K[L[c].toLowerCase()]=e,lb.headers=!0)}catch(f){}}try{v(_,K)&&(lb.headers=!0)}catch(f){}if(!M&&(!db||y.corsStatus)){try{_.status&&(M=_.status)}catch(b){}if(!M)try{M=l[_.statusText]}catch(b){}1223===M&&(M=204)}}if((a||lb.status&&lb.headers)&&(hb(D),w&&(H(M,K),H=null,w))){if("HEAD"===d)return E();J(0),w&&"content-length"in K&&(!db||"content-encoding"in K)&&(!K["content-encoding"]||"identity"===K["content-encoding"])&&(I(Number(K["content-length"])),!w)}}}},nb=function(){if(w&&(mb(!0),w)){if(!lb.success&&!M)return w(new Error("download error")),w=null,void 0;var a;try{a=fb(_)}catch(c){return E()}if(P?a!==P&&(w(new Error("download error")),w=null):I(a),w&&(J(P),w)){try{w(null,lb.entity||0!==P||"undefined"!=typeof K["content-type"]?Q(eb(_)):b,M,K)}catch(d){w(d)}w=null}}},ob=!1;if("undefined"!=typeof _.onload&&(ob=!0,_.onload=function(){lb.success=!0,nb()}),"undefined"!=typeof _.onreadystatechange&&(_.onreadystatechange=function(){if(2===_.readyState)mb(!1);else if(3===_.readyState){if(lb.success=!0,mb(!1),H)return;try{J(fb(_))}catch(a){}}else 4!==_.readyState||ob||nb()}),!db||y.corsRequestHeaders)for(var pb in G)if(G.hasOwnProperty(pb))try{_.setRequestHeader(pb,G[pb])}catch(Z){return B(w,Z)}return k(function(){if(w){if("response"in _)try{_.responseType=N?"arraybuffer":"text"}catch(b){}else try{N&&_.overrideMimeType("text/plain; charset=x-user-defined")}catch(b){}if("object"==typeof O){var c=!1,d=!1,g=!1,h=a.BlobBuilder||a.WebKitBlobBuilder||a.MozBlobBuilder||a.MSBlobBuilder;f(O)&&(O=a.Uint8Array?new Uint8Array(O):String.fromCharCode.apply(String,O));var i=h?function(){var a=new h;a.append(O),O=a.getBlob(G["Content-Type"]||"application/octet-stream")}:function(){try{O=new Blob([O],{type:G["Content-Type"]||"application/octet-stream"})}catch(a){d=!0}},j=function(){var b;if(d&&c&&g)return B(w,new Error("Unable to send"));if(e(O))if(c)if(g)d||i();else try{O=String.fromCharCode.apply(String,O)}catch(f){g=!0}else try{return D=O.byteLength,_.send(a.ArrayBufferView?O:m(O.buffer,O.byteOffset,O.byteOffset+O.byteLength)),void 0}catch(f){c=!0}else if(a.Blob&&O instanceof Blob)if(d)if(c){if(!g)try{return b=new FileReader,b.onerror=function(){g=!0,j()},b.onload=function(){O=b.result,j()},b.readAsBinaryString(O),void 0}catch(f){g=!0}}else try{return b=new FileReader,b.onerror=function(){c=!0,j()},b.onload=function(){try{O=new Uint8Array(b.result)}catch(a){c=!0}j()},b.readAsArrayBuffer(O),void 0}catch(f){c=!0}else try{return D=O.size,_.send(O),void 0}catch(f){d=!0}else if(g)if(c)d||i();else try{O=q(O)}catch(f){c=!0}else try{return D=O.length,_.sendAsBinary(O),void 0}catch(f){g=!0}k(j)};j()}else try{"string"==typeof O?(D=u(O),_.send(O)):_.send(null)}catch(b){return w=null,B(w,new Error("Unable to send"))}hb(0)}}),A=function(){if(w){var a=w;w=null,a(new Error("abort"));try{_.abort()}catch(b){}}},z(A)};return y.corsResponseContentTypeOnly=!1,y.corsRequestHeaders=!1,y.corsCredentials=!1,y.cors=!1,y.corsDELETE=!1,y.corsHEAD=!1,y.corsPATCH=!1,y.corsPUT=!1,y.corsStatus=!1,y.corsResponseTextOnly=!1,y.requestTextOnly=!1,function(){try{o=function(){return new XMLHttpRequest};var a=o();if(y.requestTextOnly="undefined"==typeof Uint8Array&&"undefined"==typeof a.sendAsBinary,y.cors="withCredentials"in a,y.cors)return y.corsRequestHeaders=!0,y.corsCredentials=!0,y.corsDELETE=!0,y.corsPATCH=!0,y.corsPUT=!0,y.corsHEAD=!0,y.corsStatus=!0,void 0}catch(c){}try{return"undefined"==typeof XDomainRequest?(o=function(){return new XMLHttpRequest},o()):(o=function(a){return a?new XDomainRequest:new XMLHttpRequest},o(!0),y.cors=!0,y.corsResponseContentTypeOnly=!0,y.corsResponseTextOnly=!0),void 0}catch(c){}try{return o(),void 0}catch(c){}for(var d=["Microsoft.XMLHTTP","Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.3.0","Msxml2.XMLHTTP"],e=d.length;e--;){try{return o=function(){return new ActiveXObject(d[e])},o(),y.requestTextOnly=!0,void 0}catch(c){}e-=1}o=b}(),y});
/*! httpinvoke 2013-12-10 */
!function(a,b){"function"==typeof define&&define.amd?define(b):"object"==typeof exports?module.exports=b():a.httpinvoke=b()}(this,function(){"use strict";var a;a=window;var b,c,d,e=0,f=1,g=2,h=function(a,b){a&&a.then&&a.then(function(){b[e].apply(null,arguments)},function(){b[f].apply(null,arguments)},function(){b[g].apply(null,arguments)})},i=a.process&&a.process.nextTick||a.setImmediate||a.setTimeout,j=function(a){var b,c=[],d=g,k=function(e){a[e]=function(a){var i,j;if(c){for(b=a,d=e,i=0;i<c.length;i++)if("function"==typeof c[i][d])try{j=c[i][d].call(null,b),g>d&&h(j,c[i]._)}catch(k){c[i]._[f](k)}else g>d&&c[i]._[d](b);g>d&&(c=null)}}};return k(g),k(e),k(f),a.then=function(){var a=[].slice.call(arguments);return a._=j({}),c?c.push(a):"function"==typeof a[d]&&i(function(){h(a[d](b),a._)}),a._},a},k=function(b){return"object"==typeof b&&null!==b&&(a.ArrayBufferView&&b instanceof ArrayBufferView||a.Int8Array&&b instanceof Int8Array||a.Uint8Array&&b instanceof Uint8Array||a.Uint8ClampedArray&&b instanceof Uint8ClampedArray||a.Int16Array&&b instanceof Int16Array||a.Uint16Array&&b instanceof Uint16Array||a.Int32Array&&b instanceof Int32Array||a.Uint32Array&&b instanceof Uint32Array||a.Float32Array&&b instanceof Float32Array||a.Float64Array&&b instanceof Float64Array)},l=function(a){return"[object Array]"===Object.prototype.toString.call(a)},m=function(b){return"object"==typeof b&&null!==b&&a.FormData&&b instanceof a.FormData},n=function(b){return"object"==typeof b&&null!==b&&(a.Buffer&&b instanceof Buffer||a.Blob&&b instanceof Blob||a.File&&b instanceof File||a.ArrayBuffer&&b instanceof ArrayBuffer||k(b)||l(b))},o="an instance of Buffer, nor Blob, nor File, nor ArrayBuffer, nor ArrayBufferView, nor Int8Array, nor Uint8Array, nor Uint8ClampedArray, nor Int16Array, nor Uint16Array, nor Int32Array, nor Uint32Array, nor Float32Array, nor Float64Array, nor Array",p=",GET,HEAD,PATCH,POST,PUT,DELETE,",q=function(a){return a},r=function(){for(var a=arguments.length,b={};a--;)for(var c=arguments[a].split(","),d=c.length;d--;)b[c[d]]=100*(a+1)+d;return b}("Continue,Switching Protocols","OK,Created,Accepted,Non-Authoritative Information,No Content,Reset Content,Partial Content","Multiple Choices,Moved Permanently,Found,See Other,Not Modified,Use Proxy,_,Temporary Redirect","Bad Request,Unauthorized,Payment Required,Forbidden,Not Found,Method Not Allowed,Not Acceptable,Proxy Authentication Required,Request Timeout,Conflict,Gone,Length Required,Precondition Failed,Request Entity Too Large,Request-URI Too Long,Unsupported Media Type,Requested Range Not Satisfiable,Expectation Failed","Internal Server Error,Not Implemented,Bad Gateway,Service Unavailable,Gateway Time-out,HTTP Version Not Supported"),s=a.Uint8Array?function(a){return new Uint8Array(a)}:q,t=function(a,b){for(var c=b.length;c<a.length;)b.push(255&a.charCodeAt(c++));return b},u=function(a){for(var b,c=0,d=a.length;d--;)b=a.charCodeAt(d),c+=128>b?1:2048>b?2:3;return c};try{execScript("Function httpinvoke0(B,A,C)\r\nDim i\r\nFor i=C to LenB(B)\r\nA.push(AscB(MidB(B,i,1)))\r\nNext\r\nEnd Function\r\nFunction httpinvoke1(B)\r\nhttpinvoke1=LenB(B)\r\nEnd Function","vbscript"),c=function(a,b){return httpinvoke0(a,b,b.length+1),b},d=function(a){return httpinvoke1(a)}}catch(v){}var w,x=function(a,b){return"responseBody"in a&&c?c(a.responseBody,b):t(a.responseText,b)},y=function(a){return"responseBody"in a&&d?d(a.responseBody):a.responseText.length},z=function(a,b){for(var c,d=a.getAllResponseHeaders().split(/\r?\n/),e=!1,f=d.length;f--;)(c=d[f].indexOf(":"))>=0&&(b[d[f].substr(0,c).toLowerCase()]=d[f].substr(c+2),e=!0);return e},A=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,B=function(a,b){return b=A.exec(b.toLowerCase()),a=A.exec(a.toLowerCase())||[],!(!b||b[1]===a[1]&&b[2]===a[2]&&(b[3]||("http:"===b[1]?"80":"443"))===(a[3]||("http:"===a[1]?"80":"443")))},C=function(c,h,v,A){var D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T;h?v?A?v.finished=A:"object"==typeof h?(h.finished=v,v=h,h="GET"):"function"==typeof v&&(v={finished:v}):"string"==typeof h?v={}:"object"==typeof h?(v=h,h="GET"):(v={finished:h},h="GET"):(h="GET",v={});var U=function(a,b,c){return function(d,e,f,g){b(d,e,f,g);try{v[a](d,e,f,g)}catch(h){}c(d,e,f,g)}};E=function(a,b){return i(function(){null!==a&&a(b)}),D=function(){},j(D)},F=U("uploading",q,function(a,b){D[g]({type:"upload",current:a,total:b})}),G=U("downloading",q,function(a,b,c){D[g]({type:"download",current:a,total:b,partial:c})}),J=U("gotStatus",function(){J=null,R&&setTimeout(function(){A&&(A(new Error("download timeout")),D())},R)},function(a,b){D[g]({type:"headers",statusCode:a,headers:b})}),A=U("finished",function(){A=null,D()},function(a,b,c,d){return a?D[f](a):(D[e]({body:b,statusCode:c,headers:d}),void 0)});var V,W=v.converters||{};I=v.headers||{},K={},L=v.corsExposedHeaders||[],L.push.apply(L,["Cache-Control","Content-Language","Content-Type","Content-Length","Expires","Last-Modified","Pragma","Content-Range","Content-Encoding"]);var X=v.partialOutputMode||"disabled";if(X.indexOf(",")>=0||",disabled,chunked,joined,".indexOf(","+X+",")<0)return E(A,new Error('Option "partialOutputMode" is neither "disabled", nor "chunked", nor "joined"'));if(h.indexOf(",")>=0||p.indexOf(","+h+",")<0)return E(A,new Error("Unsupported method "+h));var Y=v.outputType;if(N="bytearray"===Y,!Y||"text"===Y||N)Q=q;else if(W["text "+Y])Q=W["text "+Y],N=!1;else{if(!W["bytearray "+Y])return E(A,new Error("Unsupported outputType "+Y));Q=W["bytearray "+Y],N=!0}V=q;var Z=v.inputType;if(O=v.input,O!==b){if(Z&&"auto"!==Z)if("text"===Z){if("string"!=typeof O)return E(A,new Error("inputType is text, but input is not a string"))}else if("formdata"===Z){if(!m(O))return E(A,new Error("inputType is formdata, but input is not an instance of FormData"))}else if("bytearray"===Z){if(!n(O))return E(A,new Error("inputType is bytearray, but input is neither "+o))}else if(W[Z+" text"])V=W[Z+" text"];else if(W[Z+" bytearray"])V=W[Z+" bytearray"];else{if(!W[Z+" formdata"])return E(A,new Error("There is no converter for specified inputType"));V=W[Z+" formdata"]}else if("string"!=typeof O&&!n(O)&&!m(O))return E(A,new Error("inputType is undefined or auto and input is neither string, nor FormData, nor "+o));"object"!=typeof O||m(O)||(a.ArrayBuffer&&O instanceof a.ArrayBuffer?O=new a.Uint8Array(O):k(O)&&(O=new a.Uint8Array(O.buffer,O.byteOffset,O.byteLength)));try{O=V(O)}catch($){return E(A,$)}}else{if(Z&&"auto"!==Z)return E(A,new Error('"input" is undefined, but inputType is defined'));if(I["Content-Type"])return E(A,new Error('"input" is undefined, but Content-Type request header is defined'))}var _=function(a){return a>0&&1073741824>a},ab=v.timeout;if(ab!==b)if("number"==typeof ab&&_(ab))T=ab;else{if(!(l(ab)&&2===ab.length&&_(ab[0])&&_(ab[1])))return E(A,new Error('"timeout" value is not valid'));C.corsFineGrainedTimeouts||!fb?(S=ab[0],R=ab[1]):T=ab[0]+ab[1]}S&&setTimeout(function(){J&&(A(new Error("upload timeout")),D())},S),T&&setTimeout(function(){A&&(A(new Error("timeout")),D())},T);var bb,cb,db,eb,fb,gb=!1,hb=0,ib="disabled"===X?b:N?[]:"",jb=ib,kb=function(){"disabled"!==X&&(N?x(bb,ib):ib=bb.responseText,jb="joined"===X?ib:ib.slice(hb),hb=ib.length)},lb=function(a){F&&(gb||(gb=!0,F(0,H),A))&&(F(a,H),a===H&&(F=null))};try{eb=location.href}catch(mb){eb=document.createElement("a"),eb.href="",eb=eb.href}if(fb=B(eb,c),"object"==typeof O&&!m(O)&&C.requestTextOnly)return E(A,new Error("bytearray inputType is not supported on this platform, please always test using requestTextOnly feature flag - hint - you may want to try sending FormData (formdata type)"));if(fb&&!C.cors)return E(A,new Error("Cross-origin requests are not supported"));for(db=["DELETE","PATCH","PUT","HEAD"],cb=db.length;cb-->0;)if(fb&&h===db[cb]&&!C["cors"+db[cb]])return E(A,new Error(db[cb]+" method in cross-origin requests is not supported in this browser"));if("PATCH"===h&&!C.PATCH)return E(A,new Error("PATCH method is not supported in this browser"));if(!w)return E(A,new Error("unable to construct XMLHttpRequest object"));bb=w(fb);try{bb.open(h,c,!0)}catch(nb){return E(A,nb)}v.corsCredentials&&C.corsCredentials&&"boolean"==typeof bb.withCredentials&&(bb.withCredentials=!0),fb&&v.corsOriginHeader&&(I[v.corsOriginHeader]=location.protocol+"//"+location.host);var ob=function(a){A&&a.lengthComputable&&(H===b&&(H=a.total||a.totalSize||0,lb(0)),lb(a.loaded||a.position||0))};"upload"in bb?(bb.upload.onerror=function(){rb.error=!0,A&&A(new Error("network error"))},bb.upload.onprogress=ob):"onuploadprogress"in bb&&(bb.onuploadprogress=ob),"onerror"in bb&&(bb.onerror=function(){rb.error=!0,ub()});var pb=function(a){tb(!1);try{var b=a.loaded||a.position||0;a.lengthComputable&&(P=a.total||a.totalSize||0),A&&P>=b&&!J&&(kb(),G(b,P,jb))}catch(c){}};"onloadstart"in bb&&(bb.onloadstart=pb),"onloadend"in bb&&(bb.onloadend=pb),"onprogress"in bb&&(bb.onprogress=pb);var qb,rb={},sb=function(a){try{bb.status&&(rb.status=!0)}catch(c){}try{bb.statusText&&(rb.status=!0)}catch(c){}try{bb.responseText&&(rb.entity=!0)}catch(c){}try{bb.response&&(rb.entity=!0)}catch(c){}try{d(bb.responseBody)&&(rb.entity=!0)}catch(c){}if(J&&(rb.status||rb.entity||rb.success||a)){"string"==typeof bb.contentType&&bb.contentType&&("text/html"!==bb.contentType||""!==bb.responseText)&&(K["content-type"]=bb.contentType,rb.headers=!0);for(var e=0;e<L.length;e++){var f;try{(f=bb.getResponseHeader(L[e]))&&(K[L[e].toLowerCase()]=f,rb.headers=!0)}catch(g){}}try{z(bb,K)&&(rb.headers=!0)}catch(g){}if(qb="identity"===K["content-encoding"]||!fb&&!K["content-encoding"],qb&&"content-length"in K&&(P=Number(K["content-length"])),!M&&(!fb||C.corsStatus)){try{bb.status&&(M=bb.status)}catch(c){}if(!M)try{M=r[bb.statusText]}catch(c){}1223===M&&(M=204),M>=12001&&12156>=M&&(M=b)}}},tb=function(a){return A&&(a||sb(!1),J&&(a||rb.status&&rb.headers)&&(H===b&&(H=0,lb(0)),lb(H),A&&(J(M,K),A&&(G(0,P,jb),A))))?"HEAD"===h?(G(0,0,jb),A&&A(null,b,M,K)):void 0:void 0},ub=function(){if(A){sb(!0);var a;try{a="disabled"!==X?y(bb):N?"response"in bb?bb.response?bb.response.byteLength:0:y(bb):u(bb.responseText)}catch(c){a=0}if(P!==b){if(qb){if(a!==P&&"HEAD"!==h)return A(new Error("network error"))}else if(rb.error)return A(new Error("network error"))}else P=a;var d=!rb.entity&&0===P&&K["content-type"]===b;if(d&&200===M||!rb.success&&!M&&(rb.error||"onreadystatechange"in bb&&!rb.readyStateLOADING))return A(new Error("network error"));if(tb(!0),A){if(d)return G(0,0,jb),A(null,b,M,K);if(kb(),G(P,P,jb),A)try{A(null,Q(ib||(N?s("response"in bb?bb.response||[]:x(bb,[])):bb.responseText)),M,K)}catch(e){A(e)}}}},vb="onload"in bb;if(vb&&(bb.onload=function(){rb.success=!0,ub()}),"onreadystatechange"in bb&&(bb.onreadystatechange=function(){2===bb.readyState?tb(!1):3===bb.readyState?(rb.readyStateLOADING=!0,tb(!1)):4!==bb.readyState||vb||ub()}),!fb||C.corsRequestHeaders)for(var wb in I)if(I.hasOwnProperty(wb))try{bb.setRequestHeader(wb,I[wb])}catch($){return E(A,$)}return i(function(){if(A){if(N)try{"disabled"===X&&"response"in bb?bb.responseType="arraybuffer":bb.overrideMimeType("text/plain; charset=x-user-defined")}catch(b){}if(m(O))try{bb.send(O)}catch(c){return E(A,new Error("Unable to send"))}else if("object"==typeof O){var d=!1,e=!1,f=!1,g=a.BlobBuilder||a.WebKitBlobBuilder||a.MozBlobBuilder||a.MSBlobBuilder;l(O)&&(O=a.Uint8Array?new Uint8Array(O):String.fromCharCode.apply(String,O));var h=g?function(){var a=new g;a.append(O),O=a.getBlob(I["Content-Type"]||"application/octet-stream")}:function(){try{O=new Blob([O],{type:I["Content-Type"]||"application/octet-stream"})}catch(a){e=!0}},j=function(){var b;if(e&&d&&f)return E(A,new Error("Unable to send"));if(k(O))if(d)if(f)e||h();else try{O=String.fromCharCode.apply(String,O)}catch(c){f=!0}else{H=O.byteLength;try{return bb.send(a.ArrayBufferView?O:0===O.byteOffset&&O.length===O.buffer.byteLength?O.buffer:O.buffer.slice?O.buffer.slice(O.byteOffset,O.byteOffset+O.length):new Uint8Array([].slice.call(new Uint8Array(O.buffer),O.byteOffset,O.byteOffset+O.length)).buffer),void 0}catch(c){}d=!0}else if(a.Blob&&O instanceof Blob)if(e)if(d){if(!f)try{return b=new FileReader,b.onerror=function(){f=!0,j()},b.onload=function(){O=b.result,j()},b.readAsBinaryString(O),void 0}catch(c){f=!0}}else try{return b=new FileReader,b.onerror=function(){d=!0,j()},b.onload=function(){try{O=new Uint8Array(b.result)}catch(a){d=!0}j()},b.readAsArrayBuffer(O),void 0}catch(c){d=!0}else try{return H=O.size,bb.send(O),void 0}catch(c){e=!0}else if(f)if(d)e||h();else try{O=t(O,[])}catch(c){d=!0}else try{return H=O.length,bb.sendAsBinary(O),void 0}catch(c){f=!0}i(j)};j(),lb(0)}else{try{"string"==typeof O?(H=u(O),bb.send(O)):(H=0,bb.send(null))}catch(c){return E(A,new Error("Unable to send"))}lb(0)}}}),D=function(){A&&A(new Error("abort"));try{bb.abort()}catch(a){}},j(D)};return C.corsResponseContentTypeOnly=!1,C.corsRequestHeaders=!1,C.corsCredentials=!1,C.cors=!1,C.corsDELETE=!1,C.corsHEAD=!1,C.corsPATCH=!1,C.corsPUT=!1,C.corsStatus=!1,C.corsResponseTextOnly=!1,C.corsFineGrainedTimeouts=!0,C.requestTextOnly=!1,function(){try{w=function(){return new XMLHttpRequest};var c=w();if(C.requestTextOnly=!a.Uint8Array&&!c.sendAsBinary,C.cors="withCredentials"in c,C.cors)return C.corsRequestHeaders=!0,C.corsCredentials=!0,C.corsDELETE=!0,C.corsPATCH=!0,C.corsPUT=!0,C.corsHEAD=!0,C.corsStatus=!0,void 0}catch(d){}try{return a.XDomainRequest===b?(w=function(){return new XMLHttpRequest},w()):(w=function(a){return a?new XDomainRequest:new XMLHttpRequest},w(!0),C.cors=!0,C.corsResponseContentTypeOnly=!0,C.corsResponseTextOnly=!0,C.corsFineGrainedTimeouts=!1),void 0}catch(d){}try{return w(),void 0}catch(d){}for(var e=["Microsoft.XMLHTTP","Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.3.0","Msxml2.XMLHTTP"],f=e.length;f--;)try{return w=function(){return new ActiveXObject(e[f])},w(),C.requestTextOnly=!0,void 0}catch(d){}w=b}(),C.PATCH=!!function(){try{return w().open("PATCH",location.href,!0),1}catch(a){}}(),C});

@@ -5,3 +5,59 @@ var http = require('http');

;;var isArrayBufferView = function(input) {
/* jshint unused:true */
;;var resolve = 0, reject = 1, progress = 2, chain = function(a, b) {
/* jshint expr:true */
a && a.then && a.then(function() {
b[resolve].apply(null, arguments);
}, function() {
b[reject].apply(null, arguments);
}, function() {
b[progress].apply(null, arguments);
});
/* jshint expr:false */
}, nextTick = (global.process && global.process.nextTick) || global.setImmediate || global.setTimeout, mixInPromise = function(o) {
var value, queue = [], state = progress;
var makeState = function(newstate) {
o[newstate] = function(newvalue) {
var i, p;
if(queue) {
value = newvalue;
state = newstate;
for(i = 0; i < queue.length; i++) {
if(typeof queue[i][state] === 'function') {
try {
p = queue[i][state].call(null, value);
if(state < progress) {
chain(p, queue[i]._);
}
} catch(err) {
queue[i]._[reject](err);
}
} else if(state < progress) {
queue[i]._[state](value);
}
}
if(state < progress) {
queue = null;
}
}
};
};
makeState(progress);
makeState(resolve);
makeState(reject);
o.then = function() {
var item = [].slice.call(arguments);
item._ = mixInPromise({});
if(queue) {
queue.push(item);
} else if(typeof item[state] === 'function') {
nextTick(function() {
chain(item[state](value), item._);
});
}
return item._;
};
return o;
}, isArrayBufferView = /* jshint undef:false */function(input) {
return typeof input === 'object' && input !== null && (

@@ -19,5 +75,8 @@ (global.ArrayBufferView && input instanceof ArrayBufferView) ||

);
}, isArray = function(object) {
}/* jshint undef:true */, isArray = function(object) {
return Object.prototype.toString.call(object) === '[object Array]';
}, isByteArray = function(input) {
}, isFormData = function(input) {
return typeof input === 'object' && input !== null && global.FormData &&
input instanceof global.FormData;
}, isByteArray = /* jshint undef:false */function(input) {
return typeof input === 'object' && input !== null && (

@@ -31,31 +90,12 @@ (global.Buffer && input instanceof Buffer) ||

);
}, bytearrayMessage = 'an instance of Buffer, nor Blob, nor File, nor ArrayBuffer, nor ArrayBufferView, nor Int8Array, nor Uint8Array, nor Uint8ClampedArray, nor Int16Array, nor Uint16Array, nor Int32Array, nor Uint32Array, nor Float32Array, nor Float64Array, nor Array', supportedMethods = ',GET,HEAD,PATCH,POST,PUT,DELETE,', pass = function(value) {
}/* jshint undef:true */, bytearrayMessage = 'an instance of Buffer, nor Blob, nor File, nor ArrayBuffer, nor ArrayBufferView, nor Int8Array, nor Uint8Array, nor Uint8ClampedArray, nor Int16Array, nor Uint16Array, nor Int32Array, nor Uint32Array, nor Float32Array, nor Float64Array, nor Array', supportedMethods = ',GET,HEAD,PATCH,POST,PUT,DELETE,', pass = function(value) {
return value;
}, nextTick = (global.process && global.process.nextTick) || global.setImmediate || global.setTimeout, _undefined;
}, _undefined;
;
/* jshint unused:false */
var decompress = function(output, encoding, cb) {
if(encoding === 'gzip') {
zlib.gunzip(output, cb);
} else if(encoding === 'deflate') {
zlib.inflate(output, function(err, out) {
if(err) {
return zlib.inflateRaw(output, cb);
}
cb(null, out);
});
} else if(encoding === 'identity') {
process.nextTick(function() {
cb(null, output);
});
} else {
process.nextTick(function() {
cb(new Error('unsupported encoding ' + encoding));
});
}
};
// http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method
var forbiddenInputHeaders = ['accept-charset', 'accept-encoding', 'access-control-request-headers', 'access-control-request-method', 'connection', 'content-length', 'content-transfer-encoding', 'cookie', 'cookie2', 'date', 'dnt', 'expect', 'host', 'keep-alive', 'origin', 'referer', 'te', 'trailer', 'transfer-encoding', 'upgrade', 'user-agent', 'via'];
var validateInputHeaders = function(headers) {
'use strict';
for(var header in headers) {

@@ -78,2 +118,3 @@ if(headers.hasOwnProperty(header)) {

var copy = function(from, to) {
'use strict';
Object.keys(from).forEach(function(key) {

@@ -85,5 +126,37 @@ to[key] = from[key];

var emptyBuffer = new Buffer([]);
var utf8CharacterSizeFromHeaderByte = function(b) {
'use strict';
if(b < 128) {
// one byte, ascii character
return 1;
}
/* jshint bitwise:false */
var mask = (1 << 7) | (1 << 6);
var test = 128;
if((b & mask) === test) {
// b is not a header byte
return 0;
}
for(var length = 1; (b & mask) !== test; length += 1) {
mask = (mask >> 1) | 128;
test = (test >> 1) | 128;
}
/* jshint bitwise:true */
// multi byte utf8 character
return length;
};
var httpinvoke = function(uri, method, options, cb) {
;var mixInPromise, promise, failWithoutRequest, uploadProgressCb, inputLength, noData, timeout, inputHeaders, statusCb, initDownload, updateDownload, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter;
'use strict';
/* jshint unused:true */
;/* global httpinvoke, url, method, options, cb */
/* global nextTick, mixInPromise, pass, progress, reject, resolve, supportedMethods, isArray, isArrayBufferView, isFormData, isByteArray, bytearrayMessage, _undefined */
/* global setTimeout */
/* global crossDomain */// this one is a hack, because when in nodejs this is not really defined, but it is never needed
/* jshint -W020 */
var promise, failWithoutRequest, uploadProgressCb, downloadProgressCb, inputLength, inputHeaders, statusCb, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter;
/*************** COMMON initialize parameters **************/
var downloadTimeout, uploadTimeout, timeout;
if(!method) {

@@ -128,69 +201,11 @@ // 1 argument

}
var safeCallback = function(name, aspect) {
if(name in options) {
return function(a, b, c, d) {
try {
options[name](a, b, c, d);
} catch(_) {
}
aspect(a, b, c, d);
};
}
return aspect;
};
var chain = function(a, b) {
a && a.then && a.then(function() {
b[resolve].apply(null, arguments);
}, function() {
b[reject].apply(null, arguments);
}, function() {
b[progress].apply(null, arguments);
});
};
var resolve = 0, reject = 1, progress = 2;
mixInPromise = function(o) {
var value, queue = [], state = progress;
var makeState = function(newstate) {
o[newstate] = function(newvalue) {
var i, p;
if(queue) {
value = newvalue;
state = newstate;
for(i = 0; i < queue.length; i++) {
if(typeof queue[i][state] === 'function') {
try {
p = queue[i][state].call(null, value);
if(state < progress) {
chain(p, queue[i]._);
}
} catch(err) {
queue[i]._[reject](err);
}
} else if(state < progress) {
queue[i]._[state](value);
}
}
if(state < progress) {
queue = null;
}
}
};
};
makeState(progress);
makeState(resolve);
makeState(reject);
o.then = function() {
var item = [].slice.call(arguments);
item._ = mixInPromise({});
if(queue) {
queue.push(item);
} else if(typeof item[state] === 'function') {
nextTick(function() {
chain(item[state](value), item._);
});
var safeCallback = function(name, aspectBefore, aspectAfter) {
return function(a, b, c, d) {
aspectBefore(a, b, c, d);
try {
options[name](a, b, c, d);
} catch(_) {
}
return item._;
aspectAfter(a, b, c, d);
};
return o;
};

@@ -209,3 +224,3 @@ failWithoutRequest = function(cb, err) {

uploadProgressCb = safeCallback('uploading', function(current, total) {
uploadProgressCb = safeCallback('uploading', pass, function(current, total) {
promise[progress]({

@@ -217,10 +232,21 @@ type: 'upload',

});
var downloadProgressCb = safeCallback('downloading', function(current, total) {
downloadProgressCb = safeCallback('downloading', pass, function(current, total, partial) {
promise[progress]({
type: 'download',
current: current,
total: total
total: total,
partial: partial
});
});
statusCb = safeCallback('gotStatus', function(statusCode, headers) {
statusCb = safeCallback('gotStatus', function() {
statusCb = null;
if(downloadTimeout) {
setTimeout(function() {
if(cb) {
cb(new Error('download timeout'));
promise();
}
}, downloadTimeout);
}
}, function(statusCode, headers) {
promise[progress]({

@@ -232,3 +258,6 @@ type: 'headers',

});
cb = safeCallback('finished', function(err, body, statusCode, headers) {
cb = safeCallback('finished', function() {
cb = null;
promise();
}, function(err, body, statusCode, headers) {
if(err) {

@@ -243,53 +272,74 @@ return promise[reject](err);

});
timeout = options.timeout || 0;
var fixPositiveOpt = function(opt) {
if(options[opt] === _undefined) {
options[opt] = 0;
} else if(typeof options[opt] === 'number') {
if(options[opt] < 0) {
return failWithoutRequest(cb, new Error('Option "' + opt + '" is less than zero'));
}
} else {
return failWithoutRequest(cb, new Error('Option "' + opt + '" is not a number'));
}
};
var converters = options.converters || {};
var inputConverter;
inputLength = 0;
inputHeaders = options.headers || {};
outputHeaders = {};
exposedHeaders = options.corsExposedHeaders || [];
exposedHeaders.push.apply(exposedHeaders, ['Cache-Control', 'Content-Language', 'Content-Type', 'Content-Length', 'Expires', 'Last-Modified', 'Pragma', 'Content-Range']);
exposedHeaders.push.apply(exposedHeaders, ['Cache-Control', 'Content-Language', 'Content-Type', 'Content-Length', 'Expires', 'Last-Modified', 'Pragma', 'Content-Range', 'Content-Encoding']);
/*************** COMMON convert and validate parameters **************/
var partialOutputMode = options.partialOutputMode || 'disabled';
if(partialOutputMode.indexOf(',') >= 0 || ',disabled,chunked,joined,'.indexOf(',' + partialOutputMode + ',') < 0) {
return failWithoutRequest(cb, new Error('Option "partialOutputMode" is neither "disabled", nor "chunked", nor "joined"'));
}
if(method.indexOf(',') >= 0 || supportedMethods.indexOf(',' + method + ',') < 0) {
return failWithoutRequest(cb, new Error('Unsupported method ' + method));
}
outputBinary = options.outputType === 'bytearray';
if(!options.outputType || options.outputType === 'text' || outputBinary) {
var optionsOutputType = options.outputType;
outputBinary = optionsOutputType === 'bytearray';
if(!optionsOutputType || optionsOutputType === 'text' || outputBinary) {
outputConverter = pass;
} else if(converters['text ' + options.outputType]) {
outputConverter = converters['text ' + options.outputType];
} else if(converters['text ' + optionsOutputType]) {
outputConverter = converters['text ' + optionsOutputType];
outputBinary = false;
} else if(converters['bytearray ' + options.outputType]) {
outputConverter = converters['bytearray ' + options.outputType];
} else if(converters['bytearray ' + optionsOutputType]) {
outputConverter = converters['bytearray ' + optionsOutputType];
outputBinary = true;
} else {
return failWithoutRequest(cb, new Error('Unsupported outputType ' + options.outputType));
return failWithoutRequest(cb, new Error('Unsupported outputType ' + optionsOutputType));
}
inputConverter = pass;
if('input' in options) {
input = options.input;
if(!options.inputType || options.inputType === 'auto') {
if(typeof input !== 'string' && !isByteArray(input)) {
return failWithoutRequest(cb, new Error('inputType is undefined or auto and input is neither string, nor ' + bytearrayMessage));
var optionsInputType = options.inputType;
input = options.input;
if(input !== _undefined) {
if(!optionsInputType || optionsInputType === 'auto') {
if(typeof input !== 'string' && !isByteArray(input) && !isFormData(input)) {
return failWithoutRequest(cb, new Error('inputType is undefined or auto and input is neither string, nor FormData, nor ' + bytearrayMessage));
}
} else if(options.inputType === 'text') {
} else if(optionsInputType === 'text') {
if(typeof input !== 'string') {
return failWithoutRequest(cb, new Error('inputType is text, but input is not a string'));
}
} else if (options.inputType === 'bytearray') {
} else if (optionsInputType === 'formdata') {
if(!isFormData(input)) {
return failWithoutRequest(cb, new Error('inputType is formdata, but input is not an instance of FormData'));
}
} else if (optionsInputType === 'bytearray') {
if(!isByteArray(input)) {
return failWithoutRequest(cb, new Error('inputType is bytearray, but input is neither ' + bytearrayMessage));
}
} else if(converters[options.inputType + ' text']) {
inputConverter = converters[options.inputType + ' text'];
} else if(converters[options.inputType + ' bytearray']) {
inputConverter = converters[options.inputType + ' bytearray'];
} else if(converters[optionsInputType + ' text']) {
inputConverter = converters[optionsInputType + ' text'];
} else if(converters[optionsInputType + ' bytearray']) {
inputConverter = converters[optionsInputType + ' bytearray'];
} else if(converters[optionsInputType + ' formdata']) {
inputConverter = converters[optionsInputType + ' formdata'];
} else {
return failWithoutRequest(cb, new Error('There is no converter for specified inputType'));
}
if(typeof input === 'object') {
if(global.ArrayBuffer && input instanceof ArrayBuffer) {
input = new Uint8Array(input);
if(typeof input === 'object' && !isFormData(input)) {
if(global.ArrayBuffer && input instanceof global.ArrayBuffer) {
input = new global.Uint8Array(input);
} else if(isArrayBufferView(input)) {
input = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
input = new global.Uint8Array(input.buffer, input.byteOffset, input.byteLength);
}

@@ -303,3 +353,3 @@ }

} else {
if(options.inputType) {
if(optionsInputType && optionsInputType !== 'auto') {
return failWithoutRequest(cb, new Error('"input" is undefined, but inputType is defined'));

@@ -311,23 +361,39 @@ }

}
/*************** COMMON initialize helper variables **************/
var downloaded;
initDownload = function(total) {
if(typeof outputLength === 'undefined') {
downloadProgressCb(downloaded, outputLength = total);
}
var isValidTimeout = function(timeout) {
return timeout > 0 && timeout < 1073741824;
};
updateDownload = function(value) {
if(value !== downloaded) {
downloadProgressCb(downloaded = value, outputLength);
var optionsTimeout = options.timeout;
if(optionsTimeout !== _undefined) {
if(typeof optionsTimeout === 'number' && isValidTimeout(optionsTimeout)) {
timeout = optionsTimeout;
} else if(isArray(optionsTimeout) && optionsTimeout.length === 2 && isValidTimeout(optionsTimeout[0]) && isValidTimeout(optionsTimeout[1])) {
if(httpinvoke.corsFineGrainedTimeouts || !crossDomain) {
uploadTimeout = optionsTimeout[0];
downloadTimeout = optionsTimeout[1];
} else {
timeout = optionsTimeout[0] + optionsTimeout[1];
}
} else {
return failWithoutRequest(cb, new Error('"timeout" value is not valid'));
}
};
noData = function() {
initDownload(0);
if(cb) {
cb(null, _undefined, status, outputHeaders);
cb = null;
}
};
}
if(uploadTimeout) {
setTimeout(function() {
if(statusCb) {
cb(new Error('upload timeout'));
promise();
}
}, uploadTimeout);
}
if(timeout) {
setTimeout(function() {
if(cb) {
cb(new Error('timeout'));
promise();
}
}, timeout);
}
;
/* jshint unused:false */
/*************** initialize helper variables **************/

@@ -347,8 +413,2 @@ try {

uri = url.parse(uri);
if(timeout > 0) {
setTimeout(function() {
cb(new Error('Timeout of ' + timeout + 'ms exceeded'));
cb = null;
}, timeout);
}
var req = http.request({

@@ -362,5 +422,4 @@ hostname: uri.hostname,

var contentEncoding;
if(cb === null) {
ignorantlyConsume(res);
return;
if(!cb) {
return ignorantlyConsume(res);
}

@@ -371,2 +430,7 @@

contentEncoding = outputHeaders['content-encoding'];
if(['identity', 'gzip', 'deflate'].indexOf(contentEncoding) < 0) {
cb(new Error('unsupported Content-Encoding ' + contentEncoding));
cb = null;
return ignorantlyConsume(res);
}
delete outputHeaders['content-encoding'];

@@ -380,51 +444,80 @@ } else {

uploadProgressCb(inputLength, inputLength);
if(cb === null) {
ignorantlyConsume(res);
return;
if(!cb) {
return ignorantlyConsume(res);
}
statusCb(status, outputHeaders);
if(cb === null) {
ignorantlyConsume(res);
return;
if(!cb) {
return ignorantlyConsume(res);
}
updateDownload(0);
if(cb === null) {
ignorantlyConsume(res);
return;
if(contentEncoding === 'identity' && 'content-length' in outputHeaders) {
outputLength = Number(outputHeaders['content-length']);
}
if(typeof outputHeaders['content-length'] !== 'undefined') {
initDownload(Number(outputHeaders['content-length']));
if(cb === null) {
ignorantlyConsume(res);
return;
}
var partial = partialOutputMode === 'disabled' ? _undefined : (outputBinary ? [] : '');
downloadProgressCb(0, outputLength, partial);
if(!cb) {
return ignorantlyConsume(res);
}
if(method === 'HEAD' || typeof outputHeaders['content-type'] === 'undefined') {
if(method === 'HEAD') {
ignorantlyConsume(res);
return noData();
downloadProgressCb(0, 0, partial);
return cb && cb(null, _undefined, status, outputHeaders);
}
var output = [], downloaded = 0;
res.on('data', function(chunk) {
if(cb === null) {
var inputStream;
if(contentEncoding === 'identity') {
inputStream = res;
} else {
inputStream = zlib['create' + (contentEncoding === 'gzip' ? 'Gunzip' : 'InflateRaw')]();
res.pipe(inputStream);
}
var output = [], downloaded = 0, leftover = emptyBuffer;
inputStream.on('data', function(chunk) {
if(!cb) {
return;
}
if(partialOutputMode !== 'disabled' && !outputBinary) {
chunk = Buffer.concat([leftover, chunk]);
var charsize = 0, newLeftoverLength = 0;
while(charsize === 0 && newLeftoverLength < chunk.length) {
newLeftoverLength += 1;
charsize = utf8CharacterSizeFromHeaderByte(chunk[chunk.length - newLeftoverLength]);
}
if(newLeftoverLength === charsize) {
leftover = emptyBuffer;
} else {
leftover = chunk.slice(chunk.length - newLeftoverLength);
chunk = chunk.slice(0, chunk.length - newLeftoverLength);
}
}
downloaded += chunk.length;
output.push(chunk);
updateDownload(downloaded);
if(cb === null) {
return;
var partial;
if(partialOutputMode !== 'disabled') {
partial = partialOutputMode === 'chunked' ? chunk : Buffer.concat(output);
if(!outputBinary) {
partial = partial.toString('utf8');
}
}
downloadProgressCb(downloaded, outputLength, partial);
});
res.on('end', function() {
if(cb === null) {
inputStream.on('error', cb);
inputStream.on('end', function() {
if(!cb) {
return;
}
updateDownload(downloaded);
if(cb === null) {
return;
}
// just in case the utf8 text stream was damaged, and there is leftover
output.push(leftover);
downloaded += leftover.length;
if(typeof outputLength === 'undefined') {

@@ -434,21 +527,32 @@ outputLength = downloaded;

decompress(Buffer.concat(output, downloaded), contentEncoding, function(err, output) {
if(!cb) {
return;
}
if(err) {
cb(err);
cb = null;
return;
}
if(!outputBinary) {
output = output.toString('utf8');
}
try {
cb(null, outputConverter(output), status, outputHeaders);
} catch(err) {
cb(err);
}
cb = null;
});
if(downloaded !== outputLength) {
return cb(new Error('network error'));
}
output = Buffer.concat(output, downloaded);
if(!outputBinary) {
output = output.toString('utf8');
}
var partial;
if(partialOutputMode === 'chunked') {
partial = outputBinary ? leftover : leftover.toString('utf8');
} else if(partialOutputMode === 'joined') {
partial = outputBinary ? output : output.toString('utf8');
}
downloadProgressCb(outputLength, outputLength, partial);
if(!cb) {
return;
}
if(outputLength === 0 && typeof outputHeaders['content-type'] === 'undefined') {
return cb(null, _undefined, status, outputHeaders);
}
try {
cb(null, outputConverter(output), status, outputHeaders);
} catch(err) {
cb(err);
}
});

@@ -458,3 +562,3 @@ });

nextTick(function() {
if(cb === null) {
if(!cb) {
return;

@@ -468,20 +572,17 @@ }

req.write(input);
} else {
inputLength = 0;
}
req.on('error', function(e) {
if(cb === null) {
req.on('error', function() {
if(!cb) {
return;
}
cb(e);
cb = null;
cb(new Error('network error'));
});
req.end();
promise = function() {
if(cb === null) {
if(!cb) {
return;
}
// these statements are in case "abort" is called in "finished" callback
var _cb = cb;
cb = null;
_cb(new Error('abort'));
cb(new Error('abort'));
};

@@ -501,3 +602,5 @@ return mixInPromise(promise);

httpinvoke.requestTextOnly = false;
httpinvoke.PATCH = true;
httpinvoke.corsFineGrainedTimeouts = true;
module.exports = httpinvoke;

@@ -0,1 +1,2 @@

/* jshint -W020 */
if(typeof window === 'undefined') {

@@ -10,2 +11,3 @@ window = {};

}
/* jshint +W020 */

@@ -286,2 +288,3 @@ window._httpinvoke = window.httpinvoke;

makeTextFinished: function(done) {
'use strict';
var cfg = require('./dummyserver-config');

@@ -302,2 +305,3 @@ return function(err, output) {

makeByteArrayFinished: function(done) {
'use strict';
var cfg = require('./dummyserver-config');

@@ -328,2 +332,3 @@ return function(err, output) {

eachBase: function(fn) {
'use strict';
var httpinvoke = require('./httpinvoke-node');

@@ -342,2 +347,3 @@ if(httpinvoke.cors) {

jsonTest: function() {
'use strict';
return [{

@@ -351,2 +357,3 @@ a: 0,

jsonTestPasses: function(json) {
'use strict';
if(typeof json !== 'object' || json === null) {

@@ -379,5 +386,7 @@ return false;

textTest: function() {
'use strict';
return 'ąčęėįšųū„“–ž1234567890-=!@#$%^&*()_+´¬¿,./;[]';
},
bytearrayTest: function() {
'use strict';
var i, bytes = [];

@@ -401,2 +410,3 @@ for(i = 0; i < 64; i += 1) {

window.require = function(module) {
'use strict';
if(module === '../dummyserver-config' || module === './dummyserver-config') {

@@ -416,2 +426,3 @@ return window._cfg;

log: function() {
'use strict';
this._log.push([].slice.call(arguments));

@@ -418,0 +429,0 @@ }

@@ -6,74 +6,75 @@ // Karma configuration

module.exports = function(config) {
var cfg = {
'use strict';
var cfg = {
// base path, that will be used to resolve files and exclude
basePath: '',
// base path, that will be used to resolve files and exclude
basePath: '',
// frameworks to use
frameworks: ['mocha'],
// frameworks to use
frameworks: ['mocha'],
// list of files / patterns to load in the browser
files: [
'httpinvoke-browser.js',
'karma-mocha-requireHack.js',
'node_modules/es5-shim/es5-shim.js',
'test/*.js'
],
// list of files / patterns to load in the browser
files: [
'httpinvoke-browser.js',
'karma-mocha-requireHack.js',
'node_modules/es5-shim/es5-shim.js',
'test/*.js'
],
// list of files to exclude
exclude: [
// list of files to exclude
exclude: [
],
],
// test results reporter to use
// possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
reporters: ['progress'],
// test results reporter to use
// possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
reporters: ['progress'],
// web server port
port: 9876,
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: [],
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: [],
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false,
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false,
proxies: {
}
proxies: {
}
};
cfg.proxies[dummyserverCfg.proxyPath + '/'] = dummyserverCfg.url;
config.set(cfg);
};
cfg.proxies[dummyserverCfg.proxyPath + '/'] = dummyserverCfg.url;
config.set(cfg);
};
{
"name": "httpinvoke",
"version": "1.0.4",
"description": "a small, no-dependencies HTTP client library for browsers and Node.js with a promise-based or Node.js-style callback-based API to progress events, text and binary file upload and download, request and response headers, status code.",
"version": "1.1.1",
"description": "A small, no-dependencies HTTP client library for browsers and Node.js with a promise-based or Node.js-style callback-based API to progress events, text and binary file upload and download, partial response body, request and response headers, status code.",
"keywords": [

@@ -37,5 +37,6 @@ "http",

"grunt-contrib-concat": "0.3.x",
"grunt-mocha-test": "0.7.x",
"grunt-contrib-jshint": "0.7.x",
"grunt-mocha-test": "0.8.x",
"daemon": "1.1.x",
"mocha": "1.13.x",
"mocha": "1.15.x",
"karma": "0.11.x",

@@ -45,5 +46,5 @@ "karma-mocha": "0.1.x"

"scripts": {
"test": "node ./dummyserver.js;./node_modules/.bin/grunt test;kill $(cat ./dummyserver.pid);rm ./dummyserver.pid",
"test-browser": "./node_modules/.bin/grunt;node ./dummyserver.js;./node_modules/.bin/karma start;kill $(cat ./dummyserver.pid);rm ./dummyserver.pid",
"test-node": "./node_modules/.bin/grunt;node ./dummyserver.js;./node_modules/.bin/mocha --watch;kill $(cat ./dummyserver.pid);rm ./dummyserver.pid"
"test": "node ./dummyserver.js && ./node_modules/.bin/grunt test && kill $(cat ./dummyserver.pid) && rm ./dummyserver.pid",
"test-browser": "./node_modules/.bin/grunt && node ./dummyserver.js && ./node_modules/karma/bin/karma start && kill $(cat ./dummyserver.pid) && rm ./dummyserver.pid",
"test-node": "./node_modules/.bin/grunt && node ./dummyserver.js && ./node_modules/.bin/mocha --watch && kill $(cat ./dummyserver.pid) && rm ./dummyserver.pid"
},

@@ -59,3 +60,8 @@ "repository": {

},
"contributors": []
"contributors": [],
"engines" : {
"node" : ">=0.8.0 <0.11"
},
"engineStrict": true,
"private": false
}

@@ -1,12 +0,13 @@

(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.httpinvoke = factory();
}
}(this, function () {
/* jshint -W030 */
/* jshint -W033 */
/* jshint -W068 */
(function() {
/* jshint +W030 */
/* jshint +W033 */
/* jshint +W068 */
'use strict';
var global;
var pass, isArray, isArrayBufferView, _undefined, nextTick;
/* jshint unused:true */
var mixInPromise, pass, isArray, isArrayBufferView, _undefined, nextTick, isFormData;
/* jshint unused:false */
// this could be a simple map, but with this "compression" we save about 100 bytes, if minified (50 bytes, if also gzipped)

@@ -27,15 +28,29 @@ var statusTextToCode = (function() {

);
var bufferSlice = function(buffer, begin, end) {
if(begin === 0 && end === buffer.byteLength) {
return buffer;
var upgradeByteArray = global.Uint8Array ? function(array) {
return new Uint8Array(array);
} : pass;
var binaryStringToByteArray = function(str, bytearray) {
for(var i = bytearray.length; i < str.length;) {
/* jshint bitwise:false */
bytearray.push(str.charCodeAt(i++) & 255);
/* jshint bitwise:true */
}
return buffer.slice ? buffer.slice(begin, end) : new Uint8Array(Array.prototype.slice.call(new Uint8Array(buffer), begin, end)).buffer;
return bytearray;
};
var countStringBytes = function(string) {
for(var c, n = 0, i = string.length;i--;) {
c = string.charCodeAt(i);
n += c < 128 ? 1 : (c < 2048 ? 2 : 3);
}
return n;
};
var responseBodyToBytes, responseBodyLength;
try {
execScript('Function httpinvoke0(B,A)\r\nDim i\r\nFor i=1 to LenB(B)\r\nA.push(AscB(MidB(B,i,1)))\r\nNext\r\nEnd Function\r\nFunction httpinvoke1(B)\r\nhttpinvoke1=LenB(B)\r\nEnd Function', 'vbscript');
responseBodyToBytes = function(binary) {
var bytes = [];
httpinvoke0(binary, bytes);
return bytes;
/* jshint evil:true */
execScript('Function httpinvoke0(B,A,C)\r\nDim i\r\nFor i=C to LenB(B)\r\nA.push(AscB(MidB(B,i,1)))\r\nNext\r\nEnd Function\r\nFunction httpinvoke1(B)\r\nhttpinvoke1=LenB(B)\r\nEnd Function', 'vbscript');
/* jshint evil:false */
responseBodyToBytes = function(binary, bytearray) {
// that vbscript counts from 1, not from 0
httpinvoke0(binary, bytearray, bytearray.length + 1);
return bytearray;
};

@@ -48,49 +63,12 @@ // cannot just assign the function, because httpinvoke1 is not a javascript 'function'

}
var getOutputText = function(xhr) {
return xhr.response || xhr.responseText;
var responseByteArray = function(xhr, bytearray) {
// If response body has bytes out of printable ascii character range, then
// accessing xhr.responseText on Internet Explorer throws "Could not complete the operation due to error c00ce514".
// Therefore, try getting the bytearray from xhr.responseBody.
// Also responseBodyToBytes on some Internet Explorers is not defined, because of removed vbscript support.
return 'responseBody' in xhr && responseBodyToBytes ? responseBodyToBytes(xhr.responseBody, bytearray) : binaryStringToByteArray(xhr.responseText, bytearray);
};
var binaryStringToByteArray = function(str) {
for(var n = str.length, bytearray = new Array(n);n--;) {
bytearray[n] = str.charCodeAt(n) & 255;
}
return bytearray;
var responseByteArrayLength = function(xhr) {
return 'responseBody' in xhr && responseBodyLength ? responseBodyLength(xhr.responseBody) : xhr.responseText.length;
};
var getOutputBinary = function(xhr) {
if('response' in xhr) {
return new Uint8Array(xhr.response || []);
}
// responseBody must be checked this way, because otherwise
// it is falsy and then accessing responseText for binary data
// results in the "c00ce514" error
if('responseBody' in xhr) {
return responseBodyToBytes(xhr.responseBody);
}
var bytearray = binaryStringToByteArray(xhr.responseText);
// firefox 4 supports typed arrays but not xhr2
return global.Uint8Array ? new global.Uint8Array(bytearray) : bytearray;
};
var getOutputLengthText = function(xhr) {
return countStringBytes(getOutputText(xhr));
};
var getOutputLengthBinary = function(xhr) {
if('response' in xhr) {
return xhr.response ? xhr.response.byteLength : 0;
}
// responseBody must be checked this way, because otherwise
// it is falsy and then accessing responseText for binary data
// results in the "c00ce514" error
if('responseBody' in xhr) {
return responseBodyLength(xhr.responseBody);
}
return xhr.responseText.length;
};
var countStringBytes = function(string) {
for(var c, n = 0, i = string.length;i--;) {
c = string.charCodeAt(i);
n += c < 128 ? 1 : (c < 2048 ? 2 : 3);
}
return n;
};
var fillOutputHeaders = function(xhr, outputHeaders) {

@@ -116,8 +94,23 @@ var headers = xhr.getAllResponseHeaders().split(/\r?\n/);

var httpinvoke = function(uri, method, options, cb) {
var mixInPromise, promise, failWithoutRequest, uploadProgressCb, inputLength, noData, timeout, inputHeaders, statusCb, initDownload, updateDownload, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter;
/* jshint unused:true */
var promise, failWithoutRequest, uploadProgressCb, downloadProgressCb, inputLength, inputHeaders, statusCb, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter, partialOutputMode;
/* jshint unused:false */
/*************** initialize helper variables **************/
var xhr, i, j, currentLocation, crossDomain, output,
getOutput = outputBinary ? getOutputBinary : getOutputText,
getOutputLength = outputBinary ? getOutputLengthBinary : getOutputLengthText,
uploadProgressCbCalled = false;
uploadProgressCbCalled = false,
partialPosition = 0,
partialBuffer = partialOutputMode === 'disabled' ? _undefined : (outputBinary ? [] : ''),
partial = partialBuffer,
partialUpdate = function() {
if(partialOutputMode === 'disabled') {
return;
}
if(outputBinary) {
responseByteArray(xhr, partialBuffer);
} else {
partialBuffer = xhr.responseText;
}
partial = partialOutputMode === 'joined' ? partialBuffer : partialBuffer.slice(partialPosition);
partialPosition = partialBuffer.length;
};
var uploadProgress = function(uploaded) {

@@ -152,4 +145,4 @@ if(!uploadProgressCb) {

/*************** start XHR **************/
if(typeof input === 'object' && httpinvoke.requestTextOnly) {
return failWithoutRequest(cb, new Error('bytearray inputType is not supported on this platform, please always test using requestTextOnly feature flag'));
if(typeof input === 'object' && !isFormData(input) && httpinvoke.requestTextOnly) {
return failWithoutRequest(cb, new Error('bytearray inputType is not supported on this platform, please always test using requestTextOnly feature flag - hint - you may want to try sending FormData (formdata type)'));
}

@@ -164,2 +157,5 @@ if(crossDomain && !httpinvoke.cors) {

}
if(method === 'PATCH' && !httpinvoke.PATCH) {
return failWithoutRequest(cb, new Error('PATCH method is not supported in this browser'));
}
if(!createXHR) {

@@ -169,12 +165,6 @@ return failWithoutRequest(cb, new Error('unable to construct XMLHttpRequest object'));

xhr = createXHR(crossDomain);
xhr.open(method, uri, true);
if(timeout > 0) {
if('timeout' in xhr) {
xhr.timeout = timeout;
} else {
setTimeout(function() {
cb(new Error('download timeout'));
cb = null;
}, timeout);
}
try {
xhr.open(method, uri, true);
} catch(e) {
return failWithoutRequest(cb, e);
}

@@ -196,19 +186,19 @@ if(options.corsCredentials && httpinvoke.corsCredentials && typeof xhr.withCredentials === 'boolean') {

/*************** bind XHR event listeners **************/
var makeErrorCb = function(message) {
return function() {
// must check, because some callbacks are called synchronously, thus throwing exceptions and breaking code
if(cb) {
cb(new Error(message));
cb = null;
}
};
};
var onuploadprogress = function(progressEvent) {
if(cb && progressEvent.lengthComputable) {
uploadProgress(progressEvent.loaded);
if(inputLength === _undefined) {
inputLength = progressEvent.total || progressEvent.totalSize || 0;
uploadProgress(0);
}
uploadProgress(progressEvent.loaded || progressEvent.position || 0);
}
};
if('upload' in xhr) {
xhr.upload.ontimeout = makeErrorCb('upload timeout');
xhr.upload.onerror = makeErrorCb('upload error');
xhr.upload.onerror = function() {
received.error = true;
// must check, because some callbacks are called synchronously, thus throwing exceptions and breaking code
/* jshint expr:true */
cb && cb(new Error('network error'));
/* jshint expr:false */
};
xhr.upload.onprogress = onuploadprogress;

@@ -219,7 +209,5 @@ } else if('onuploadprogress' in xhr) {

if('ontimeout' in xhr) {
xhr.ontimeout = makeErrorCb('download timeout');
}
if('onerror' in xhr) {
xhr.onerror = function() {
received.error = true;
//inspect('onerror', arguments[0]);

@@ -231,43 +219,30 @@ //dbg('onerror');

}
var ondownloadprogress = function(progressEvent) {
onHeadersReceived(false);
// There is a bug in Chrome 10 on 206 response with Content-Range=0-4/12 - total must be 5
// 'total', 12, 'totalSize', 12, 'loaded', 5, 'position', 5, 'lengthComputable', true, 'status', 206
// console.log('total', progressEvent.total, 'totalSize', progressEvent.totalSize, 'loaded', progressEvent.loaded, 'position', progressEvent.position, 'lengthComputable', progressEvent.lengthComputable, 'status', status);
// httpinvoke does not work around this bug, because Chrome 10 is practically not used at all, as Chrome agressively auto-updates itself to latest version
try {
var current = progressEvent.loaded || progressEvent.position || 0;
if(progressEvent.lengthComputable) {
outputLength = progressEvent.total || progressEvent.totalSize || 0;
}
// Opera 12 progress events has a bug - .loaded can be higher than .total
// see http://dev.opera.com/articles/view/xhr2/#comment-96081222
/* jshint expr:true */
cb && current <= outputLength && !statusCb && (partialUpdate(), downloadProgressCb(current, outputLength, partial));
/* jshint expr:false */
} catch(_) {
}
};
if('onloadstart' in xhr) {
xhr.onloadstart = function() {
//dbg('onloadstart');
onHeadersReceived(false);
};
xhr.onloadstart = ondownloadprogress;
}
if('onloadend' in xhr) {
xhr.onloadend = function() {
//dbg('onloadend');
onHeadersReceived(false);
};
xhr.onloadend = ondownloadprogress;
}
if('onprogress' in xhr) {
xhr.onprogress = function(progressEvent) {
//dbg('onprogress');
if(!cb) {
return;
}
onHeadersReceived(false);
if(statusCb) {
return;
}
// There is a bug in Chrome 10 on 206 response with Content-Range=0-4/12 - total must be 5
// 'total', 12, 'totalSize', 12, 'loaded', 5, 'position', 5, 'lengthComputable', true, 'status', 206
// console.log('total', progressEvent.total, 'totalSize', progressEvent.totalSize, 'loaded', progressEvent.loaded, 'position', progressEvent.position, 'lengthComputable', progressEvent.lengthComputable, 'status', status);
// httpinvoke does not work around this bug, because Chrome 10 is practically not used at all, as Chrome agressively auto-updates itself to latest version
var total = progressEvent.total || progressEvent.totalSize || 0,
current = progressEvent.loaded || progressEvent.position || 0;
if(progressEvent.lengthComputable) {
initDownload(total);
}
if(!cb) {
return;
}
if(current > total) {
// Opera 12 progress events has a bug - .loaded can be higher than .total
// see http://dev.opera.com/articles/view/xhr2/#comment-96081222
return;
}
updateDownload(current);
};
xhr.onprogress = ondownloadprogress;
}

@@ -301,13 +276,5 @@ /*

*/
var received = {
success: false,
status: false,
entity: false,
headers: false
};
var onHeadersReceived = function(lastTry) {
if(!cb) {
return;
}
var received = {};
var mustBeIdentity;
var tryHeadersAndStatus = function(lastTry) {
try {

@@ -337,2 +304,8 @@ if(xhr.status) {

}
try {
if(responseBodyLength(xhr.responseBody)) {
received.entity = true;
}
} catch(_) {
}

@@ -344,3 +317,3 @@ if(!statusCb) {

if(received.status || received.entity || received.success || lastTry) {
if(typeof xhr.contentType === 'string') {
if(typeof xhr.contentType === 'string' && xhr.contentType) {
if(xhr.contentType !== 'text/html' || xhr.responseText !== '') {

@@ -354,6 +327,8 @@ // When no entity body and/or no Content-Type header is sent,

}
for(var i = 0; i < exposedHeaders.length; i += 1) {
for(var i = 0; i < exposedHeaders.length; i++) {
var header;
try {
/* jshint boss:true */
if(header = xhr.getResponseHeader(exposedHeaders[i])) {
/* jshint boss:false */
outputHeaders[exposedHeaders[i].toLowerCase()] = header;

@@ -373,2 +348,7 @@ received.headers = true;

mustBeIdentity = outputHeaders['content-encoding'] === 'identity' || (!crossDomain && !outputHeaders['content-encoding']);
if(mustBeIdentity && 'content-length' in outputHeaders) {
outputLength = Number(outputHeaders['content-length']);
}
if(!status && (!crossDomain || httpinvoke.corsStatus)) {

@@ -392,9 +372,28 @@ // Sometimes on IE 9 accessing .status throws an error, but .statusText does not.

}
// IE (at least version 6) returns various detailed network
// connection error codes (concretely - WinInet Error Codes).
// For references of their meaning, see http://support.microsoft.com/kb/193625
if(status >= 12001 && status <= 12156) {
status = _undefined;
}
}
}
};
var onHeadersReceived = function(lastTry) {
if(!cb) {
return;
}
if(!lastTry && !(received.status && received.headers)) {
if(!lastTry) {
tryHeadersAndStatus(false);
}
if(!statusCb || (!lastTry && !(received.status && received.headers))) {
return;
}
if(inputLength === _undefined) {
inputLength = 0;
uploadProgress(0);
}
uploadProgress(inputLength);

@@ -406,3 +405,2 @@ if(!cb) {

statusCb(status, outputHeaders);
statusCb = null;
if(!cb) {

@@ -412,16 +410,9 @@ return;

if(method === 'HEAD') {
return noData();
}
updateDownload(0);
downloadProgressCb(0, outputLength, partial);
if(!cb) {
return;
}
if('content-length' in outputHeaders && (!crossDomain || 'content-encoding' in outputHeaders) && (!outputHeaders['content-encoding'] || outputHeaders['content-encoding'] === 'identity')) {
initDownload(Number(outputHeaders['content-length']));
if(!cb) {
return;
}
if(method === 'HEAD') {
downloadProgressCb(0, 0, partial);
return cb && cb(null, _undefined, status, outputHeaders);
}

@@ -434,27 +425,53 @@ };

onHeadersReceived(true);
if(!cb) {
return;
}
tryHeadersAndStatus(true);
if(!received.success && !status) {
// 'finished in onerror and status code is undefined'
cb(new Error('download error'));
cb = null;
return;
}
var length;
try {
length = getOutputLength(xhr);
length =
partialOutputMode !== 'disabled' ?
responseByteArrayLength(xhr) :
(
outputBinary ?
(
'response' in xhr ?
(
xhr.response ?
xhr.response.byteLength :
0
) :
responseByteArrayLength(xhr)
) :
countStringBytes(xhr.responseText)
);
} catch(_) {
return noData();
length = 0;
}
if(!outputLength) {
initDownload(length);
} else if(length !== outputLength) {
// 'output length ' + outputLength + ' is not equal to actually received entity length ' + length
cb(new Error('download error'));
cb = null;
if(outputLength !== _undefined) {
if(mustBeIdentity) {
if(length !== outputLength && method !== 'HEAD') {
return cb(new Error('network error'));
}
} else {
if(received.error) {
return cb(new Error('network error'));
}
}
} else {
outputLength = length;
}
var noentity = !received.entity && outputLength === 0 && outputHeaders['content-type'] === _undefined;
if((noentity && status === 200) || (!received.success && !status && (received.error || ('onreadystatechange' in xhr && !received.readyStateLOADING)))) {
/*
* Note: on Opera 10.50, TODO there is absolutely no difference
* between a non 2XX response and an immediate socket closing on
* server side - both give no headers, no status, no entity, and
* end up in 'onload' event. Thus some network errors will end
* up calling "finished" without Error.
*/
return cb(new Error('network error'));
}
onHeadersReceived(true);
if(!cb) {

@@ -464,3 +481,9 @@ return;

updateDownload(outputLength);
if(noentity) {
downloadProgressCb(0, 0, partial);
return cb(null, _undefined, status, outputHeaders);
}
partialUpdate();
downloadProgressCb(outputLength, outputLength, partial);
if(!cb) {

@@ -471,11 +494,21 @@ return;

try {
cb(null, !received.entity && outputLength === 0 && typeof outputHeaders['content-type'] === 'undefined' ? _undefined : outputConverter(getOutput(xhr)), status, outputHeaders);
// If XHR2 (there is xhr.response), then there must also be Uint8Array.
// But Uint8Array might exist even if not XHR2 (on Firefox 4).
cb(null, outputConverter(
partialBuffer || (
outputBinary ?
upgradeByteArray(
'response' in xhr ?
xhr.response || [] :
responseByteArray(xhr, [])
) :
xhr.responseText
)
), status, outputHeaders);
} catch(err) {
cb(err);
}
cb = null;
};
var onloadBound = false;
if(typeof xhr.onload !== 'undefined') {
onloadBound = true;
var onloadBound = 'onload' in xhr;
if(onloadBound) {
xhr.onload = function() {

@@ -487,3 +520,3 @@ received.success = true;

}
if(typeof xhr.onreadystatechange !== 'undefined') {
if('onreadystatechange' in xhr) {
xhr.onreadystatechange = function() {

@@ -496,11 +529,4 @@ //dbg('onreadystatechange ' + xhr.readyState);

// LOADING
received.success = true;
received.readyStateLOADING = true;
onHeadersReceived(false);
if(statusCb) {
return;
}
try {
updateDownload(getOutputLength(xhr));
} catch(err) {
}
// Instead of 'typeof xhr.onload === "undefined"', we must use

@@ -534,17 +560,20 @@ // onloadBound variable, because otherwise Firefox 3.5 synchronously

}
if('response' in xhr) {
if(outputBinary) {
try {
xhr.responseType = outputBinary ? 'arraybuffer' : 'text';
} catch(err) {
if(partialOutputMode === 'disabled' && 'response' in xhr) {
xhr.responseType = 'arraybuffer';
} else {
// mime type override must be done before receiving headers - at least for Safari 5.0.4
xhr.overrideMimeType('text/plain; charset=x-user-defined');
}
} catch(_) {
}
} else {
}
if(isFormData(input)) {
try {
// mime type override must be done before receiving headers - at least for Safari 5.0.4
if(outputBinary) {
xhr.overrideMimeType('text/plain; charset=x-user-defined');
}
xhr.send(input);
} catch(err) {
return failWithoutRequest(cb, new Error('Unable to send'));
}
}
if(typeof input === 'object') {
} else if(typeof input === 'object') {
var triedSendArrayBufferView = false;

@@ -588,10 +617,22 @@ var triedSendBlob = false;

} else {
inputLength = input.byteLength;
try {
inputLength = input.byteLength;
// if there is ArrayBufferView, then the browser supports sending instances of subclasses of ArayBufferView, otherwise we must send an ArrayBuffer
xhr.send(global.ArrayBufferView ? input : bufferSlice(input.buffer, input.byteOffset, input.byteOffset + input.byteLength));
xhr.send(
global.ArrayBufferView ?
input :
(
input.byteOffset === 0 && input.length === input.buffer.byteLength ?
input.buffer :
(
input.buffer.slice ?
input.buffer.slice(input.byteOffset, input.byteOffset + input.length) :
new Uint8Array([].slice.call(new Uint8Array(input.buffer), input.byteOffset, input.byteOffset + input.length)).buffer
)
)
);
return;
} catch(_) {
triedSendArrayBufferView = true;
}
triedSendArrayBufferView = true;
}

@@ -650,3 +691,3 @@ } else if(global.Blob && input instanceof Blob) {

try {
input = binaryStringToByteArray(input);
input = binaryStringToByteArray(input, []);
} catch(_) {

@@ -671,2 +712,3 @@ triedSendArrayBufferView = true;

go();
uploadProgress(0);
} else {

@@ -678,11 +720,10 @@ try {

} else {
inputLength = 0;
xhr.send(null);
}
} catch(err) {
var _cb = cb;
cb = null;
return failWithoutRequest(cb, new Error('Unable to send'));
}
uploadProgress(0);
}
uploadProgress(0);
});

@@ -692,11 +733,5 @@

promise = function() {
if(!cb) {
return;
}
// these statements are in case "abort" is called in "finished" callback
var _cb = cb;
cb = null;
_cb(new Error('abort'));
/* jshint expr:true */
cb && cb(new Error('abort'));
/* jshint expr:false */
try {

@@ -719,2 +754,3 @@ xhr.abort();

httpinvoke.corsResponseTextOnly = false;
httpinvoke.corsFineGrainedTimeouts = true;
httpinvoke.requestTextOnly = false;

@@ -727,3 +763,3 @@ (function() {

var tmpxhr = createXHR();
httpinvoke.requestTextOnly = typeof Uint8Array === 'undefined' && typeof tmpxhr.sendAsBinary === 'undefined';
httpinvoke.requestTextOnly = !global.Uint8Array && !tmpxhr.sendAsBinary;
httpinvoke.cors = 'withCredentials' in tmpxhr;

@@ -743,3 +779,3 @@ if(httpinvoke.cors) {

try {
if(typeof XDomainRequest === 'undefined') {
if(global.XDomainRequest === _undefined) {
createXHR = function() {

@@ -757,2 +793,3 @@ return new XMLHttpRequest();

httpinvoke.corsResponseTextOnly = true;
httpinvoke.corsFineGrainedTimeouts = false;
}

@@ -770,5 +807,7 @@ return;

try {
/* jshint loopfunc:true */
createXHR = function() {
return new ActiveXObject(candidates[i]);
};
/* jshint loopfunc:true */
createXHR();

@@ -779,8 +818,14 @@ httpinvoke.requestTextOnly = true;

}
i -= 1;
}
createXHR = _undefined;
})();
httpinvoke.PATCH = !!(function() {
try {
createXHR().open('PATCH', location.href, true);
return 1;
} catch(_) {
}
})();
return httpinvoke;
}));
})

@@ -1,3 +0,9 @@

var mixInPromise, promise, failWithoutRequest, uploadProgressCb, inputLength, noData, timeout, inputHeaders, statusCb, initDownload, updateDownload, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter;
/* global httpinvoke, url, method, options, cb */
/* global nextTick, mixInPromise, pass, progress, reject, resolve, supportedMethods, isArray, isArrayBufferView, isFormData, isByteArray, bytearrayMessage, _undefined */
/* global setTimeout */
/* global crossDomain */// this one is a hack, because when in nodejs this is not really defined, but it is never needed
/* jshint -W020 */
var promise, failWithoutRequest, uploadProgressCb, downloadProgressCb, inputLength, inputHeaders, statusCb, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter;
/*************** COMMON initialize parameters **************/
var downloadTimeout, uploadTimeout, timeout;
if(!method) {

@@ -42,69 +48,11 @@ // 1 argument

}
var safeCallback = function(name, aspect) {
if(name in options) {
return function(a, b, c, d) {
try {
options[name](a, b, c, d);
} catch(_) {
}
aspect(a, b, c, d);
};
}
return aspect;
};
var chain = function(a, b) {
a && a.then && a.then(function() {
b[resolve].apply(null, arguments);
}, function() {
b[reject].apply(null, arguments);
}, function() {
b[progress].apply(null, arguments);
});
};
var resolve = 0, reject = 1, progress = 2;
mixInPromise = function(o) {
var value, queue = [], state = progress;
var makeState = function(newstate) {
o[newstate] = function(newvalue) {
var i, p;
if(queue) {
value = newvalue;
state = newstate;
for(i = 0; i < queue.length; i++) {
if(typeof queue[i][state] === 'function') {
try {
p = queue[i][state].call(null, value);
if(state < progress) {
chain(p, queue[i]._);
}
} catch(err) {
queue[i]._[reject](err);
}
} else if(state < progress) {
queue[i]._[state](value);
}
}
if(state < progress) {
queue = null;
}
}
};
};
makeState(progress);
makeState(resolve);
makeState(reject);
o.then = function() {
var item = [].slice.call(arguments);
item._ = mixInPromise({});
if(queue) {
queue.push(item);
} else if(typeof item[state] === 'function') {
nextTick(function() {
chain(item[state](value), item._);
});
var safeCallback = function(name, aspectBefore, aspectAfter) {
return function(a, b, c, d) {
aspectBefore(a, b, c, d);
try {
options[name](a, b, c, d);
} catch(_) {
}
return item._;
aspectAfter(a, b, c, d);
};
return o;
};

@@ -123,3 +71,3 @@ failWithoutRequest = function(cb, err) {

uploadProgressCb = safeCallback('uploading', function(current, total) {
uploadProgressCb = safeCallback('uploading', pass, function(current, total) {
promise[progress]({

@@ -131,10 +79,21 @@ type: 'upload',

});
var downloadProgressCb = safeCallback('downloading', function(current, total) {
downloadProgressCb = safeCallback('downloading', pass, function(current, total, partial) {
promise[progress]({
type: 'download',
current: current,
total: total
total: total,
partial: partial
});
});
statusCb = safeCallback('gotStatus', function(statusCode, headers) {
statusCb = safeCallback('gotStatus', function() {
statusCb = null;
if(downloadTimeout) {
setTimeout(function() {
if(cb) {
cb(new Error('download timeout'));
promise();
}
}, downloadTimeout);
}
}, function(statusCode, headers) {
promise[progress]({

@@ -146,3 +105,6 @@ type: 'headers',

});
cb = safeCallback('finished', function(err, body, statusCode, headers) {
cb = safeCallback('finished', function() {
cb = null;
promise();
}, function(err, body, statusCode, headers) {
if(err) {

@@ -157,53 +119,74 @@ return promise[reject](err);

});
timeout = options.timeout || 0;
var fixPositiveOpt = function(opt) {
if(options[opt] === _undefined) {
options[opt] = 0;
} else if(typeof options[opt] === 'number') {
if(options[opt] < 0) {
return failWithoutRequest(cb, new Error('Option "' + opt + '" is less than zero'));
}
} else {
return failWithoutRequest(cb, new Error('Option "' + opt + '" is not a number'));
}
};
var converters = options.converters || {};
var inputConverter;
inputLength = 0;
inputHeaders = options.headers || {};
outputHeaders = {};
exposedHeaders = options.corsExposedHeaders || [];
exposedHeaders.push.apply(exposedHeaders, ['Cache-Control', 'Content-Language', 'Content-Type', 'Content-Length', 'Expires', 'Last-Modified', 'Pragma', 'Content-Range']);
exposedHeaders.push.apply(exposedHeaders, ['Cache-Control', 'Content-Language', 'Content-Type', 'Content-Length', 'Expires', 'Last-Modified', 'Pragma', 'Content-Range', 'Content-Encoding']);
/*************** COMMON convert and validate parameters **************/
var partialOutputMode = options.partialOutputMode || 'disabled';
if(partialOutputMode.indexOf(',') >= 0 || ',disabled,chunked,joined,'.indexOf(',' + partialOutputMode + ',') < 0) {
return failWithoutRequest(cb, new Error('Option "partialOutputMode" is neither "disabled", nor "chunked", nor "joined"'));
}
if(method.indexOf(',') >= 0 || supportedMethods.indexOf(',' + method + ',') < 0) {
return failWithoutRequest(cb, new Error('Unsupported method ' + method));
}
outputBinary = options.outputType === 'bytearray';
if(!options.outputType || options.outputType === 'text' || outputBinary) {
var optionsOutputType = options.outputType;
outputBinary = optionsOutputType === 'bytearray';
if(!optionsOutputType || optionsOutputType === 'text' || outputBinary) {
outputConverter = pass;
} else if(converters['text ' + options.outputType]) {
outputConverter = converters['text ' + options.outputType];
} else if(converters['text ' + optionsOutputType]) {
outputConverter = converters['text ' + optionsOutputType];
outputBinary = false;
} else if(converters['bytearray ' + options.outputType]) {
outputConverter = converters['bytearray ' + options.outputType];
} else if(converters['bytearray ' + optionsOutputType]) {
outputConverter = converters['bytearray ' + optionsOutputType];
outputBinary = true;
} else {
return failWithoutRequest(cb, new Error('Unsupported outputType ' + options.outputType));
return failWithoutRequest(cb, new Error('Unsupported outputType ' + optionsOutputType));
}
inputConverter = pass;
if('input' in options) {
input = options.input;
if(!options.inputType || options.inputType === 'auto') {
if(typeof input !== 'string' && !isByteArray(input)) {
return failWithoutRequest(cb, new Error('inputType is undefined or auto and input is neither string, nor ' + bytearrayMessage));
var optionsInputType = options.inputType;
input = options.input;
if(input !== _undefined) {
if(!optionsInputType || optionsInputType === 'auto') {
if(typeof input !== 'string' && !isByteArray(input) && !isFormData(input)) {
return failWithoutRequest(cb, new Error('inputType is undefined or auto and input is neither string, nor FormData, nor ' + bytearrayMessage));
}
} else if(options.inputType === 'text') {
} else if(optionsInputType === 'text') {
if(typeof input !== 'string') {
return failWithoutRequest(cb, new Error('inputType is text, but input is not a string'));
}
} else if (options.inputType === 'bytearray') {
} else if (optionsInputType === 'formdata') {
if(!isFormData(input)) {
return failWithoutRequest(cb, new Error('inputType is formdata, but input is not an instance of FormData'));
}
} else if (optionsInputType === 'bytearray') {
if(!isByteArray(input)) {
return failWithoutRequest(cb, new Error('inputType is bytearray, but input is neither ' + bytearrayMessage));
}
} else if(converters[options.inputType + ' text']) {
inputConverter = converters[options.inputType + ' text'];
} else if(converters[options.inputType + ' bytearray']) {
inputConverter = converters[options.inputType + ' bytearray'];
} else if(converters[optionsInputType + ' text']) {
inputConverter = converters[optionsInputType + ' text'];
} else if(converters[optionsInputType + ' bytearray']) {
inputConverter = converters[optionsInputType + ' bytearray'];
} else if(converters[optionsInputType + ' formdata']) {
inputConverter = converters[optionsInputType + ' formdata'];
} else {
return failWithoutRequest(cb, new Error('There is no converter for specified inputType'));
}
if(typeof input === 'object') {
if(global.ArrayBuffer && input instanceof ArrayBuffer) {
input = new Uint8Array(input);
if(typeof input === 'object' && !isFormData(input)) {
if(global.ArrayBuffer && input instanceof global.ArrayBuffer) {
input = new global.Uint8Array(input);
} else if(isArrayBufferView(input)) {
input = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
input = new global.Uint8Array(input.buffer, input.byteOffset, input.byteLength);
}

@@ -217,3 +200,3 @@ }

} else {
if(options.inputType) {
if(optionsInputType && optionsInputType !== 'auto') {
return failWithoutRequest(cb, new Error('"input" is undefined, but inputType is defined'));

@@ -225,21 +208,36 @@ }

}
/*************** COMMON initialize helper variables **************/
var downloaded;
initDownload = function(total) {
if(typeof outputLength === 'undefined') {
downloadProgressCb(downloaded, outputLength = total);
}
var isValidTimeout = function(timeout) {
return timeout > 0 && timeout < 1073741824;
};
updateDownload = function(value) {
if(value !== downloaded) {
downloadProgressCb(downloaded = value, outputLength);
var optionsTimeout = options.timeout;
if(optionsTimeout !== _undefined) {
if(typeof optionsTimeout === 'number' && isValidTimeout(optionsTimeout)) {
timeout = optionsTimeout;
} else if(isArray(optionsTimeout) && optionsTimeout.length === 2 && isValidTimeout(optionsTimeout[0]) && isValidTimeout(optionsTimeout[1])) {
if(httpinvoke.corsFineGrainedTimeouts || !crossDomain) {
uploadTimeout = optionsTimeout[0];
downloadTimeout = optionsTimeout[1];
} else {
timeout = optionsTimeout[0] + optionsTimeout[1];
}
} else {
return failWithoutRequest(cb, new Error('"timeout" value is not valid'));
}
};
noData = function() {
initDownload(0);
if(cb) {
cb(null, _undefined, status, outputHeaders);
cb = null;
}
};
}
if(uploadTimeout) {
setTimeout(function() {
if(statusCb) {
cb(new Error('upload timeout'));
promise();
}
}, uploadTimeout);
}
if(timeout) {
setTimeout(function() {
if(cb) {
cb(new Error('timeout'));
promise();
}
}, timeout);
}

@@ -1,2 +0,57 @@

var isArrayBufferView = function(input) {
var resolve = 0, reject = 1, progress = 2, chain = function(a, b) {
/* jshint expr:true */
a && a.then && a.then(function() {
b[resolve].apply(null, arguments);
}, function() {
b[reject].apply(null, arguments);
}, function() {
b[progress].apply(null, arguments);
});
/* jshint expr:false */
}, nextTick = (global.process && global.process.nextTick) || global.setImmediate || global.setTimeout, mixInPromise = function(o) {
var value, queue = [], state = progress;
var makeState = function(newstate) {
o[newstate] = function(newvalue) {
var i, p;
if(queue) {
value = newvalue;
state = newstate;
for(i = 0; i < queue.length; i++) {
if(typeof queue[i][state] === 'function') {
try {
p = queue[i][state].call(null, value);
if(state < progress) {
chain(p, queue[i]._);
}
} catch(err) {
queue[i]._[reject](err);
}
} else if(state < progress) {
queue[i]._[state](value);
}
}
if(state < progress) {
queue = null;
}
}
};
};
makeState(progress);
makeState(resolve);
makeState(reject);
o.then = function() {
var item = [].slice.call(arguments);
item._ = mixInPromise({});
if(queue) {
queue.push(item);
} else if(typeof item[state] === 'function') {
nextTick(function() {
chain(item[state](value), item._);
});
}
return item._;
};
return o;
}, isArrayBufferView = /* jshint undef:false */function(input) {
return typeof input === 'object' && input !== null && (

@@ -14,5 +69,8 @@ (global.ArrayBufferView && input instanceof ArrayBufferView) ||

);
}, isArray = function(object) {
}/* jshint undef:true */, isArray = function(object) {
return Object.prototype.toString.call(object) === '[object Array]';
}, isByteArray = function(input) {
}, isFormData = function(input) {
return typeof input === 'object' && input !== null && global.FormData &&
input instanceof global.FormData;
}, isByteArray = /* jshint undef:false */function(input) {
return typeof input === 'object' && input !== null && (

@@ -26,4 +84,4 @@ (global.Buffer && input instanceof Buffer) ||

);
}, bytearrayMessage = 'an instance of Buffer, nor Blob, nor File, nor ArrayBuffer, nor ArrayBufferView, nor Int8Array, nor Uint8Array, nor Uint8ClampedArray, nor Int16Array, nor Uint16Array, nor Int32Array, nor Uint32Array, nor Float32Array, nor Float64Array, nor Array', supportedMethods = ',GET,HEAD,PATCH,POST,PUT,DELETE,', pass = function(value) {
}/* jshint undef:true */, bytearrayMessage = 'an instance of Buffer, nor Blob, nor File, nor ArrayBuffer, nor ArrayBufferView, nor Int8Array, nor Uint8Array, nor Uint8ClampedArray, nor Int16Array, nor Uint16Array, nor Int32Array, nor Uint32Array, nor Float32Array, nor Float64Array, nor Array', supportedMethods = ',GET,HEAD,PATCH,POST,PUT,DELETE,', pass = function(value) {
return value;
}, nextTick = (global.process && global.process.nextTick) || global.setImmediate || global.setTimeout, _undefined;
}, _undefined;
if(typeof process !== 'undefined' && typeof process.versions !== 'undefined' && typeof process.versions.node !== 'undefined') {
var node;
/* jshint unused:true */
var node;
/* jshint unused:false */
} else {
var browser;
/* jshint unused:true */
var browser;
/* jshint unused:false */
}

@@ -5,28 +5,10 @@ var http = require('http');

var pass, isArray, isArrayBufferView, _undefined, nextTick;
/* jshint unused:true */
var mixInPromise, pass, isArray, isArrayBufferView, _undefined, nextTick, isFormData;
/* jshint unused:false */
var decompress = function(output, encoding, cb) {
if(encoding === 'gzip') {
zlib.gunzip(output, cb);
} else if(encoding === 'deflate') {
zlib.inflate(output, function(err, out) {
if(err) {
return zlib.inflateRaw(output, cb);
}
cb(null, out);
});
} else if(encoding === 'identity') {
process.nextTick(function() {
cb(null, output);
});
} else {
process.nextTick(function() {
cb(new Error('unsupported encoding ' + encoding));
});
}
};
// http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method
var forbiddenInputHeaders = ['accept-charset', 'accept-encoding', 'access-control-request-headers', 'access-control-request-method', 'connection', 'content-length', 'content-transfer-encoding', 'cookie', 'cookie2', 'date', 'dnt', 'expect', 'host', 'keep-alive', 'origin', 'referer', 'te', 'trailer', 'transfer-encoding', 'upgrade', 'user-agent', 'via'];
var validateInputHeaders = function(headers) {
'use strict';
for(var header in headers) {

@@ -49,2 +31,3 @@ if(headers.hasOwnProperty(header)) {

var copy = function(from, to) {
'use strict';
Object.keys(from).forEach(function(key) {

@@ -56,4 +39,31 @@ to[key] = from[key];

var emptyBuffer = new Buffer([]);
var utf8CharacterSizeFromHeaderByte = function(b) {
'use strict';
if(b < 128) {
// one byte, ascii character
return 1;
}
/* jshint bitwise:false */
var mask = (1 << 7) | (1 << 6);
var test = 128;
if((b & mask) === test) {
// b is not a header byte
return 0;
}
for(var length = 1; (b & mask) !== test; length += 1) {
mask = (mask >> 1) | 128;
test = (test >> 1) | 128;
}
/* jshint bitwise:true */
// multi byte utf8 character
return length;
};
var httpinvoke = function(uri, method, options, cb) {
var mixInPromise, promise, failWithoutRequest, uploadProgressCb, inputLength, noData, timeout, inputHeaders, statusCb, initDownload, updateDownload, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter;
'use strict';
/* jshint unused:true */
var promise, failWithoutRequest, uploadProgressCb, downloadProgressCb, inputLength, inputHeaders, statusCb, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter, partialOutputMode;
/* jshint unused:false */
/*************** initialize helper variables **************/

@@ -73,8 +83,2 @@ try {

uri = url.parse(uri);
if(timeout > 0) {
setTimeout(function() {
cb(new Error('Timeout of ' + timeout + 'ms exceeded'));
cb = null;
}, timeout);
}
var req = http.request({

@@ -88,5 +92,4 @@ hostname: uri.hostname,

var contentEncoding;
if(cb === null) {
ignorantlyConsume(res);
return;
if(!cb) {
return ignorantlyConsume(res);
}

@@ -97,2 +100,7 @@

contentEncoding = outputHeaders['content-encoding'];
if(['identity', 'gzip', 'deflate'].indexOf(contentEncoding) < 0) {
cb(new Error('unsupported Content-Encoding ' + contentEncoding));
cb = null;
return ignorantlyConsume(res);
}
delete outputHeaders['content-encoding'];

@@ -106,51 +114,80 @@ } else {

uploadProgressCb(inputLength, inputLength);
if(cb === null) {
ignorantlyConsume(res);
return;
if(!cb) {
return ignorantlyConsume(res);
}
statusCb(status, outputHeaders);
if(cb === null) {
ignorantlyConsume(res);
return;
if(!cb) {
return ignorantlyConsume(res);
}
updateDownload(0);
if(cb === null) {
ignorantlyConsume(res);
return;
if(contentEncoding === 'identity' && 'content-length' in outputHeaders) {
outputLength = Number(outputHeaders['content-length']);
}
if(typeof outputHeaders['content-length'] !== 'undefined') {
initDownload(Number(outputHeaders['content-length']));
if(cb === null) {
ignorantlyConsume(res);
return;
}
var partial = partialOutputMode === 'disabled' ? _undefined : (outputBinary ? [] : '');
downloadProgressCb(0, outputLength, partial);
if(!cb) {
return ignorantlyConsume(res);
}
if(method === 'HEAD' || typeof outputHeaders['content-type'] === 'undefined') {
if(method === 'HEAD') {
ignorantlyConsume(res);
return noData();
downloadProgressCb(0, 0, partial);
return cb && cb(null, _undefined, status, outputHeaders);
}
var output = [], downloaded = 0;
res.on('data', function(chunk) {
if(cb === null) {
var inputStream;
if(contentEncoding === 'identity') {
inputStream = res;
} else {
inputStream = zlib['create' + (contentEncoding === 'gzip' ? 'Gunzip' : 'InflateRaw')]();
res.pipe(inputStream);
}
var output = [], downloaded = 0, leftover = emptyBuffer;
inputStream.on('data', function(chunk) {
if(!cb) {
return;
}
if(partialOutputMode !== 'disabled' && !outputBinary) {
chunk = Buffer.concat([leftover, chunk]);
var charsize = 0, newLeftoverLength = 0;
while(charsize === 0 && newLeftoverLength < chunk.length) {
newLeftoverLength += 1;
charsize = utf8CharacterSizeFromHeaderByte(chunk[chunk.length - newLeftoverLength]);
}
if(newLeftoverLength === charsize) {
leftover = emptyBuffer;
} else {
leftover = chunk.slice(chunk.length - newLeftoverLength);
chunk = chunk.slice(0, chunk.length - newLeftoverLength);
}
}
downloaded += chunk.length;
output.push(chunk);
updateDownload(downloaded);
if(cb === null) {
return;
var partial;
if(partialOutputMode !== 'disabled') {
partial = partialOutputMode === 'chunked' ? chunk : Buffer.concat(output);
if(!outputBinary) {
partial = partial.toString('utf8');
}
}
downloadProgressCb(downloaded, outputLength, partial);
});
res.on('end', function() {
if(cb === null) {
inputStream.on('error', cb);
inputStream.on('end', function() {
if(!cb) {
return;
}
updateDownload(downloaded);
if(cb === null) {
return;
}
// just in case the utf8 text stream was damaged, and there is leftover
output.push(leftover);
downloaded += leftover.length;
if(typeof outputLength === 'undefined') {

@@ -160,21 +197,32 @@ outputLength = downloaded;

decompress(Buffer.concat(output, downloaded), contentEncoding, function(err, output) {
if(!cb) {
return;
}
if(err) {
cb(err);
cb = null;
return;
}
if(!outputBinary) {
output = output.toString('utf8');
}
try {
cb(null, outputConverter(output), status, outputHeaders);
} catch(err) {
cb(err);
}
cb = null;
});
if(downloaded !== outputLength) {
return cb(new Error('network error'));
}
output = Buffer.concat(output, downloaded);
if(!outputBinary) {
output = output.toString('utf8');
}
var partial;
if(partialOutputMode === 'chunked') {
partial = outputBinary ? leftover : leftover.toString('utf8');
} else if(partialOutputMode === 'joined') {
partial = outputBinary ? output : output.toString('utf8');
}
downloadProgressCb(outputLength, outputLength, partial);
if(!cb) {
return;
}
if(outputLength === 0 && typeof outputHeaders['content-type'] === 'undefined') {
return cb(null, _undefined, status, outputHeaders);
}
try {
cb(null, outputConverter(output), status, outputHeaders);
} catch(err) {
cb(err);
}
});

@@ -184,3 +232,3 @@ });

nextTick(function() {
if(cb === null) {
if(!cb) {
return;

@@ -194,20 +242,17 @@ }

req.write(input);
} else {
inputLength = 0;
}
req.on('error', function(e) {
if(cb === null) {
req.on('error', function() {
if(!cb) {
return;
}
cb(e);
cb = null;
cb(new Error('network error'));
});
req.end();
promise = function() {
if(cb === null) {
if(!cb) {
return;
}
// these statements are in case "abort" is called in "finished" callback
var _cb = cb;
cb = null;
_cb(new Error('abort'));
cb(new Error('abort'));
};

@@ -227,3 +272,5 @@ return mixInPromise(promise);

httpinvoke.requestTextOnly = false;
httpinvoke.PATCH = true;
httpinvoke.corsFineGrainedTimeouts = true;
module.exports = httpinvoke;

@@ -5,2 +5,3 @@ var cfg = require('../dummyserver-config');

describe('abort', function() {
'use strict';
this.timeout(10000);

@@ -17,2 +18,61 @@ cfg.eachBase(function(postfix, url) {

});
it('does not cause any trouble when calling in "downloading"' + postfix, function(done) {
var abort = httpinvoke(url, {
finished: function(err) {
if(!err) {
return done(new Error('did not end with error'));
}
if(err.message !== 'abort') {
return done(new Error('message was not "abort"'));
}
done();
},
downloading: function() {
abort();
}
});
});
it('does not cause any trouble when calling in "uploading"' + postfix, function(done) {
var abort = httpinvoke(url, {
finished: function(err) {
if(!err) {
return done(new Error('did not end with error'));
}
if(err.message !== 'abort') {
return done(new Error('message was not "abort"'));
}
done();
},
uploading: function() {
abort();
}
});
});
it('does not cause any trouble when calling in "gotStatus"' + postfix, function(done) {
var abort = httpinvoke(url, {
finished: function(err) {
if(!err) {
return done(new Error('did not end with error'));
}
if(err.message !== 'abort') {
return done(new Error('message was not "abort"'));
}
done();
},
gotStatus: function() {
abort();
}
});
});
it('does not cause any trouble when calling in "finished"' + postfix, function(done) {
var abort = httpinvoke(url, {
finished: function(err) {
if(err) {
return done(err);
}
abort();
done();
}
});
});
it('ensures that no callbacks, except finished with Error, are called when invoked immediately' + postfix, function(done) {

@@ -19,0 +79,0 @@ var callback = function(callback) {

@@ -5,2 +5,3 @@ var cfg = require('../dummyserver-config');

describe('sequence of callback options', function() {
'use strict';
this.timeout(10000);

@@ -7,0 +8,0 @@ cfg.eachBase(function(postfix, url) {

@@ -5,2 +5,3 @@ var cfg = require('../dummyserver-config');

describe('calling', function() {
'use strict';
this.timeout(10000);

@@ -53,10 +54,2 @@ cfg.eachBase(function(postfix, url) {

});
it('immediately errors-out when url is not reachable', function(done) {
httpinvoke('http://non-existant.url/foobar', 'GET', function(err) {
if(typeof err !== 'object' || err === null || !(err instanceof Error)) {
return done(new Error('error was not received'));
}
done();
});
});
});

@@ -5,2 +5,3 @@ var cfg = require('../dummyserver-config');

describe('support for "Content-Encoding" from server-side', function() {
'use strict';
this.timeout(10000);

@@ -7,0 +8,0 @@ cfg.eachBase(function(postfix, url) {

@@ -5,2 +5,3 @@ var cfg = require('../dummyserver-config');

describe('"converters" option', function() {
'use strict';
this.timeout(10000);

@@ -7,0 +8,0 @@ it('basically works', function(done) {

@@ -5,2 +5,3 @@ var cfg = require('../dummyserver-config');

describe('"cors" feature flag', function() {
'use strict';
this.timeout(10000);

@@ -11,5 +12,2 @@ it('exists', function(done) {

}
if(!httpinvoke.cors) {
console.log('CORS is not supported');
}
done();

@@ -16,0 +14,0 @@ });

@@ -1,5 +0,5 @@

var cfg = require('../dummyserver-config');
var httpinvoke = require('../httpinvoke-node');
describe('"corsCredentials" feature flag', function() {
'use strict';
this.timeout(10000);

@@ -10,5 +10,2 @@ it('exists', function(done) {

}
if(!httpinvoke.corsCredentials) {
console.log('CORS credentials sending is not supported');
}
done();

@@ -15,0 +12,0 @@ });

var cfg = require('../dummyserver-config');
var httpinvoke = require('../httpinvoke-node');
var arraysEqual = function(a, b) {
'use strict';
if(a.length !== b.length) {
return false;
}
for(var i = 0; i < a.length; i += 1) {
if(a[i] !== b[i]) {
return false;
}
}
return true;
};
describe('"downloading" option', function() {
'use strict';
this.timeout(10000);
var urls = [];
cfg.eachBase(function(postfix, url, crossDomain) {
it('is called at least twice' + postfix, function(done) {
var count = 0;
var abort = httpinvoke(url, {
downloading: function() {
count += 1;
if(count === 2) {
urls.push({
postfix: postfix,
url: url,
crossDomain: crossDomain
});
urls.push({
postfix: postfix + ' (deflate)',
url: url + 'contentEncoding/deflate',
crossDomain: crossDomain
});
urls.push({
postfix: postfix + ' (gzip)',
url: url + 'contentEncoding/gzip',
crossDomain: crossDomain
});
urls.push({
postfix: postfix + ' (noentity)',
url: url + 'noentity',
crossDomain: crossDomain
});
});
cfg.eachBase(function(postfix, url) {
['chunked', 'joined'].forEach(function(partial) {
it('has argument "partial", if option "partialOutputMode" is set to "' + partial + '"' + postfix, function(done) {
httpinvoke(url + 'big', {
partialOutputMode: partial,
downloading: function(current, total, partial) {
if(typeof partial !== 'string' && typeof partial !== 'object') {
done(new Error('partial is neither string, nor object'));
done = null;
return;
}
},
finished: function(err) {
if(!done) {
return;
}
if(err) {
return done(err);
}
done();
done = null;
}
});
});
});
it('has the concatenated values of argument "partial" equal to "output", when "partialOutputMode" is "chunked" and "outputType" is "text"' + postfix, function(done) {
var partials = '';
httpinvoke(url + 'big', {
partialOutputMode: 'chunked',
outputType: 'text',
downloading: function(current, total, partial) {
partials += partial;
},
finished: function(err) {
if(done === null) {
finished: function(err, output) {
if(!done) {
return;

@@ -24,25 +82,63 @@ }

}
if(count < 2) {
done(new Error('It was called ' + count + ' times'));
if(partials !== output) {
return done(new Error('Concatenated values of argument "partial" is not equal to output'));
}
abort();
done();
}
});
});
it('has total be 0, if there is no entity body' + postfix, function(done) {
httpinvoke(url + 'noentity', 'POST', {
downloading: function(_, total) {
if(done === null) {
it('has the concatenated values of argument "partial" equal to "output", when "partialOutputMode" is "chunked" and "outputType" is "bytearray"' + postfix, function(done) {
var partials = [];
httpinvoke(url + 'big', {
partialOutputMode: 'chunked',
outputType: 'bytearray',
downloading: function(current, total, partial) {
partials = partials.concat([].slice.call(partial));
},
finished: function(err, output) {
if(!done) {
return;
}
if(typeof total === 'undefined') {
if(err) {
return done(err);
}
if(!arraysEqual(output, partials)) {
return done(new Error('Concatenated values of argument "partial" is not equal to output'));
}
done();
}
});
});
it('has argument "partial" on the last call equal to "output", when "partialOutputMode" is "joined" and "outputType" is "text"' + postfix, function(done) {
var lastPartial;
httpinvoke(url + 'big', {
partialOutputMode: 'joined',
outputType: 'text',
downloading: function(current, total, partial) {
lastPartial = partial;
},
finished: function(err, output) {
if(!done) {
return;
}
if(total !== 0) {
done(new Error('total is not 0'));
done = null;
if(err) {
return done(err);
}
if(lastPartial !== output) {
return done(new Error('Last partial is not equal to output'));
}
done();
}
});
});
it('has argument "partial" on the last call equal to "output", when "partialOutputMode" is "joined" and "outputType" is "bytearray"' + postfix, function(done) {
var lastPartial;
httpinvoke(url + 'big', {
partialOutputMode: 'joined',
outputType: 'bytearray',
downloading: function(current, total, partial) {
lastPartial = partial;
},
finished: function(err, output) {
if(done === null) {
if(!done) {
return;

@@ -53,4 +149,4 @@ }

}
if(typeof output !== 'undefined') {
return done(new Error('Output is not undefined'));
if(!arraysEqual(output, lastPartial)) {
return done(new Error('Last partial is not equal to output'));
}

@@ -61,5 +157,43 @@ done();

});
});
urls.forEach(function(url) {
var postfix = url.postfix;
url = url.url;
it('is called at least twice' + postfix, function(done) {
var count = 0;
httpinvoke(url, {
downloading: function() {
count += 1;
},
finished: function(err) {
if(err) {
return done(err);
}
if(count < 2) {
done(new Error('It was called ' + count + ' times'));
}
done();
}
});
});
it('has total be 0, if there is no entity body' + postfix, function(done) {
var total;
httpinvoke(url, 'POST', {
downloading: function(_, _total) {
total = _total;
},
finished: function(err, output) {
if(err) {
return done(err);
}
if(typeof output === 'undefined' && total !== 0) {
return done(new Error('total is not 0'));
}
done();
}
});
});
it('has the last total be always defined' + postfix, function(done) {
var defined = false;
var abort = httpinvoke(url, {
httpinvoke(url, {
downloading: function(_, total) {

@@ -81,3 +215,3 @@ defined = typeof total !== 'undefined';

var defined = false;
var abort = httpinvoke(url, {
httpinvoke(url, {
downloading: function(_, total) {

@@ -229,21 +363,2 @@ if(typeof total !== 'undefined') {

});
it('has the last "total" be equal to output length, when outputType="bytearray"' + postfix, function(done) {
var total = null;
httpinvoke(url, {
outputType: 'bytearray',
downloading: function(_, _total) {
total = _total;
},
finished: function(err, output) {
if(err) {
return done(err);
}
if(output.length !== total) {
done(new Error('The last "total"=' + total + ' was not equal to output length = ' + output.length));
} else {
done();
}
}
});
});
it('has "current" be non-decreasing' + postfix, function(done) {

@@ -250,0 +365,0 @@ var current = null;

@@ -5,2 +5,3 @@ var cfg = require('../dummyserver-config');

describe('"finished" option', function() {
'use strict';
this.timeout(10000);

@@ -18,3 +19,3 @@ cfg.eachBase(function(postfix, url, crossDomain) {

if(count === 1) {
setTimeout(function() {
global.setTimeout(function() {
if(done === null) {

@@ -33,3 +34,5 @@ return;

httpinvoke(url, {
/* jshint unused:false */
finished: function(err, _, __, headers) {
/* jshint unused:true */
if(err) {

@@ -45,3 +48,3 @@ return done(err);

httpinvoke(url, {
finished: function(err, _, status, __) {
finished: function(err, _, status) {
if(err) {

@@ -48,0 +51,0 @@ return done(err);

@@ -5,2 +5,3 @@ var cfg = require('../dummyserver-config');

describe('"gotStatus" option', function() {
'use strict';
this.timeout(10000);

@@ -18,3 +19,3 @@ cfg.eachBase(function(postfix, url, crossDomain) {

httpinvoke(url, {
gotStatus: function(status, __) {
gotStatus: function(status) {
if(status !== 200) {

@@ -21,0 +22,0 @@ return done(new Error('status argument is not defined'));

@@ -8,2 +8,3 @@ var cfg = require('../dummyserver-config');

describe('"headers" option', function() {
'use strict';
this.timeout(10000);

@@ -10,0 +11,0 @@ cfg.eachBase(function(postfix, url, crossDomain) {

@@ -5,3 +5,4 @@ var cfg = require('../dummyserver-config');

var makeErrorFinished = function(done) {
return function(err, output) {
'use strict';
return function(err) {
if(err) {

@@ -15,2 +16,3 @@ return done();

describe('"input" option', function() {
'use strict';
this.timeout(10000);

@@ -20,4 +22,4 @@ cfg.eachBase(function(postfix, url) {

httpinvoke(url, 'POST', {
inputType: "string",
input: "test",
inputType: 'string',
input: 'test',
finished: makeErrorFinished(done)

@@ -28,15 +30,9 @@ });

httpinvoke(url, 'POST', {
inputType: "text",
inputType: 'text',
finished: makeErrorFinished(done)
});
});
it('finishes with error, if "inputType" option is "auto" and "input" option is undefined' + postfix, function(done) {
httpinvoke(url, 'POST', {
inputType: "auto",
finished: makeErrorFinished(done)
});
});
it('finishes with error, if "inputType" option is "bytearray" and "input" option is undefined' + postfix, function(done) {
httpinvoke(url, 'POST', {
inputType: "bytearray",
inputType: 'bytearray',
finished: makeErrorFinished(done)

@@ -55,3 +51,3 @@ });

httpinvoke(url, 'POST', {
inputType: "auto",
inputType: 'auto',
input: 'foobar',

@@ -100,4 +96,4 @@ finished: done

});
if(typeof Uint8Array !== 'undefined') {
var buffer = new Uint8Array(cfg.bytearrayTest()).buffer;
if(typeof global.Uint8Array !== 'undefined') {
var buffer = new global.Uint8Array(cfg.bytearrayTest()).buffer;
var classes = ['Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array', 'Float32Array', 'Float64Array'];

@@ -150,3 +146,3 @@

var str;
if(typeof Uint8Array === 'undefined') {
if(typeof global.Uint8Array === 'undefined') {
str = '';

@@ -157,8 +153,8 @@ for(var i = 0; i < bytearray.length; i += 1) {

} else {
str = new Uint8Array(bytearray).buffer;
str = new global.Uint8Array(bytearray).buffer;
}
var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
var BlobBuilder = global.BlobBuilder || global.WebKitBlobBuilder || global.MozBlobBuilder || global.MSBlobBuilder;
if(typeof BlobBuilder === 'undefined') {
try {
return new Blob([str], {
return new global.Blob([str], {
type: 'application/octet-stream'

@@ -165,0 +161,0 @@ });

@@ -5,2 +5,3 @@ var cfg = require('../dummyserver-config');

describe('supported HTTP methods', function() {
'use strict';
this.timeout(10000);

@@ -14,3 +15,3 @@ cfg.eachBase(function(postfix, url, crossDomain) {

}
if(crossDomain && method === 'PATCH' && !httpinvoke.corsPATCH) {
if(!httpinvoke.PATCH || (crossDomain && method === 'PATCH' && !httpinvoke.corsPATCH)) {
return;

@@ -17,0 +18,0 @@ }

@@ -5,2 +5,3 @@ var cfg = require('../dummyserver-config');

describe('"output" argument of "finished" option', function() {
'use strict';
this.timeout(10000);

@@ -10,4 +11,4 @@ cfg.eachBase(function(postfix, url, crossDomain) {

httpinvoke(url, {
outputType: "string",
finished: function(err, output) {
outputType: 'string',
finished: function(err) {
if(err) {

@@ -45,3 +46,3 @@ return done();

}
if(!(output instanceof Buffer)) {
if(!(output instanceof global.Buffer)) {
return done(new Error('Received output is not a Buffer'));

@@ -61,3 +62,3 @@ }

}
if(!(output instanceof Uint8Array)) {
if(!(output instanceof global.Uint8Array)) {
return done(new Error('Received output is not an Uint8Array'));

@@ -64,0 +65,0 @@ }

var cfg = require('../dummyserver-config');
var httpinvoke = require('../httpinvoke-node');
function isValidReason(reason) {
'use strict';
return typeof reason === 'object' && reason !== null && reason instanceof Error;
}
function isValidResponse(response, crossDomain) {
'use strict';
return typeof response === 'object' && typeof response.body === 'string' && (typeof response.statusCode === 'number' || !(!crossDomain || httpinvoke.corsStatus)) && typeof response.headers === 'object';
}
function isValidProgress(progress, crossDomain) {
'use strict';
if(typeof progress !== 'object' || typeof progress.type !== 'string') {
return false;
}
if(progress.type === 'upload') {
if(typeof progress.current !== 'number') {
return false;
}
if(typeof progress.total !== 'number') {
return false;
}
if(progress.current > progress.total) {
return false;
}
} else if(progress.type === 'download') {
if(typeof progress.current !== 'number') {
return false;
}
if(typeof progress.total === 'number') {
if(progress.current > progress.total) {
return false;
}
}
} else if(progress.type === 'headers') {
if((!crossDomain || httpinvoke.corsStatus) && typeof progress.statusCode !== 'number') {
return false;
}
if(typeof progress.headers !== 'object') {
return false;
}
if(typeof progress.headers['content-type'] !== 'string') {
return false;
}
} else if(progress.type === 'body') {
if(typeof progress.statusCode !== 'number') {
return false;
}
if(typeof progress.headers !== 'object') {
return false;
}
if(typeof progress.headers['content-type'] !== 'string') {
return false;
}
if(typeof progress.body !== 'string') {
return false;
}
} else {
return false;
}
return true;
}
describe('promise', function() {
'use strict';
this.timeout(10000);
cfg.eachBase(function(postfix, url) {
cfg.eachBase(function(postfix, url, crossDomain) {
it('supports Promises/A' + postfix, function(done) {

@@ -12,6 +76,6 @@ var promise = httpinvoke(url).then(function(response) {

}
if(isValidResponse(response)) {
if(isValidResponse(response, crossDomain)) {
done();
} else {
done(new Error('invalid response'));
done(new Error('invalid response ' + JSON.stringify(response)));
}

@@ -27,4 +91,4 @@ }, function(error) {

}
if(!isValidProgress(progress)) {
done(new Error('invalid progress'));
if(!isValidProgress(progress, crossDomain)) {
done(new Error('invalid progress ' + JSON.stringify(progress)));
done = null;

@@ -38,2 +102,21 @@ }

});
it('supports skipping onresolved' + postfix, function(done) {
httpinvoke(url, {
finished: done
}).then(null, function() {
}, function() {
});
});
it('supports skipping onrejected' + postfix, function(done) {
httpinvoke('foo:bar', {
finished: function(err) {
if(!err) {
return done(new Error('expected error'));
}
done();
}
}).then(function() {
}, null, function() {
});
});
it('supports Promises/A+ requirement, that callbacks must be called as functions' + postfix, function(done) {

@@ -44,14 +127,16 @@ httpinvoke(url).then(function() {

}
if(this !== global) {
if(this !== global && this !== null) {
done(new Error('onResolved was not called as a function'));
done = null;
return done(new Error('onResolved was not called as a function'));
return;
}
httpinvoke(url, 'ERROR').then(function() {
}, function(err) {
}, function() {
if(!done) {
return;
}
if(this !== global) {
if(this !== global && this !== null) {
done(new Error('onRejected was not called as a function'));
done = null;
return done(new Error('onRejected was not called as a function'));
return;
}

@@ -65,5 +150,5 @@ done();

}
if(this !== global) {
if(this !== global && this !== null) {
done(new Error('onProgress was not called as a function'));
done = null;
return done(new Error('onProgress was not called as a function'));
}

@@ -82,4 +167,4 @@ });

httpinvoke(url).then(function(response) {
if(!isValidResponse(response)) {
done(new Error('invalid response'));
if(!isValidResponse(response, crossDomain)) {
done(new Error('invalid response ' + JSON.stringify(response)));
}

@@ -150,63 +235,33 @@ done();

});
['chunked', 'joined'].forEach(function(partial) {
it('supports .partial in "download" progress event, when option "partialOutputMode" is set to "' + partial + '"' + postfix, function(done) {
httpinvoke(url, {
partialOutputMode: partial
}).then(function() {
if(!done) {
return;
}
done();
done = null;
}, function(err) {
if(!done) {
return;
}
done(err);
done = null;
}, function(progress) {
if(!isValidProgress(progress, crossDomain)) {
done(new Error('invalid progress'));
done = null;
return;
}
if(progress.type === 'download' && typeof progress.partial !== 'string' && typeof progress.partial !== 'object') {
done(new Error('progress.partial is neither string, nor object'));
done = null;
return;
}
});
});
});
});
});
function isValidReason(reason) {
return typeof reason === 'object' && reason !== null && reason instanceof Error;
}
function isValidResponse(response) {
return typeof response === 'object' && typeof response.body === 'string' && typeof response.statusCode === 'number' && typeof response.headers === 'object';
}
function isValidProgress(progress) {
if(typeof progress !== 'object' || typeof progress.type !== 'string') {
return false;
}
if(progress.type === 'upload') {
if(typeof progress.current !== 'number') {
return false;
}
if(typeof progress.total !== 'number') {
return false;
}
if(progress.current > progress.total) {
return false;
}
} else if(progress.type === 'download') {
if(typeof progress.current !== 'number') {
return false;
}
if(typeof progress.total === 'number') {
if(progress.current > progress.total) {
return false;
}
}
} else if(progress.type === 'headers') {
if(typeof progress.statusCode !== 'number') {
return false;
}
if(typeof progress.headers !== 'object') {
return false;
}
if(typeof progress.headers['content-type'] !== 'string') {
return false;
}
} else if(progress.type === 'body') {
if(typeof progress.statusCode !== 'number') {
return false;
}
if(typeof progress.headers !== 'object') {
return false;
}
if(typeof progress.headers['content-type'] !== 'string') {
return false;
}
if(typeof progress.body !== 'string') {
return false;
}
} else {
return false;
}
return true;
}

@@ -5,2 +5,3 @@ var cfg = require('../dummyserver-config');

describe('"status" argument', function() {
'use strict';
this.timeout(10000);

@@ -17,2 +18,5 @@ cfg.eachBase(function(postfix, url, crossDomain) {

Object.keys(cfg.status[code]).forEach(function(method) {
if(method === 'PATCH' && !httpinvoke.PATCH) {
return;
}
cfg.status[code][method].forEach(function(params, i) {

@@ -30,18 +34,7 @@ var _postfix = postfix;

corsExposedHeaders: [],
finished: function(err, output, status, headers) {
finished: function(err, output) {
if(err) {
return done(err);
}
if(status !== Number(code)) {
console.log('Status code ' + code + ' was expected, but received ' + status);
}
if(params.location) {
if(typeof headers.location === 'undefined') {
console.log('Location header was expected, but not received');
}
}
if(params.responseEntity) {
if(headers['content-type'] !== 'text/plain') {
console.log('Content-Type text/plain header was expected, but received ' + headers['content-type']);
}
if(params.partialResponse) {

@@ -60,5 +53,2 @@ if(output !== hello.substr(0, 5)) {

}
if(typeof headers['content-type'] !== 'undefined') {
console.log('Content-Type header was not expected, but received ' + headers['content-type']);
}
}

@@ -65,0 +55,0 @@ done();

@@ -5,7 +5,14 @@ var cfg = require('../dummyserver-config');

describe('"timeout" option', function() {
'use strict';
this.timeout(10000);
cfg.eachBase(function(postfix, url) {
it('forces finish with error when normal finish would take longer than specified timeout ' + postfix, function(done) {
httpinvoke(url + 'tenseconds', {
timeout: 3000,
it('lets finish without an error when the whole request would take shorter than specified timeout' + postfix, function(done) {
httpinvoke(url, {
timeout: 200,
finished: done
});
});
it('forces finish with error when the whole request would take longer than specified timeout' + postfix, function(done) {
httpinvoke(url + 'onesecondDownload', {
timeout: 200,
finished: function(err) {

@@ -19,3 +26,117 @@ if(typeof err !== 'object' || err === null || !(err instanceof Error)) {

});
it('forces finish with error when value is less than or equal to 0' + postfix, function(done) {
httpinvoke(url, {
timeout: 0,
finished: function(err) {
if(typeof err !== 'object' || err === null || !(err instanceof Error)) {
return done(new Error('An error was not received'));
}
done();
}
});
});
it('forces finish with error when value is greater than or equal to 1073741824' + postfix, function(done) {
httpinvoke(url, {
timeout: 1073741824,
finished: function(err) {
if(typeof err !== 'object' || err === null || !(err instanceof Error)) {
return done(new Error('An error was not received'));
}
done();
}
});
});
it('lets finish without an error when upload would take shorter than specified timeout' + postfix, function(done) {
httpinvoke(url, {
timeout: [200, 1073741823],
finished: done
});
});
it('lets finish without an error when upload would take shorter than specified upload timeout, but download would take longer than upload timeout' + postfix, function(done) {
httpinvoke(url + 'onesecondDownload', {
timeout: [200, 1073741823],
finished: done
});
});
it('forces finish with "upload timeout" error when upload would take longer than specified upload timeout' + postfix, function(done) {
httpinvoke(url + 'onesecondUpload', {
timeout: [200, 1073741823],
finished: function(err) {
if(typeof err !== 'object' || err === null || !(err instanceof Error) || err.message !== 'upload timeout') {
return done(new Error('A "upload timeout" error was not received'));
}
done();
}
});
});
it('forces finish with error when upload value is less than or equal to 0' + postfix, function(done) {
httpinvoke(url + 'onesecondUpload', {
timeout: [0, 1073741823],
finished: function(err) {
if(typeof err !== 'object' || err === null || !(err instanceof Error)) {
return done(new Error('An error was not received'));
}
done();
}
});
});
it('forces finish with error when upload value is greater than or equal to 1073741824' + postfix, function(done) {
httpinvoke(url + 'onesecondUpload', {
timeout: [1073741824, 1073741823],
finished: function(err) {
if(typeof err !== 'object' || err === null || !(err instanceof Error)) {
return done(new Error('An error was not received'));
}
done();
}
});
});
it('lets finish without an error when download would take shorter than specified timeout' + postfix, function(done) {
httpinvoke(url, {
timeout: [1073741823, 200],
finished: done
});
});
it('lets finish without an error when download would take shorter than specified download timeout, but upload would take longer than download timeout' + postfix, function(done) {
httpinvoke(url + 'onesecondUpload', {
timeout: [1073741823, 200],
finished: done
});
});
it('forces finish with "download timeout" error when download would take longer than specified download timeout' + postfix, function(done) {
httpinvoke(url + 'onesecondDownload', {
timeout: [1073741823, 200],
finished: function(err) {
if(typeof err !== 'object' || err === null || !(err instanceof Error) || err.message !== 'download timeout') {
return done(new Error('A "download timeout" error was not received'));
}
done();
}
});
});
it('forces finish with error when download value is less than or equal to 0' + postfix, function(done) {
httpinvoke(url + 'onesecondDownload', {
timeout: [1073741823, 0],
finished: function(err) {
if(typeof err !== 'object' || err === null || !(err instanceof Error)) {
return done(new Error('An error was not received'));
}
done();
}
});
});
it('forces finish with error when download value is greater than or equal to 1073741824' + postfix, function(done) {
httpinvoke(url + 'onesecondDownload', {
timeout: [1073741823, 1073741824],
finished: function(err) {
if(typeof err !== 'object' || err === null || !(err instanceof Error)) {
return done(new Error('An error was not received'));
}
done();
}
});
});
});
});

@@ -5,21 +5,48 @@ var cfg = require('../dummyserver-config');

describe('"uploading" option', function() {
'use strict';
this.timeout(10000);
var inputs = [{
var input, inputs = [];
inputs.push({
name: 'undefined',
inputLength: 0
});
if(global.FormData) {
inputs.push({
name: 'formdata',
inputType: 'formdata',
input: new global.FormData()
});
}
input = 'foobar';
inputs.push({
name: 'text',
inputType: 'text',
input: 'foobar'
}];
input: input,
inputLength: input.length
});
if(!httpinvoke.requestTextOnly) {
input = cfg.bytearrayTest();
inputs.push({
name: 'bytearray',
inputType: 'bytearray',
input: cfg.bytearrayTest()
input: input,
inputLength: input.length
});
}
var eachInput = function(fn) {
var _undefined;
for(var input = 0; input < inputs.length; input += 1) {
fn(inputs[input].inputType, inputs[input].input);
fn(inputs[input].inputType, inputs[input].input, inputs[input].inputLength, inputs[input].name);
fn('auto', inputs[input].input, inputs[input].inputLength, inputs[input].name);
fn(_undefined, inputs[input].input, inputs[input].inputLength, inputs[input].name);
}
};
cfg.eachBase(function(_postfix, url, crossDomain) {
eachInput(function(inputType, input) {
var postfix = _postfix + ' (' + inputType + ')';
cfg.eachBase(function(_postfix, url) {
eachInput(function(inputType, input, inputLength, name) {
var postfix = _postfix + ' (' + name + '-' + inputType + ')';
it('is called at least twice' + postfix, function(done) {

@@ -177,20 +204,22 @@ var count = 0;

});
it('has "total" be equal to input length' + postfix, function(done) {
var abort = httpinvoke(url, 'POST', {
inputType: inputType,
input: input,
uploading: function(_, total) {
if(done === null) {
return;
if(typeof inputLength === 'number') {
it('has "total" be equal to input length' + postfix, function(done) {
var abort = httpinvoke(url, 'POST', {
inputType: inputType,
input: input,
uploading: function(_, total) {
if(done === null) {
return;
}
if(inputLength !== total) {
done(new Error('"total"=' + total + ' was not equal to input length = ' + inputLength));
} else {
done();
}
done = null;
abort();
}
if(input.length !== total) {
done(new Error('"total"=' + total + ' was not equal to input length = ' + input.length));
} else {
done();
}
done = null;
abort();
}
});
});
});
}
it('has "current" be non-decreasing' + postfix, function(done) {

@@ -197,0 +226,0 @@ var current = null;

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc