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 0.0.10 to 1.0.0

Gruntfile.js

3

bower.json
{
"name": "httpinvoke",
"version": "0.0.10",
"version": "1.0.0",
"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.",
"ignore": [

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

{
"name": "httpinvoke",
"repo": "jakutis/httpinvoke",
"description": "HTTP client for JavaScript",
"version": "0.0.10",
"version": "1.0.0",
"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.",
"keywords": [

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

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

} else if(req.method === 'POST') {
var entity = 'Ši mokykla negriūva.\n';
var entity = new Buffer('Ši mokykla negriūva.\n');
var n = 100;

@@ -36,0 +36,0 @@ res.writeHead(200, {

@@ -5,8 +5,6 @@ var cfg = require('./karma-mocha-requireHack');

cfg.host = '0.0.0.0';
cfg.port = cfg.dummyserverPort;
cfg.path = '/';
// generated
cfg.url = 'http://' + cfg.host + ':' + cfg.port + cfg.path;
cfg.url = 'http://' + cfg.host + ':' + cfg.dummyserverPort + '/';
cfg.corsURL = cfg.url;
module.exports = cfg;
var http = require('http');
var cfg = require('./dummyserver-config');
var daemon = require('daemon');
var fs = require('fs');
var mime = require('mime');
var hello = new Buffer('Hello World\n', 'utf8');
var bigslowHello = function(res) {

@@ -45,35 +50,101 @@ var entity = 'This School Is Not Falling Apart.\n';

http.createServer(function (req, res) {
// on some Android devices CORS implementations are buggy
// that is why there needs to be two workarounds:
// 1. custom header with origin has to be passed, because they do not send Origin header on the actual request
// 2. caching must be disabled on serverside, because of unknown reasons, and when developing, you should clear cache on device, after disabling the cache on serverside
// read more: http://www.kinvey.com/blog/107/how-to-build-a-service-that-supports-every-android-browser
var corsHeaders = function(headers, req) {
headers['Access-Control-Allow-Credentials'] = 'true';
headers['Access-Control-Allow-Origin'] = '*';
headers['Access-Control-Allow-Methods'] = 'OPTIONS, POST, HEAD, PUT, DELETE, GET';
// workaround for #1: the server-side part: need X-Httpinvoke-Origin header
// workaround for Safari 4.0: need Content-Type header
headers['Access-Control-Allow-Headers'] = 'Content-Type, If-Modified-Since, Range, X-Httpinvoke-Origin';
// additional optional headers
headers['Access-Control-Expose-Headers'] = 'Content-Length, Content-Range, Location';
if(typeof req.headers.origin !== 'undefined') {
headers['Access-Control-Allow-Origin'] = req.headers.origin;
} else if(typeof req.headers['x-httpinvoke-origin'] !== 'undefined') {
// workaround for #1: the server-side part
headers['Access-Control-Allow-Origin'] = req.headers['x-httpinvoke-origin'];
}
};
var entityHeaders = function(headers) {
// workaround for #2: avoiding cache
headers.Pragma = 'no-cache';
headers.Expires = 'Thu, 01 Jan 1970 00:00:00 GMT';
headers['Last-Modified'] = new Date().toGMTString();
headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0';
};
var outputStatus = function(req, res) {
var code, i, max = 0;
Object.keys(cfg.status).forEach(function(code) {
Object.keys(cfg.status[code]).forEach(function(method) {
if(max < cfg.status[code][method].length) {
max = cfg.status[code][method].length;
}
});
});
if(Object.keys(cfg.status).some(function(_code) {
code = _code;
if(endsWith(req.url, '/status/' + code)) {
for(i = 0; i < max; i += 1) {
if(req.url === req.proxyPath + '/' + i + '/status/' + code) {
break;
}
}
return true;
}
})) {
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';
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 {
if(code === '407') {
headers['Proxy-Authenticate'] = 'Basic realm="httpinvoke"';
}
res.writeHead(Number(code), headers);
res.end();
}
}
return true;
}
return false;
};
var listen = function (req, res) {
req.proxyPath = req.url.substr(0, cfg.proxyPath.length) === cfg.proxyPath ? cfg.proxyPath : '';
res.useChunkedEncodingByDefault = false;
var output = function(status, body, head, mimeType) {
// on some Android devices CORS implementations are buggy
// that is why there needs to be two workarounds:
// 1. custom header with origin has to be passed, because they do not send Origin header on the actual request
// 2. caching must be disabled on serverside, because of unknown reasons, and when developing, you should clear cache on device, after disabling the cache on serverside
// read more: http://www.kinvey.com/blog/107/how-to-build-a-service-that-supports-every-android-browser
var headers = {
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'OPTIONS, POST, HEAD, PUT, DELETE, GET',
// workaround for #1: the server-side part: need X-Httpinvoke-Origin header
// workaround for Safari 4.0: need Content-Type header
'Access-Control-Allow-Headers': 'Content-Type, X-Httpinvoke-Origin',
// workaround for #2: avoiding cache
'Pragma': 'no-cache',
'Expires': 'Thu, 01 Jan 1970 00:00:00 GMT',
'Last-Modified': new Date().toGMTString(),
'Cache-Control': 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
};
if(body !== null) {
entityHeaders(headers);
headers['Content-Type'] = mimeType;
headers['Content-Length'] = String(body.length);
}
if(typeof req.headers.origin !== 'undefined') {
headers['Access-Control-Allow-Origin'] = req.headers.origin;
} else if(typeof req.headers['x-httpinvoke-origin'] !== 'undefined') {
// workaround for #1: the server-side part
headers['Access-Control-Allow-Origin'] = req.headers['x-httpinvoke-origin'];
}
corsHeaders(headers, req);
res.writeHead(status, headers);

@@ -88,19 +159,26 @@ if(body === null || head) {

if(err) {
return output(200, new Buffer(err.message, 'utf8'), false, 'text/plain; charset=UTF-8');
return output(200, new Buffer(err.stack, 'utf8'), false, 'text/plain; charset=UTF-8');
}
output(200, new Buffer('OK', 'utf8'), false, 'text/plain; charset=UTF-8');
};
var hello = new Buffer('Hello World\n', 'utf8');
if(req.method === 'OPTIONS') {
output(200, new Buffer([]), false, 'text/plain; charset=UTF-8');
} else if(req.method === 'POST') {
if(endsWith(req.url, '/noentity')) {
return output(200, new Buffer([]), false, 'text/plain; charset=UTF-8');
}
if(outputStatus(req, res)) {
return;
}
if(req.method === 'POST') {
if(req.url === req.proxyPath + '/noentity') {
output(204, null, false);
} else if(endsWith(req.url, '/headers/contentType')) {
} else if(req.url === req.proxyPath + '/headers/contentType') {
output(200, new Buffer(typeof req.headers['content-type'] === 'undefined' ? 'undefined' : req.headers['content-type'], 'utf8'), false, 'text/plain; charset=UTF-8');
} else if(endsWith(req.url, '/bytearray')) {
} else if(req.url === req.proxyPath + '/bytearray') {
readEntityBody(req, false, cfg.makeByteArrayFinished(reportTest));
} else if(endsWith(req.url, '/text/utf8')) {
} else if(req.url === req.proxyPath + '/text/utf8') {
readEntityBody(req, true, cfg.makeTextFinished(reportTest));
} else if(req.url === req.proxyPath + '/boolean') {
readEntityBody(req, false, function(err, input) {
output(200, input, false, 'text/plain; charset=UTF-8');
});
} else {

@@ -116,17 +194,19 @@ output(200, hello, false, 'text/plain; charset=UTF-8');

} else if(req.method === 'GET') {
if(endsWith(req.url, '/bigslow')) {
if(req.url === req.proxyPath + '/') {
output(200, hello, false, 'text/plain; charset=UTF-8');
} else if(req.url === req.proxyPath + '/bigslow') {
bigslowHello(res);
} else if(endsWith(req.url, '/text/utf8')) {
} else if(req.url === req.proxyPath + '/text/utf8') {
output(200, new Buffer(cfg.textTest(), 'utf8'), false, 'text/plain; charset=UTF-8');
} else if(endsWith(req.url, '/text/utf8/empty')) {
} else if(req.url === req.proxyPath + '/text/utf8/empty') {
output(200, new Buffer('', 'utf8'), false, 'text/plain; charset=UTF-8');
} else if(endsWith(req.url, '/json')) {
} else if(req.url === req.proxyPath + '/json') {
output(200, new Buffer(JSON.stringify(cfg.jsonTest()), 'utf8'), false, 'application/json');
} else if(endsWith(req.url, '/json/null')) {
} else if(req.url === req.proxyPath + '/json/null') {
output(200, new Buffer('null', 'utf8'), false, 'application/json');
} else if(endsWith(req.url, '/bytearray')) {
} else if(req.url === req.proxyPath + '/bytearray') {
output(200, new Buffer(cfg.bytearrayTest()), false, 'application/octet-stream');
} else if(endsWith(req.url, '/bytearray/empty')) {
} else if(req.url === req.proxyPath + '/bytearray/empty') {
output(200, new Buffer([]), false, 'application/octet-stream');
} else if(endsWith(req.url, '/tenseconds')) {
} else if(req.url === req.proxyPath + '/tenseconds') {
setTimeout(function() {

@@ -136,3 +216,13 @@ output(200, hello, false, 'text/plain; charset=UTF-8');

} else {
output(200, hello, false, 'text/plain; charset=UTF-8');
fs.realpath(__dirname + req.url.substr(req.proxyPath.length), function(err, path) {
if(err || path.substr(0, __dirname.length) !== __dirname) {
return output(404, null, false);
}
fs.readFile(path, function(err, contents) {
if(err) {
return output(404, null, false);
}
output(200, contents, false, mime.lookup(path));
});
});
}

@@ -142,2 +232,13 @@ } else {

}
}).listen(cfg.port, cfg.host);
};
if(fs.existsSync('./dummyserver.pid')) {
console.log('Error: file ./dummyserver.pid already exists');
process.exit(1);
} else {
console.log('HTML test runner available at http://localhost:' + cfg.dummyserverPort + '/test/index.html');
daemon();
fs.writeFileSync('./dummyserver.pid', String(process.pid));
http.createServer(listen).listen(cfg.dummyserverPort, cfg.host);
http.createServer(listen).listen(cfg.dummyserverPortAlternative, cfg.host);
}

@@ -10,33 +10,86 @@ (function (root, factory) {

}(this, function () {
var global;
;global = window;;var isArrayBufferView = function(input) {
return typeof input === 'object' && input !== null && (
(global.ArrayBufferView && input instanceof ArrayBufferView) ||
(global.Int8Array && input instanceof Int8Array) ||
(global.Uint8Array && input instanceof Uint8Array) ||
(global.Uint8ClampedArray && input instanceof Uint8ClampedArray) ||
(global.Int16Array && input instanceof Int16Array) ||
(global.Uint16Array && input instanceof Uint16Array) ||
(global.Int32Array && input instanceof Int32Array) ||
(global.Uint32Array && input instanceof Uint32Array) ||
(global.Float32Array && input instanceof Float32Array) ||
(global.Float64Array && input instanceof Float64Array)
);
};
var isArray = function(object) {
return Object.prototype.toString.call(object) === '[object Array]';
};
var isByteArray = function(input) {
return typeof input === 'object' && input !== null && (
(global.Buffer && input instanceof Buffer) ||
(global.Blob && input instanceof Blob) ||
(global.File && input instanceof File) ||
(global.ArrayBuffer && input instanceof ArrayBuffer) ||
isArrayBufferView(input) ||
isArray(input)
);
};
var 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';
var supportedMethods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'];
var indexOf = [].indexOf ? function(array, item) {
return array.indexOf(item);
} : function(array, item) {
var i = -1;
while(++i < array.length) {
if(array[i] === item) {
return i;
}
}
return -1;
};
var pass = function(value) {
return value;
};
var nextTick = (global.process && global.process.nextTick) || global.setImmediate || global.setTimeout;
var _undefined;
;
// this could be a simple map, but with this "compression" we save about 100 bytes, if minified (50 bytes, if also gzipped)
var statusTextToCode = (function() {
var group = arguments.length, map = {};
while(group--) {
var texts = arguments[group].split(','), index = texts.length;
while(index--) {
map[texts[index]] = (group + 1) * 100 + index;
}
}
return map;
})(
'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'
);
var bufferSlice = function(buffer, begin, end) {
if(begin === 0 && end === buffer.byteLength) {
return buffer;
}
return buffer.slice ? buffer.slice(begin, end) : new Uint8Array(Array.prototype.slice.call(new Uint8Array(buffer), begin, end)).buffer;
};
var responseBodyToBytes, responseBodyLength;
(function() {
try {
var vbscript = '';
vbscript += 'Function httpinvoke_BinaryExtract(Binary, Array)\r\n';
vbscript += ' Dim len, i\r\n';
vbscript += ' len = LenB(Binary)\r\n';
vbscript += ' For i = 1 to len\r\n';
vbscript += ' Array.push(AscB(MidB(Binary, i, 1)))\r\n';
vbscript += ' Next\r\n';
vbscript += 'End Function\r\n';
vbscript += '\r\n';
vbscript += 'Function httpinvoke_BinaryLength(Binary)\r\n';
vbscript += ' httpinvoke_BinaryLength = LenB(Binary)\r\n';
vbscript += 'End Function\r\n';
vbscript += '\r\n';
window.execScript(vbscript, 'vbscript');
var byteMapping = {};
for(var i = 0; i < 256; i += 1) {
for (var j = 0; j < 256; j += 1) {
byteMapping[String.fromCharCode(i + j * 256)] = String.fromCharCode(i) + String.fromCharCode(j);
}
}
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 = [];
window.httpinvoke_BinaryExtract(binary, bytes);
httpinvoke0(binary, bytes);
return bytes;
};
// cannot just assign the function, because httpinvoke1 is not a javascript 'function'
responseBodyLength = function(binary) {
return window.httpinvoke_BinaryLength(binary);
return httpinvoke1(binary);
};

@@ -46,119 +99,60 @@ } catch(err) {

})();
var getOutput = {
'text' : function(xhr) {
if(typeof xhr.response !== 'undefined') {
return xhr.response;
}
return xhr.responseText;
},
'bytearray' : function(xhr) {
if(typeof xhr.response !== 'undefined') {
return new Uint8Array(xhr.response);
}
if(typeof xhr.responseBody !== 'undefined') {
return responseBodyToBytes(xhr.responseBody);
}
var str = xhr.responseText, n = str.length, bytearray = new Array(n);
for(var i = 0; i < n; i += 1) {
bytearray[i] = str.charCodeAt(i) & 0xFF;
}
if(typeof Uint8Array !== 'undefined') {
// firefox 4 supports typed arrays but not xhr2
return new Uint8Array(bytearray);
}
return bytearray;
var getOutputText = function(xhr) {
return xhr.response || xhr.responseText;
};
var binaryStringToByteArray = function(str) {
var n = str.length, bytearray = new Array(n);
while(n--) {
bytearray[n] = str.charCodeAt(n) & 255;
}
return bytearray;
};
var getOutputLength = {
'text': function(xhr) {
return countStringBytes(getOutput.text(xhr));
},
'bytearray': function(xhr) {
if(typeof xhr.response !== 'undefined') {
return xhr.response.byteLength;
}
if(typeof xhr.responseBody !== 'undefined') {
return responseBodyLength(xhr.responseBody);
}
return 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 trim = typeof ''.trim === 'undefined' ? function(string) {
return string.replace(/^\s+|\s+$/g,'');
} : function(string) {
return string.trim();
var getOutputLengthText = function(xhr) {
return countStringBytes(getOutputText(xhr));
};
var indexOf = typeof [].indexOf === 'undefined' ? function(array, item) {
for(var i = 0; i < array.length; i += 1) {
if(array[i] === item) {
return i;
}
var getOutputLengthBinary = function(xhr) {
if('response' in xhr) {
return xhr.response ? xhr.response.byteLength : 0;
}
return -1;
} : function(array, item) {
return array.indexOf(item);
// 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) {
var n = 0;
for(var i = 0; i < string.length; i += 1) {
var c = string.charCodeAt(i);
if (c < 128) {
n += 1;
} else if (c < 2048) {
n += 2;
} else {
n += 3;
}
var c, n = 0, i = string.length;
while(i--) {
c = string.charCodeAt(i);
n += c < 128 ? 1 : (c < 2048 ? 2 : 3);
}
return n;
};
var convertByteArrayToBinaryString = function(bytearray) {
var str = '';
for(var i = 0; i < bytearray.length; i += 1) {
str += String.fromCharCode(bytearray[i]);
}
return str;
};
var supportedMethods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'];
var parseHeader = function(header) {
var colon = header.indexOf(':');
return {
name: header.slice(0, colon).toLowerCase(),
value: trim(header.slice(colon + 1))
};
};
// 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) {
for(var header in headers) {
if(headers.hasOwnProperty(header)) {
var headerl = header.toLowerCase();
if(indexOf(forbiddenInputHeaders, headerl) >= 0) {
throw new Error('Input header ' + header + ' is forbidden to be set programmatically');
}
if(headerl.substr(0, 'proxy-'.length) === 'proxy-') {
throw new Error('Input header ' + header + ' (to be precise, all Proxy-*) is forbidden to be set programmatically');
}
if(headerl.substr(0, 'sec-'.length) === 'sec-') {
throw new Error('Input header ' + header + ' (to be precise, all Sec-*) is forbidden to be set programmatically');
}
}
var fillOutputHeaders = function(xhr, headers, outputHeaders) {
var i, colon, header;
headers = xhr.getAllResponseHeaders().split(/\r?\n/);
i = headers.length;
while(i-- && (colon = headers[i].indexOf(':')) >= 0) {
outputHeaders[headers[i].slice(0, colon).toLowerCase()] = header.slice(colon + 2);
}
return i + 1 !== headers.length;
};
var fillOutputHeaders = function(xhr, outputHeaders) {
var headers = xhr.getAllResponseHeaders().split(/\r?\n/);
var i = headers.length - 1;
var header;
while(i >= 0) {
header = trim(headers[i]);
if(header.length > 0) {
header = parseHeader(header);
outputHeaders[header.name] = header.value;
}
i -= 1;
}
};

@@ -171,144 +165,276 @@ var urlPartitioningRegExp = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/;

};
var failWithoutRequest = function(cb, err) {
setTimeout(function() {
if(cb === null) {
return;
}
cb(err);
}, 0);
return noop;
};
var noop = function() {};
var createXHR;
var httpinvoke = function(uri, method, options) {
/*************** COMMON initialize parameters **************/
if(typeof method === 'undefined') {
method = 'GET';
options = {};
} else if(typeof options === 'undefined') {
if(typeof method === 'string') {
options = {};
} else {
options = method;
method = 'GET';
}
}
options = typeof options === 'function' ? {
var httpinvoke = function(uri, method, options, cb) {
;var mixInPromise, promise, failWithoutRequest, uploadProgressCb, inputLength, noData, timeout, inputHeaders, corsOriginHeader, statusCb, initDownload, updateDownload, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter;
/*************** COMMON initialize parameters **************/
if(!method) {
// 1 argument
// method, options, cb skipped
method = 'GET';
options = {};
} else if(!options) {
// 2 arguments
if(typeof method === 'string') {
// options. cb skipped
options = {};
} else if(typeof method === 'object') {
// method, cb skipped
options = method;
method = 'GET';
} else {
// method, options skipped
options = {
finished: method
};
method = 'GET';
}
} else if(!cb) {
// 3 arguments
if(typeof method === 'object') {
// method skipped
method.finished = options;
options = method;
method = 'GET';
} else if(typeof options === 'function') {
// options skipped
options = {
finished: options
} : options;
var safeCallback = function(name) {
if(typeof options[name] === 'undefined') {
return noop;
};
}
// cb skipped
} else {
// 4 arguments
options.finished = cb;
}
var safeCallback = function(name, aspect) {
if(name in options) {
return function(a, b, c, d) {
try {
options[name](a, b, c, d);
} catch(_) {
}
return function() {
try {
options[name].apply(null, arguments);
} catch(_) {
}
};
aspect(a, b, c, d);
};
var uploadProgressCb = safeCallback('uploading');
var downloadProgressCb = safeCallback('downloading');
var statusCb = safeCallback('gotStatus');
var cb = safeCallback('finished');
var timeout = options.timeout || 0;
var inputLength, inputHeaders = options.headers || {};
var inputType;
var outputType = options.outputType || "text";
var exposedHeaders = options.corsHeaders || [];
var corsOriginHeader = options.corsOriginHeader || 'X-Httpinvoke-Origin';
exposedHeaders.push.apply(exposedHeaders, ['Cache-Control', 'Content-Language', 'Content-Type', 'Expires', 'Last-Modified', 'Pragma']);
/*************** COMMON convert and validate parameters **************/
if(indexOf(supportedMethods, method) < 0) {
return failWithoutRequest(cb, new Error('Unsupported method ' + method));
}
return aspect;
};
mixInPromise = function(o) {
var state = [];
var chain = function(p, promise) {
if(p && p.then) {
p.then(promise.resolve.bind(promise), promise.reject.bind(promise), promise.notify.bind(promise));
}
if(outputType !== 'text' && outputType !== 'bytearray') {
return failWithoutRequest(cb, new Error('Unsupported outputType ' + outputType));
};
var loop = function(value) {
if(!isArray(state)) {
return;
}
if(typeof options.input === 'undefined') {
if(typeof options.inputType !== 'undefined') {
return failWithoutRequest(cb, new Error('"input" is undefined, but inputType is defined'));
}
if(typeof inputHeaders['Content-Type'] !== 'undefined') {
return failWithoutRequest(cb, new Error('"input" is undefined, but Content-Type request header is defined'));
}
var name, after = function() {
state = value;
};
if(value instanceof Error) {
name = 'onreject';
} else if(value.type) {
name = 'onnotify';
after = pass;
} else {
if(typeof options.inputType === 'undefined') {
inputType = 'auto';
} else {
inputType = options.inputType;
if(inputType !== 'auto' && inputType !== 'text' && inputType !== 'bytearray') {
return failWithoutRequest(cb, new Error('Unsupported inputType ' + inputType));
name = 'onresolve';
}
var p;
for(var i = 0; i < state.length; i++) {
try {
p = state[i][name](value);
if(after !== pass) {
chain(p, state[i].promise);
}
} catch(_) {
}
if(inputType === 'auto') {
if(typeof inputHeaders['Content-Type'] === 'undefined') {
return failWithoutRequest(cb, new Error('inputType is auto and Content-Type request header is not specified'));
}
if(typeof inputHeaders['Content-Type'] === 'undefined') {
inputType = 'bytearray';
} else if(inputHeaders['Content-Type'].substr(0, 'text/'.length) === 'text/') {
inputType = 'text';
} else {
inputType = 'bytearray';
}
}
if(inputType === 'text') {
if(typeof options.input !== 'string') {
return failWithoutRequest(cb, new Error('inputType is text, but input is not a string'));
}
if(typeof inputHeaders['Content-Type'] === 'undefined') {
inputHeaders['Content-Type'] = 'text/plain; charset=UTF-8';
}
} else if(inputType === 'bytearray') {
if(httpinvoke.requestTextOnly) {
return failWithoutRequest(cb, new Error('bytearray inputType is not supported on this platform, please always test using requestTextOnly feature flag'));
}
if(typeof options.input !== 'object' || options.input === null || !((typeof Blob !== 'undefined' && options.input instanceof Blob) || (typeof ArrayBuffer !== 'undefined' && options.input instanceof ArrayBuffer) || Object.prototype.toString.call(options.input) === '[object Array]')) {
return failWithoutRequest(cb, new Error('inputType is bytearray, but input is neither an instance of ArrayBuffer, nor Array, nor Blob'));
}
if(typeof inputHeaders['Content-Type'] === 'undefined') {
inputHeaders['Content-Type'] = 'application/octet-stream';
}
}
}
after();
};
o.then = function(onresolve, onreject, onnotify) {
var promise = mixInPromise({});
if(isArray(state)) {
// TODO see if the property names are minifed
state.push({
onresolve: onresolve,
onreject: onreject,
onnotify: onnotify,
promise: promise
});
} else if(state instanceof Error) {
nextTick(function() {
chain(onreject(state), promise);
});
} else {
nextTick(function() {
chain(onresolve(state), promise);
});
}
return promise;
};
o.notify = loop;
o.resolve = loop;
o.reject = loop;
return o;
};
failWithoutRequest = function(cb, err) {
nextTick(function() {
if(cb === null) {
return;
}
cb(err);
});
promise = function() {
};
return mixInPromise(promise);
};
try {
validateInputHeaders(inputHeaders);
} catch(err) {
return failWithoutRequest(cb, err);
uploadProgressCb = safeCallback('uploading', function(current, total) {
promise.notify({
type: 'upload',
current: current,
total: total
});
});
var downloadProgressCb = safeCallback('downloading', function(current, total) {
promise.notify({
type: 'download',
current: current,
total: total
});
});
statusCb = safeCallback('gotStatus', function(statusCode, headers) {
promise.notify({
type: 'headers',
statusCode: statusCode,
headers: headers
});
});
cb = safeCallback('finished', function(err, body, statusCode, headers) {
if(err) {
return promise.reject(err);
}
promise.resolve({
body: body,
statusCode: statusCode,
headers: headers
});
});
timeout = options.timeout || 0;
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']);
corsOriginHeader = options.corsOriginHeader || 'X-Httpinvoke-Origin';
/*************** COMMON convert and validate parameters **************/
if(indexOf(supportedMethods, method) < 0) {
return failWithoutRequest(cb, new Error('Unsupported method ' + method));
}
outputBinary = options.outputType === 'bytearray';
if(!options.outputType || options.outputType === 'text' || outputBinary) {
outputConverter = pass;
} else if(converters['text ' + options.outputType]) {
outputConverter = converters['text ' + options.outputType];
outputBinary = false;
} else if(converters['bytearray ' + options.outputType]) {
outputConverter = converters['bytearray ' + options.outputType];
outputBinary = true;
} else {
return failWithoutRequest(cb, new Error('Unsupported outputType ' + options.outputType));
}
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));
}
/*************** COMMON initialize helper variables **************/
var downloaded, outputHeaders, outputLength;
var initDownload = function(total) {
if(typeof outputLength !== 'undefined') {
return;
}
outputLength = total;
} else if(options.inputType === 'text') {
if(typeof input !== 'string') {
return failWithoutRequest(cb, new Error('inputType is text, but input is not a string'));
}
} else if (options.inputType === '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 {
return failWithoutRequest(cb, new Error('There is no converter for specified inputType'));
}
if(typeof input === 'string') {
if(!inputHeaders['Content-Type']) {
inputHeaders['Content-Type'] = 'text/plain; charset=UTF-8';
}
} else {
if(!inputHeaders['Content-Type']) {
inputHeaders['Content-Type'] = 'application/octet-stream';
}
if(global.ArrayBuffer && input instanceof ArrayBuffer) {
input = new Uint8Array(input);
} else if(isArrayBufferView(input)) {
input = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
}
}
try {
input = inputConverter(input);
} catch(err) {
return failWithoutRequest(cb, err);
}
} else {
if(options.inputType) {
return failWithoutRequest(cb, new Error('"input" is undefined, but inputType is defined'));
}
if(inputHeaders['Content-Type']) {
return failWithoutRequest(cb, new Error('"input" is undefined, but Content-Type request header is defined'));
}
}
downloadProgressCb(downloaded, outputLength);
};
var updateDownload = function(value) {
if(value === downloaded) {
/*************** COMMON initialize helper variables **************/
var downloaded;
initDownload = function(total) {
if(typeof outputLength === 'undefined') {
downloadProgressCb(downloaded, outputLength = total);
}
};
updateDownload = function(value) {
if(value !== downloaded) {
downloadProgressCb(downloaded = value, outputLength);
}
};
noData = function() {
initDownload(0);
if(cb) {
// TODO what happens if we try to call abort in cb?
cb(null, _undefined, status, outputHeaders);
cb = null;
}
};
;
/*************** initialize helper variables **************/
var getOutput = outputBinary ? getOutputBinary : getOutputText;
var getOutputLength = outputBinary ? getOutputLengthBinary : getOutputLengthText;
var uploadProgressCbCalled = false;
var uploadProgress = function(uploaded) {
if(!uploadProgressCb) {
return;
}
downloaded = value;
downloadProgressCb(downloaded, outputLength);
};
var noData = function() {
initDownload(0);
if(cb === null) {
return;
if(!uploadProgressCbCalled) {
uploadProgressCbCalled = true;
uploadProgressCb(0, inputLength);
if(!cb) {
return;
}
}
updateDownload(0);
if(cb === null) {
return;
uploadProgressCb(uploaded, inputLength);
if(uploaded === inputLength) {
uploadProgressCb = null;
}
cb();
cb = null;
};
/*************** initialize helper variables **************/
var uploadProgressCbCalled = false;
var output;

@@ -319,8 +445,8 @@ var i;

// IE may throw an exception when accessing
// a field from window.location if document.domain has been set
currentLocation = window.location.href;
// a field from global.location if global.document.domain has been set
currentLocation = global.location.href;
} catch(_) {
// Use the href attribute of an A element
// since IE will modify it given document.location
currentLocation = window.document.createElement('a');
currentLocation = global.document.createElement('a');
currentLocation.href = '';

@@ -331,2 +457,5 @@ currentLocation = currentLocation.href;

/*************** 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(crossDomain && !httpinvoke.cors) {

@@ -344,12 +473,15 @@ return failWithoutRequest(cb, new Error('Cross-origin requests are not supported'));

}
if(!createXHR) {
return failWithoutRequest(cb, new Error('unable to construct XMLHttpRequest object'));
}
var xhr = createXHR(crossDomain);
xhr.open(method, uri, true);
if(timeout > 0) {
if(typeof xhr.timeout === 'undefined') {
if('timeout' in xhr) {
xhr.timeout = timeout;
} else {
setTimeout(function() {
cb(new Error('Timeout of ' + timeout + 'ms exceeded'));
cb(new Error('download timeout'));
cb = null;
}, timeout);
} else {
xhr.timeout = timeout;
}

@@ -368,150 +500,203 @@ }

// workaraound for #1: sending origin in custom header, also see the server-side part of the workaround in dummyserver.js
inputHeaders[corsOriginHeader] = window.location.protocol + '//' + window.location.host;
inputHeaders[corsOriginHeader] = global.location.protocol + '//' + global.location.host;
}
/*************** bind XHR event listeners **************/
if(typeof xhr.upload !== 'undefined') {
xhr.upload.ontimeout = function(progressEvent) {
if(cb === null) {
return;
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;
}
cb(new Error('upload timeout'));
cb = null;
};
xhr.upload.onerror = function(progressEvent) {
if(cb === null) {
return;
}
cb(new Error('upload error'));
cb = null;
};
xhr.upload.onprogress = function(progressEvent) {
if(cb === null) {
return;
}
if(progressEvent.lengthComputable) {
if(!uploadProgressCbCalled) {
uploadProgressCbCalled = true;
uploadProgressCb(0, inputLength);
}
uploadProgressCb(progressEvent.loaded, inputLength);
}
};
};
var onuploadprogress = function(progressEvent) {
if(cb && progressEvent.lengthComputable) {
uploadProgress(progressEvent.loaded);
}
};
if('upload' in xhr) {
xhr.upload.ontimeout = makeErrorCb('upload timeout');
xhr.upload.onerror = makeErrorCb('upload error');
xhr.upload.onprogress = onuploadprogress;
} else if('onuploadprogress' in xhr) {
xhr.onuploadprogress = onuploadprogress;
}
if(typeof xhr.ontimeout !== 'undefined') {
xhr.ontimeout = function(progressEvent) {
if(cb === null) {
return;
}
cb(new Error('download timeout'));
cb = null;
};
if('ontimeout' in xhr) {
xhr.ontimeout = makeErrorCb('download timeout');
}
if(typeof xhr.onerror !== 'undefined') {
if('onerror' in xhr) {
xhr.onerror = function() {
if(cb === null) {
return;
}
cb(new Error('download error'));
cb = null;
//inspect('onerror', arguments[0]);
//dbg('onerror');
// For 4XX and 5XX response codes Firefox 3.6 cross-origin request ends up here, but has correct statusText, but no status and headers
onLoad();
};
}
if(typeof xhr.onloadstart !== 'undefined') {
if('onloadstart' in xhr) {
xhr.onloadstart = function() {
//dbg('onloadstart');
onHeadersReceived(false);
};
}
if(typeof xhr.onloadend !== 'undefined') {
if('onloadend' in xhr) {
xhr.onloadend = function() {
//dbg('onloadend');
onHeadersReceived(false);
};
}
if(typeof xhr.onprogress !== 'undefined') {
if('onprogress' in xhr) {
xhr.onprogress = function(progressEvent) {
if(cb === null) {
//dbg('onprogress');
if(!cb) {
return;
}
onHeadersReceived(false);
if(statusCb !== null) {
if(statusCb) {
return;
}
if(typeof progressEvent !== 'undefined') {
var total = progressEvent.total || progressEvent.totalSize || 0;
var current = progressEvent.loaded || progressEvent.position || 0;
if(progressEvent.lengthComputable) {
initDownload(total);
}
if(cb === null) {
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);
// 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;
var 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);
};
}
/*
var inspect = function(name, obj) {
return;
console.log('INSPECT ----- ', name, uri);
for(var i in obj) {
try {
console.log(name, 'PASS', i, typeof obj[i], typeof obj[i] === 'function' ? '[code]' : obj[i]);
} catch(_) {
console.log(name, 'FAIL', i);
}
}
};
var dbg = function(name) {
console.log('DBG ----- ', name, uri);
inspect('xhr', xhr);
try {
console.log('PASS', 'headers', xhr.getAllResponseHeaders());
} catch(_) {
console.log('FAIL', 'headers');
}
try {
console.log('PASS', 'cache-control', xhr.getResponseHeader('Cache-Control'));
} catch(_) {
console.log('FAIL', 'cache-control');
}
};
*/
var received = {
success: false,
status: false,
entity: false,
headers: false
};
var onHeadersReceived = function(lastTry) {
if(cb === null) {
if(!cb) {
return;
}
if(statusCb === null) {
return;
try {
if(xhr.status) {
received.status = true;
}
} catch(_) {
}
var status;
if(!crossDomain || httpinvoke.corsStatus) {
try {
if(typeof xhr.status === 'undefined' || xhr.status === 0) {
return;
}
status = xhr.status;
} catch(_) {
return;
try {
if(xhr.statusText) {
received.status = true;
}
// sometimes IE returns 1223 when it should be 204
if(status === 1223) {
status = 204;
} catch(_) {
}
try {
if(xhr.responseText) {
received.entity = true;
}
} catch(_) {
}
try {
if(xhr.response) {
received.entity = true;
}
} catch(_) {
}
outputHeaders = {};
if(crossDomain) {
if(httpinvoke.corsResponseContentTypeOnly) {
if(typeof xhr.contentType === 'string') {
if(!statusCb) {
return;
}
if(received.status || received.entity || received.success || lastTry) {
if(typeof xhr.contentType === 'string') {
if(xhr.contentType !== 'text/html' || xhr.responseText !== '') {
// When no entity body and/or no Content-Type header is sent,
// XDomainRequest on IE-8 defaults to text/html xhr.contentType.
// Also, empty string is not a valid 'text/html' entity.
outputHeaders['content-type'] = xhr.contentType;
received.headers = true;
}
} else {
for(var i = 0; i < exposedHeaders.length; i += 1) {
try {
var header = xhr.getResponseHeader(exposedHeaders[i]);
if(header !== null) {
outputHeaders[exposedHeaders[i].toLowerCase()] = header;
}
} catch(err) {
if(!lastTry) {
return;
}
}
for(var i = 0; i < exposedHeaders.length; i += 1) {
var header;
try {
if(header = xhr.getResponseHeader(exposedHeaders[i])) {
outputHeaders[exposedHeaders[i].toLowerCase()] = header;
received.headers = true;
}
} catch(err) {
}
}
} else {
try {
fillOutputHeaders(xhr, outputHeaders);
} catch(_) {
if(!lastTry) {
return;
// note - on Opera 11.10 and 11.50 calling getAllResponseHeaders may introduce side effects on xhr and responses will timeout when server responds with some HTTP status codes
if(fillOutputHeaders(xhr, outputHeaders)) {
received.headers = true;
}
} catch(err) {
}
if(!status && (!crossDomain || httpinvoke.corsStatus)) {
// Sometimes on IE 9 accessing .status throws an error, but .statusText does not.
try {
if(xhr.status) {
status = xhr.status;
}
} catch(_) {
}
if(!status) {
try {
status = statusTextToCode[xhr.statusText];
} catch(_) {
}
}
// sometimes IE returns 1223 when it should be 204
if(status === 1223) {
status = 204;
}
}
}
if(!uploadProgressCbCalled) {
uploadProgressCbCalled = true;
uploadProgressCb(0, inputLength);
if(!lastTry && !(received.status && received.headers)) {
return;
}
uploadProgressCb(inputLength, inputLength);
if(cb === null) {
uploadProgress(inputLength);
if(!cb) {
return;

@@ -522,62 +707,80 @@ }

statusCb = null;
if(cb === null) {
if(!cb) {
return;
}
// BEGIN COMMON
if(typeof outputHeaders['content-length'] !== 'undefined') {
if(method === 'HEAD') {
return noData();
}
updateDownload(0);
if(!cb) {
return;
}
if('content-length' in outputHeaders) {
initDownload(Number(outputHeaders['content-length']));
if(cb === null) {
if(!cb) {
return;
}
}
if(method === 'HEAD' || typeof outputHeaders['content-type'] === 'undefined' || outputLength === 0) {
return noData();
}
updateDownload(0);
// END COMMON
};
var onLoad = function() {
if(cb === null) {
if(!cb) {
return;
}
if((!crossDomain || httpinvoke.corsStatus) && xhr.status === 0) {
cb(new Error('"some type" of network error'));
cb = null;
onHeadersReceived(true);
if(!cb) {
return;
}
onHeadersReceived(true);
if(cb === null) {
if(!received.success && !status) {
// 'finished in onerror and status code is undefined'
cb(new Error('download error'));
cb = null;
return;
}
if(typeof xhr.response !== 'undefined' && xhr.response === null) {
return noData();
}
var length;
try {
initDownload(getOutputLength[outputType](xhr));
if(cb === null) {
return;
}
length = getOutputLength(xhr);
} catch(_) {
return noData();
}
if(outputLength === 0) {
return noData();
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(!cb) {
return;
}
output = getOutput[outputType](xhr);
updateDownload(outputLength);
if(cb === null) {
if(!cb) {
return;
}
cb(null, output);
try {
cb(null, !received.entity && outputLength === 0 && typeof outputHeaders['content-type'] === 'undefined' ? _undefined : outputConverter(getOutput(xhr)), status, outputHeaders);
} catch(err) {
cb(err);
}
cb = null;
};
var onloadBound = false;
if(typeof xhr.onload !== 'undefined') {
onloadBound = true;
xhr.onload = function() {
received.success = true;
//dbg('onload');
onLoad();
};
}
if(typeof xhr.onreadystatechange !== 'undefined') {
xhr.onreadystatechange = function() {
//dbg('onreadystatechange ' + xhr.readyState);
if(xhr.readyState === 2) {

@@ -588,11 +791,16 @@ // HEADERS_RECEIVED

// LOADING
received.success = true;
onHeadersReceived(false);
if(statusCb !== null) {
if(statusCb) {
return;
}
try {
updateDownload(getOutputLength[outputType](xhr));
updateDownload(getOutputLength(xhr));
} catch(err) {
}
} else if(xhr.readyState === 4) {
// Instead of 'typeof xhr.onload === "undefined"', we must use
// onloadBound variable, because otherwise Firefox 3.5 synchronously
// throws a "Permission denied for <> to create wrapper for
// object of class UnnamedClass" error
} else if(xhr.readyState === 4 && !onloadBound) {
// DONE

@@ -603,3 +811,2 @@ onLoad();

}
xhr.onload = onLoad;

@@ -610,3 +817,7 @@ /*************** set XHR request headers **************/

if(inputHeaders.hasOwnProperty(inputHeaderName)) {
xhr.setRequestHeader(inputHeaderName, inputHeaders[inputHeaderName]);
try {
xhr.setRequestHeader(inputHeaderName, inputHeaders[inputHeaderName]);
} catch(err) {
return failWithoutRequest(cb, err);
}
}

@@ -616,44 +827,52 @@ }

/*************** invoke XHR request process **************/
setTimeout(function() {
if(cb === null) {
nextTick(function() {
if(!cb) {
return;
}
try {
xhr.responseType = outputType === 'bytearray' ? 'arraybuffer' : 'text';
} catch(err) {
}
try {
// must override mime type before receiving headers - at least for Safari 5.0.4
if(outputType === 'bytearray') {
xhr.overrideMimeType('text/plain; charset=x-user-defined');
} else if(outputType === 'text') {
if(outputHeaders['content-type'].substr(0, 'text/'.length) !== 'text/') {
xhr.overrideMimeType('text/plain');
if('response' in xhr) {
try {
xhr.responseType = outputBinary ? 'arraybuffer' : 'text';
} catch(err) {
}
} else {
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');
}
} catch(err) {
}
} catch(err) {
}
// Content-Length header is set automatically
if(inputType === 'bytearray') {
var triedSendArrayBuffer = typeof ArrayBuffer === 'undefined';
var triedSendBlob = typeof Blob === 'undefined';
if(typeof input === 'object') {
var triedSendArrayBufferView = false;
var triedSendBlob = false;
var triedSendBinaryString = false;
var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
if(Object.prototype.toString.call(options.input) === '[object Array]') {
if(typeof Uint8Array === 'undefined') {
options.input = convertByteArrayToBinaryString(options.input);
} else {
options.input = new Uint8Array(options.input).buffer;
var BlobBuilder = global.BlobBuilder || global.WebKitBlobBuilder || global.MozBlobBuilder || global.MSBlobBuilder;
if(isArray(input)) {
input = global.Uint8Array ? new Uint8Array(input) : String.fromCharCode.apply(String, input);
}
var toBlob = BlobBuilder ? function() {
var bb = new BlobBuilder();
bb.append(input);
input = bb.getBlob(inputHeaders['Content-Type']);
} : function() {
try {
input = new Blob([input], {
type: inputHeaders['Content-Type']
});
} catch(_) {
triedSendBlob = true;
}
}
};
var go = function() {
if(triedSendBlob && triedSendArrayBuffer && triedSendBinaryString) {
var reader;
if(triedSendBlob && triedSendArrayBufferView && triedSendBinaryString) {
return failWithoutRequest(cb, new Error('Unable to send'));
}
if(typeof ArrayBuffer !== 'undefined' && options.input instanceof ArrayBuffer) {
if(triedSendArrayBuffer) {
if(isArrayBufferView(input)) {
if(triedSendArrayBufferView) {
if(!triedSendBinaryString) {
try {
options.input = convertByteArrayToBinaryString(new Uint8Array(options.input));
input = String.fromCharCode.apply(String, input);
} catch(_) {

@@ -663,46 +882,39 @@ triedSendBinaryString = true;

} else if(!triedSendBlob) {
if(typeof BlobBuilder === 'undefined') {
try {
options.input = new Blob([options.input], {
type: inputHeaders['Content-Type']
});
} catch(_) {
triedSendBlob = true;
}
} else {
var bb = new BlobBuilder();
bb.append(options.input);
options.input = bb.getBlob(inputHeaders['Content-Type']);
}
toBlob();
}
} else {
try {
xhr.send(options.input);
outputLength = options.input.byteLength;
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));
return;
} catch(_) {
triedSendArrayBuffer = true;
triedSendArrayBufferView = true;
}
}
} else if(typeof Blob !== 'undefined' && options.input instanceof Blob) {
} else if(global.Blob && input instanceof Blob) {
if(triedSendBlob) {
if(!triedSendArrayBuffer) {
if(!triedSendArrayBufferView) {
try {
var reader = new FileReader();
reader = new FileReader();
reader.onerror = function() {
triedSendArrayBuffer = true;
triedSendArrayBufferView = true;
go();
};
reader.onload = function() {
options.input = reader.result;
try {
input = new Uint8Array(reader.result);
} catch(_) {
triedSendArrayBufferView = true;
}
go();
};
reader.readAsArrayBuffer(options.input);
reader.readAsArrayBuffer(input);
return;
} catch(_) {
triedSendArrayBuffer = true;
triedSendArrayBufferView = true;
}
} else if(!triedSendBinaryString) {
try {
var reader = new FileReader();
reader = new FileReader();
reader.onerror = function() {

@@ -713,6 +925,6 @@ triedSendBinaryString = true;

reader.onload = function() {
options.input = reader.result;
input = reader.result;
go();
};
reader.readAsBinaryString(options.input);
reader.readAsBinaryString(input);
return;

@@ -725,4 +937,4 @@ } catch(_) {

try {
xhr.send(options.input);
outputLength = options.input.size;
inputLength = input.size;
xhr.send(input);
return;

@@ -735,32 +947,15 @@ } catch(_) {

if(triedSendBinaryString) {
if(!triedSendArrayBuffer) {
if(!triedSendArrayBufferView) {
try {
var a = new ArrayBuffer(options.input.length);
var b = new Uint8Array(a);
for(var i = 0; i < options.input.length; i += 1) {
b[i] = options.input[i] & 0xFF;
}
options.input = a;
input = binaryStringToByteArray(input);
} catch(_) {
triedSendArrayBuffer = true;
triedSendArrayBufferView = true;
}
} else if(!triedSendBlob) {
if(typeof BlobBuilder === 'undefined') {
try {
options.input = new Blob([options.input], {
type: inputHeaders['Content-Type']
});
} catch(_) {
triedSendBlob = true;
}
} else {
var bb = new BlobBuilder();
bb.append(options.input);
options.input = bb.getBlob(inputHeaders['Content-Type']);
}
toBlob();
}
} else {
try {
xhr.sendAsBinary(options.input);
outputLength = options.input.length;
inputLength = input.length;
xhr.sendAsBinary(input);
return;

@@ -772,20 +967,25 @@ } catch(_) {

}
setTimeout(go, 0);
nextTick(go);
};
go();
} else if(inputType === 'text') {
inputLength = countStringBytes(options.input);
xhr.send(options.input);
} else {
xhr.send(null);
try {
if(typeof input === 'string') {
inputLength = countStringBytes(input);
xhr.send(input);
} else {
xhr.send(null);
}
} catch(err) {
var _cb = cb;
cb = null;
return failWithoutRequest(cb, new Error('Unable to send'));
}
}
if(!uploadProgressCbCalled) {
uploadProgressCbCalled = true;
uploadProgressCb(0, inputLength);
}
}, 0);
uploadProgress(0);
});
/*************** return "abort" function **************/
return function() {
if(cb === null) {
promise = function() {
if(!cb) {
return;

@@ -804,2 +1004,3 @@ }

};
return mixInPromise(promise);
};

@@ -819,3 +1020,3 @@ httpinvoke.corsResponseContentTypeOnly = false;

createXHR = function() {
return new window.XMLHttpRequest();
return new global.XMLHttpRequest();
};

@@ -825,12 +1026,11 @@ var tmpxhr = createXHR();

httpinvoke.cors = 'withCredentials' in tmpxhr;
if(!httpinvoke.cors) {
throw '';
if(httpinvoke.cors) {
httpinvoke.corsRequestHeaders = true;
httpinvoke.corsCredentials = true;
httpinvoke.corsDELETE = true;
httpinvoke.corsPUT = true;
httpinvoke.corsHEAD = true;
httpinvoke.corsStatus = true;
return;
}
httpinvoke.corsRequestHeaders = true;
httpinvoke.corsCredentials = true;
httpinvoke.corsDELETE = true;
httpinvoke.corsPUT = true;
httpinvoke.corsHEAD = true;
httpinvoke.corsStatus = true;
return;
} catch(err) {

@@ -841,3 +1041,3 @@ }

createXHR = function() {
return new window.XMLHttpRequest();
return new global.XMLHttpRequest();
};

@@ -847,3 +1047,3 @@ createXHR();

createXHR = function(cors) {
return cors ? new window.XDomainRequest() : new window.XMLHttpRequest();
return cors ? new global.XDomainRequest() : new global.XMLHttpRequest();
};

@@ -868,5 +1068,6 @@ createXHR(true);

createXHR = function() {
return new window.ActiveXObject(candidates[i]);
return new global.ActiveXObject(candidates[i]);
};
createXHR();
httpinvoke.requestTextOnly = true;
return;

@@ -877,5 +1078,3 @@ } catch(err) {

}
createXHR = function() {
throw new Error('Cannot construct XMLHttpRequest');
};
createXHR = _undefined;
})();

@@ -882,0 +1081,0 @@

var http = require('http');
var url = require('url');
var noop = function() {};
;;var isArrayBufferView = function(input) {
return typeof input === 'object' && input !== null && (
(global.ArrayBufferView && input instanceof ArrayBufferView) ||
(global.Int8Array && input instanceof Int8Array) ||
(global.Uint8Array && input instanceof Uint8Array) ||
(global.Uint8ClampedArray && input instanceof Uint8ClampedArray) ||
(global.Int16Array && input instanceof Int16Array) ||
(global.Uint16Array && input instanceof Uint16Array) ||
(global.Int32Array && input instanceof Int32Array) ||
(global.Uint32Array && input instanceof Uint32Array) ||
(global.Float32Array && input instanceof Float32Array) ||
(global.Float64Array && input instanceof Float64Array)
);
};
var isArray = function(object) {
return Object.prototype.toString.call(object) === '[object Array]';
};
var isByteArray = function(input) {
return typeof input === 'object' && input !== null && (
(global.Buffer && input instanceof Buffer) ||
(global.Blob && input instanceof Blob) ||
(global.File && input instanceof File) ||
(global.ArrayBuffer && input instanceof ArrayBuffer) ||
isArrayBufferView(input) ||
isArray(input)
);
};
var 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';
var supportedMethods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'];
var failWithoutRequest = function(cb, err) {
process.nextTick(function() {
if(cb === null) {
return;
}
cb(err);
});
return noop;
};
var indexOf = function(array, item) {
var indexOf = [].indexOf ? function(array, item) {
return array.indexOf(item);
};
var countStringBytes = function(string) {
var n = 0;
for(var i = 0; i < string.length; i += 1) {
var c = string.charCodeAt(i);
if (c < 128) {
n += 1;
} else if (c < 2048) {
n += 2;
} else {
n += 3;
} : function(array, item) {
var i = -1;
while(++i < array.length) {
if(array[i] === item) {
return i;
}
}
return n;
return -1;
};
var convertByteArrayToBinaryString = function(bytearray) {
var str = '';
for(var i = 0; i < bytearray.length; i += 1) {
str += String.fromCharCode(bytearray[i]);
}
return str;
var pass = function(value) {
return value;
};
var nextTick = (global.process && global.process.nextTick) || global.setImmediate || global.setTimeout;
var _undefined;
;
// http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method

@@ -45,3 +59,3 @@ 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 headerl = header.toLowerCase();
if(indexOf(forbiddenInputHeaders, headerl) >= 0) {
if(forbiddenInputHeaders.indexOf(headerl) >= 0) {
throw new Error('Input header ' + header + ' is forbidden to be set programmatically');

@@ -59,146 +73,264 @@ }

var httpinvoke = function(uri, method, options) {
/*************** COMMON initialize parameters **************/
if(typeof method === 'undefined') {
var httpinvoke = function(uri, method, options, cb) {
;var mixInPromise, promise, failWithoutRequest, uploadProgressCb, inputLength, noData, timeout, inputHeaders, corsOriginHeader, statusCb, initDownload, updateDownload, outputHeaders, exposedHeaders, status, outputBinary, input, outputLength, outputConverter;
/*************** COMMON initialize parameters **************/
if(!method) {
// 1 argument
// method, options, cb skipped
method = 'GET';
options = {};
} else if(!options) {
// 2 arguments
if(typeof method === 'string') {
// options. cb skipped
options = {};
} else if(typeof method === 'object') {
// method, cb skipped
options = method;
method = 'GET';
options = {};
} else if(typeof options === 'undefined') {
if(typeof method === 'string') {
options = {};
} else {
options = method;
method = 'GET';
}
} else {
// method, options skipped
options = {
finished: method
};
method = 'GET';
}
options = typeof options === 'function' ? {
finished: options
} : options;
var safeCallback = function(name) {
if(typeof options[name] === 'undefined') {
return noop;
}
return function() {
} else if(!cb) {
// 3 arguments
if(typeof method === 'object') {
// method skipped
method.finished = options;
options = method;
method = 'GET';
} else if(typeof options === 'function') {
// options skipped
options = {
finished: options
};
}
// cb skipped
} else {
// 4 arguments
options.finished = cb;
}
var safeCallback = function(name, aspect) {
if(name in options) {
return function(a, b, c, d) {
try {
options[name].apply(null, arguments);
options[name](a, b, c, d);
} catch(_) {
}
aspect(a, b, c, d);
};
}
return aspect;
};
mixInPromise = function(o) {
var state = [];
var chain = function(p, promise) {
if(p && p.then) {
p.then(promise.resolve.bind(promise), promise.reject.bind(promise), promise.notify.bind(promise));
}
};
var uploadProgressCb = safeCallback('uploading');
var downloadProgressCb = safeCallback('downloading');
var statusCb = safeCallback('gotStatus');
var cb = safeCallback('finished');
var timeout = options.timeout || 0;
var input, inputLength, inputHeaders = options.headers || {};
var inputType, inputIsArray;
var outputType = options.outputType || "text";
var exposedHeaders = options.corsHeaders || [];
var corsOriginHeader = options.corsOriginHeader || 'X-Httpinvoke-Origin';
exposedHeaders.push.apply(exposedHeaders, ['Cache-Control', 'Content-Language', 'Content-Type', 'Expires', 'Last-Modified', 'Pragma']);
var loop = function(value) {
if(!isArray(state)) {
return;
}
var name, after = function() {
state = value;
};
if(value instanceof Error) {
name = 'onreject';
} else if(value.type) {
name = 'onnotify';
after = pass;
} else {
name = 'onresolve';
}
var p;
for(var i = 0; i < state.length; i++) {
try {
p = state[i][name](value);
if(after !== pass) {
chain(p, state[i].promise);
}
} catch(_) {
}
}
after();
};
o.then = function(onresolve, onreject, onnotify) {
var promise = mixInPromise({});
if(isArray(state)) {
// TODO see if the property names are minifed
state.push({
onresolve: onresolve,
onreject: onreject,
onnotify: onnotify,
promise: promise
});
} else if(state instanceof Error) {
nextTick(function() {
chain(onreject(state), promise);
});
} else {
nextTick(function() {
chain(onresolve(state), promise);
});
}
return promise;
};
o.notify = loop;
o.resolve = loop;
o.reject = loop;
return o;
};
failWithoutRequest = function(cb, err) {
nextTick(function() {
if(cb === null) {
return;
}
cb(err);
});
promise = function() {
};
return mixInPromise(promise);
};
/*************** COMMON convert and validate parameters **************/
if(indexOf(supportedMethods, method) < 0) {
return failWithoutRequest(cb, new Error('Unsupported method ' + method));
uploadProgressCb = safeCallback('uploading', function(current, total) {
promise.notify({
type: 'upload',
current: current,
total: total
});
});
var downloadProgressCb = safeCallback('downloading', function(current, total) {
promise.notify({
type: 'download',
current: current,
total: total
});
});
statusCb = safeCallback('gotStatus', function(statusCode, headers) {
promise.notify({
type: 'headers',
statusCode: statusCode,
headers: headers
});
});
cb = safeCallback('finished', function(err, body, statusCode, headers) {
if(err) {
return promise.reject(err);
}
if(outputType !== 'text' && outputType !== 'bytearray') {
return failWithoutRequest(cb, new Error('Unsupported outputType ' + outputType));
}
if(typeof options.input === 'undefined') {
if(typeof options.inputType !== 'undefined') {
return failWithoutRequest(cb, new Error('"input" is undefined, but inputType is defined'));
promise.resolve({
body: body,
statusCode: statusCode,
headers: headers
});
});
timeout = options.timeout || 0;
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']);
corsOriginHeader = options.corsOriginHeader || 'X-Httpinvoke-Origin';
/*************** COMMON convert and validate parameters **************/
if(indexOf(supportedMethods, method) < 0) {
return failWithoutRequest(cb, new Error('Unsupported method ' + method));
}
outputBinary = options.outputType === 'bytearray';
if(!options.outputType || options.outputType === 'text' || outputBinary) {
outputConverter = pass;
} else if(converters['text ' + options.outputType]) {
outputConverter = converters['text ' + options.outputType];
outputBinary = false;
} else if(converters['bytearray ' + options.outputType]) {
outputConverter = converters['bytearray ' + options.outputType];
outputBinary = true;
} else {
return failWithoutRequest(cb, new Error('Unsupported outputType ' + options.outputType));
}
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));
}
if(typeof inputHeaders['Content-Type'] !== 'undefined') {
return failWithoutRequest(cb, new Error('"input" is undefined, but Content-Type request header is defined'));
} else if(options.inputType === 'text') {
if(typeof input !== 'string') {
return failWithoutRequest(cb, new Error('inputType is text, but input is not a string'));
}
} else if (options.inputType === '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(typeof options.inputType === 'undefined') {
inputType = 'auto';
} else {
inputType = options.inputType;
if(inputType !== 'auto' && inputType !== 'text' && inputType !== 'bytearray') {
return failWithoutRequest(cb, new Error('Unsupported inputType ' + inputType));
}
return failWithoutRequest(cb, new Error('There is no converter for specified inputType'));
}
if(typeof input === 'string') {
if(!inputHeaders['Content-Type']) {
inputHeaders['Content-Type'] = 'text/plain; charset=UTF-8';
}
if(inputType === 'auto') {
if(typeof inputHeaders['Content-Type'] === 'undefined') {
return failWithoutRequest(cb, new Error('inputType is auto and Content-Type request header is not specified'));
}
if(typeof inputHeaders['Content-Type'] === 'undefined') {
inputType = 'bytearray';
} else if(inputHeaders['Content-Type'].substr(0, 'text/'.length) === 'text/') {
inputType = 'text';
} else {
inputType = 'bytearray';
}
} else {
if(!inputHeaders['Content-Type']) {
inputHeaders['Content-Type'] = 'application/octet-stream';
}
if(inputType === 'text') {
if(typeof options.input !== 'string') {
return failWithoutRequest(cb, new Error('inputType is text, but input is not a string'));
}
input = options.input;
inputLength = countStringBytes(input);
if(typeof inputHeaders['Content-Type'] === 'undefined') {
inputHeaders['Content-Type'] = 'text/plain; charset=UTF-8';
}
} else if(inputType === 'bytearray') {
if(typeof options.input !== 'object' || options.input === null) {
return failWithoutRequest(cb, new Error('inputType is bytearray, but input is not a non-null object'));
}
if(typeof inputHeaders['Content-Type'] === 'undefined') {
inputHeaders['Content-Type'] = 'application/octet-stream';
}
if(global.ArrayBuffer && input instanceof ArrayBuffer) {
input = new Uint8Array(input);
} else if(isArrayBufferView(input)) {
input = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
}
}
try {
validateInputHeaders(inputHeaders);
input = inputConverter(input);
} catch(err) {
return failWithoutRequest(cb, err);
}
/*************** COMMON initialize helper variables **************/
var downloaded, outputHeaders, outputLength;
var initDownload = function(total) {
if(typeof outputLength !== 'undefined') {
return;
}
outputLength = total;
} else {
if(options.inputType) {
return failWithoutRequest(cb, new Error('"input" is undefined, but inputType is defined'));
}
if(inputHeaders['Content-Type']) {
return failWithoutRequest(cb, new Error('"input" is undefined, but Content-Type request header is defined'));
}
}
downloadProgressCb(downloaded, outputLength);
};
var updateDownload = function(value) {
if(value === downloaded) {
return;
}
downloaded = value;
downloadProgressCb(downloaded, outputLength);
};
var noData = function() {
initDownload(0);
if(cb === null) {
return;
}
updateDownload(0);
if(cb === null) {
return;
}
cb();
/*************** COMMON initialize helper variables **************/
var downloaded;
initDownload = function(total) {
if(typeof outputLength === 'undefined') {
downloadProgressCb(downloaded, outputLength = total);
}
};
updateDownload = function(value) {
if(value !== downloaded) {
downloadProgressCb(downloaded = value, outputLength);
}
};
noData = function() {
initDownload(0);
if(cb) {
// TODO what happens if we try to call abort in cb?
cb(null, _undefined, status, outputHeaders);
cb = null;
};
}
};
;
/*************** initialize helper variables **************/
if(inputType === 'bytearray') {
if(options.input instanceof Buffer) {
input = options.input;
} else if(options.input instanceof ArrayBuffer) {
input = new Buffer(new Uint8Array(options.input));
} else if(Object.prototype.toString.call(options.input) === '[object Array]') {
input = new Buffer(options.input);
} else {
return failWithoutRequest(cb, new Error('inputType is bytearray, but input is neither a Buffer, nor Array, nor ArrayBuffer'));
}
inputLength = input.length;
try {
validateInputHeaders(inputHeaders);
} catch(err) {
return failWithoutRequest(cb, err);
}
var ignoringlyConsume = function(res) {
res.on('data', noop);
res.on('end', noop);
var ignorantlyConsume = function(res) {
res.on('data', pass);
res.on('end', pass);
};

@@ -220,16 +352,17 @@ uri = url.parse(uri);

if(cb === null) {
ignoringlyConsume(res);
ignorantlyConsume(res);
return;
}
outputHeaders = res.headers;
status = res.statusCode;
uploadProgressCb(inputLength, inputLength);
if(cb === null) {
ignoringlyConsume(res);
ignorantlyConsume(res);
return;
}
statusCb(res.statusCode, outputHeaders);
statusCb(status, outputHeaders);
if(cb === null) {
ignoringlyConsume(res);
ignorantlyConsume(res);
return;

@@ -239,17 +372,17 @@ }

updateDownload(0);
// BEGIN COMMON
if(typeof outputHeaders['content-length'] === 'string') {
initDownload(Number(outputHeaders['content-length']));
} else {
initDownload();
}
if(cb === null) {
ignoringlyConsume(res);
ignorantlyConsume(res);
return;
}
if(method === 'HEAD' || typeof outputHeaders['content-type'] === 'undefined' || outputLength === 0) {
ignoringlyConsume(res);
if(typeof outputHeaders['content-length'] !== 'undefined') {
initDownload(Number(outputHeaders['content-length']));
if(cb === null) {
ignorantlyConsume(res);
return;
}
}
if(method === 'HEAD' || typeof outputHeaders['content-type'] === 'undefined') {
ignorantlyConsume(res);
return noData();
}
// END COMMON

@@ -280,28 +413,12 @@ var output = [], downloaded = 0;

}
if(outputLength === 0) {
return noData();
}
if(outputType === 'auto') {
if(outputHeaders['content-type'] === 'application/json') {
outputType = 'json';
} else if(outputHeaders['content-type'].substr(0, 'text/'.length) === 'text/') {
outputType = 'text';
} else {
outputType = 'bytearray';
}
}
output = Buffer.concat(output, downloaded);
if(outputType === 'bytearray') {
cb(null, output);
} else if(outputType === 'text') {
cb(null, output.toString('utf8'));
} else if(outputType === 'json') {
try {
cb(null, JSON.parse(output.toString('utf8')));
} catch(err) {
cb(err);
}
if(!outputBinary) {
output = output.toString('utf8');
}
try {
cb(null, outputConverter(output), status, outputHeaders);
} catch(err) {
cb(err);
}
cb = null;

@@ -311,3 +428,3 @@ });

process.nextTick(function() {
nextTick(function() {
if(cb === null) {

@@ -318,6 +435,5 @@ return;

});
if(typeof options.input !== 'undefined') {
if(input instanceof Array) {
input = new Buffer(input);
}
if(typeof input !== 'undefined') {
input = new Buffer(input);
inputLength = input.length;
req.write(input);

@@ -333,3 +449,3 @@ }

req.end();
return function() {
promise = function() {
if(cb === null) {

@@ -344,2 +460,3 @@ return;

};
return mixInPromise(promise);
};

@@ -346,0 +463,0 @@ httpinvoke.corsResponseContentTypeOnly = false;

if(typeof window === 'undefined') {
window = {};
} else {
global = window;
}
if(typeof location === 'undefined') {

@@ -12,6 +15,268 @@ location = {};

window._cfg = {
proxyPath: '/dummyserver',
dummyserverPort: 1337,
dummyserverPortAlternative: 1338,
host: location.hostname,
port: location.port || (location.protocol === 'https:' ? 443 : 80),
path: '/dummyserver/',
port: Number(location.port) || (location.protocol === 'https:' ? 443 : 80),
/* # Statuses from RFC 2616
*
* ## Not tested statuses, with reasons
*
* 100 Continue: technical status, not semantic, irrelevant for practical use
* 101 Switching Protocols: technical status, not semantic, irrelevant for practical use
* 205 Reset Content: Roy T. Fielding: "The most common use of 205 is within custom HTTP systems, not browsers.": http://w3-org.9356.n7.nabble.com/p2-deprecating-205-Reset-Content-tp253298p253354.html
* 401 Unauthorized: Chrome 29.0 throws an authorization dialog, when the mandatory header 'WWW-Authenticate' is set
* 407 Proxy Authentication Required: not useful, Chrome 29.0 sends "some type" of network error
* 411 Length Required: Content-Length is always sent by browsers
* 417 Expectation Failed: the required header 'Expect' is not allowed by browsers
*
* ## Statuses that should work, but should not be used, with reasons
*
* ### 3XX with Location header set
*
* Causes various unexpected behaviors - browsers are supposed to redirect,
* also Karma test runner proxy failure.
*
* ### 3XX without Location header set
*
* 301, 302, 303, 307 GET same-origin:
* - IE 8.0 returns status 12150, which is WinInet error code ERROR_HTTP_HEADER_NOT_FOUND The requested header could not be located
*
* 301, 302, 303, 307 POST:
* - fails ("write EPIPE" error) on node
*
* 300, 305 POST:
* - Karma test runner proxy failure
*
* 305 GET:
* - Opera 12.10 responseText: <HTML><HEAD><TITLE>Redirect to alternative proxy</TITLE></HEAD><BODY>The server tried to redirect Opera to the alternative proxy "". For security reasons this is no longer supported.<BR><BR><HR>Generated by Opera &copy;</BODY></HTML>
*
* 300 GET:
* - Opera 12.10 times out
*
* 304 POST:
* - By RFC2616 impossible
*
*/
// TODO PUT POST - verify headers and input on server
// TODO HEAD POST PUT DELETE
status: {
// OK
'200': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: true
}]
},
// Created
'201': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: true
}]
},
// Accepted
'202': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: true
}]
},
// Non-Authoritative Information
'203': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: true
}]
},
// No Content
'204': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Partial Content
'206': {
GET: [{
requestEntity: false,
partialResponse: true,
responseEntity: true
}]
},
// Not Modified
'304': {
GET: [{
ifModified: true,
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Bad Request
'400': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Payment Required
'402': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Forbidden
'403': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Not Found
'404': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Method Not Allowed
'405': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Not Acceptable
'406': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Request Timeout
'408': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Conflict
'409': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Gone
'410': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Precondition Failed
'412': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Request Entity Too Large
'413': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Request-URI Too Long
'414': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Unsupported Media Type
'415': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Requested Range Not Satisfiable
'416': {
GET: [{
requestEntity: false,
partialResponse: true,
responseEntity: false
}]
},
// Internal Server Error
'500': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Not Implemented
'501': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Bad Gateway
'502': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Service Unavailable
'503': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// Gateway Timeout
'504': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
},
// HTTP Version Not Supported
'505': {
GET: [{
requestEntity: false,
partialResponse: false,
responseEntity: false
}]
}
},
makeTextFinished: function(done) {

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

}
for(i = 255; i > 0; i -= 1) {
for(i = 255; i >= 0; i -= 1) {
bytes.push(i);

@@ -124,4 +389,4 @@ }

// generated
window._cfg.corsURL = 'http://' + window._cfg.host + ':' + window._cfg.dummyserverPort + '/';
window._cfg.url = 'http://' + window._cfg.host + ':' + window._cfg.port + window._cfg.path;
window._cfg.corsURL = 'http://' + window._cfg.host + ':' + (window._cfg.port === window._cfg.dummyserverPort ? window._cfg.dummyserverPortAlternative : window._cfg.dummyserverPort) + '/';
window._cfg.url = 'http://' + window._cfg.host + ':' + window._cfg.port + (window._cfg.port === window._cfg.dummyserverPort ? '' : window._cfg.proxyPath) + '/';

@@ -138,1 +403,10 @@ window.require = function(module) {

}
if(!global.console) {
global.console = {
_log: [],
log: function() {
this._log.push([].slice.call(arguments));
}
};
}

@@ -6,3 +6,3 @@ // Karma configuration

module.exports = function(config) {
config.set({
var cfg = {

@@ -21,2 +21,3 @@ // base path, that will be used to resolve files and exclude

'karma-mocha-requireHack.js',
'node_modules/es5-shim/es5-shim.js',
'test/*.js'

@@ -74,6 +75,7 @@ ],

proxies: {
'/dummyserver/': dummyserverCfg.url
}
});
};
cfg.proxies[dummyserverCfg.proxyPath + '/'] = dummyserverCfg.url;
config.set(cfg);
};
{
"name": "httpinvoke",
"version": "0.0.10",
"description": "HTTP client for JavaScript",
"version": "1.0.0",
"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.",
"keywords": [

@@ -25,7 +25,17 @@ "http",

],
"main": "./httpinvoke-generated-commonjs.js",
"main": "./httpinvoke-commonjs.js",
"private": false,
"dependencies": {},
"devDependencies": {
"mocha": "1.12.x",
"mime": "1.2.x",
"sizzle": "1.1.x",
"JSON2": "0.1.x",
"es5-shim": "2.1.x",
"grunt": "0.4.x",
"grunt-cli": "0.1.x",
"grunt-contrib-uglify": "0.2.x",
"grunt-contrib-concat": "0.3.x",
"grunt-mocha-test": "0.7.x",
"daemon": "1.1.x",
"mocha": "1.13.x",
"karma": "0.10.x",

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

"scripts": {
"install": "make",
"test": "make test"
"test": "./node_modules/.bin/grunt;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"
},

@@ -39,0 +50,0 @@ "repository": {

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