httpinvoke
Advanced tools
Comparing version 0.0.7 to 0.0.8
{ | ||
"name": "httpinvoke", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"main": "httpinvoke-browser.js", | ||
@@ -5,0 +5,0 @@ "ignore": [ |
@@ -5,3 +5,3 @@ { | ||
"description": "HTTP client for JavaScript", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"keywords": [ | ||
@@ -8,0 +8,0 @@ "http", |
@@ -21,27 +21,2 @@ (function (root, factory) { | ||
}; | ||
var createXHR = function() { | ||
try { | ||
createXHR = function() { | ||
return new XMLHttpRequest(); | ||
}; | ||
return createXHR(); | ||
} catch(err) { | ||
} | ||
var candidates = ['Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP']; | ||
var i = candidates.length - 1; | ||
while(i >= 0) { | ||
try { | ||
createXHR = function() { | ||
return new ActiveXObject(candidates[i]); | ||
}; | ||
return createXHR(); | ||
} catch(err) { | ||
} | ||
i -= 1; | ||
} | ||
createXHR = function() { | ||
throw new Error('Cannot construct XMLHttpRequest'); | ||
}; | ||
return createXHR(); | ||
}; | ||
@@ -88,5 +63,11 @@ var parseHeader = function(header) { | ||
var urlPartitioningRegExp = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/; | ||
var isCrossDomain = function(location, uri) { | ||
uri = urlPartitioningRegExp.exec(uri.toLowerCase()); | ||
location = urlPartitioningRegExp.exec(location.toLowerCase()) || []; | ||
return !!(uri && (uri[1] !== location[1] || uri[2] !== location[2] || (uri[3] || (uri[1] === 'http:' ? '80' : '443')) !== (location[3] || (location[1] === 'http:' ? '80' : '443')))); | ||
}; | ||
var noop = function() {}; | ||
var readyStates = ['UNSENT', 'OPENED', 'HEADERS_RECEIVED', 'LOADING', 'DONE']; | ||
return function(uri, method, options) { | ||
var createXHR; | ||
var httpinvoke = function(uri, method, options) { | ||
if(typeof method === 'undefined') { | ||
@@ -103,2 +84,6 @@ method = 'GET'; | ||
} | ||
options = typeof options === 'function' ? { | ||
finished: options | ||
} : options; | ||
var uploadProgressCb = options.uploading || noop; | ||
@@ -108,37 +93,66 @@ var downloadProgressCb = options.downloading || noop; | ||
var cb = options.finished || noop; | ||
var deleteCallbacks = function() { | ||
uploadProgressCb = null; | ||
downloadProgressCb = null; | ||
statusCb = null; | ||
cb = null; | ||
}; | ||
var input = options.input || null, inputLength = input === null ? 0 : input.length, inputHeaders = options.headers || {}; | ||
var exposedHeaders = options.corsHeaders || []; | ||
exposedHeaders.push.apply(exposedHeaders, ['Cache-Control', 'Content-Language', 'Content-Type', 'Expires', 'Last-Modified', 'Pragma']); | ||
var uploadProgressCbCalled = false; | ||
try { | ||
validateInputHeaders(inputHeaders); | ||
} catch(err) { | ||
cb(err); | ||
deleteCallbacks(); | ||
return; | ||
setTimeout(function() { | ||
if(cb === null) { | ||
return; | ||
} | ||
cb(err); | ||
}, 0); | ||
return function() { | ||
}; | ||
} | ||
var output, outputLength, outputHeaders = {}; | ||
var xhr = createXHR(); | ||
// IE may throw an exception when accessing | ||
// a field from window.location if document.domain has been set | ||
var currentLocation; | ||
try { | ||
currentLocation = window.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.href = ''; | ||
currentLocation = currentLocation.href; | ||
} | ||
var output, outputLength = null, outputHeaders = {}; | ||
var i; | ||
var xhr = createXHR(isCrossDomain(currentLocation, uri)); | ||
xhr.open(method, uri, true); | ||
if(options.corsCredentials && httpinvoke.corsCredentials) { | ||
xhr.withCredentials = true; | ||
} | ||
if(typeof xhr.upload !== 'undefined') { | ||
xhr.upload.ontimeout = function(progressEvent) { | ||
if(cb) { | ||
cb(new Error('upload timeout')); | ||
deleteCallbacks(); | ||
if(cb === null) { | ||
return; | ||
} | ||
cb(new Error('upload timeout')); | ||
cb = null; | ||
}; | ||
xhr.upload.onerror = function(progressEvent) { | ||
if(cb) { | ||
cb(new Error('upload error')); | ||
deleteCallbacks(); | ||
if(cb === null) { | ||
return; | ||
} | ||
cb(new Error('upload error')); | ||
cb = null; | ||
}; | ||
xhr.upload.onprogress = function(progressEvent) { | ||
if(uploadProgressCb && progressEvent.lengthComputable) { | ||
uploadProgressCb(0, progressEvent.loaded, inputLength); | ||
if(cb === null) { | ||
return; | ||
} | ||
if(progressEvent.lengthComputable) { | ||
if(!uploadProgressCbCalled) { | ||
uploadProgressCbCalled = true; | ||
uploadProgressCb(0, inputLength); | ||
} | ||
uploadProgressCb(progressEvent.loaded, inputLength); | ||
} | ||
}; | ||
@@ -149,14 +163,16 @@ } | ||
xhr.ontimeout = function(progressEvent) { | ||
if(cb) { | ||
cb(new Error('download timeout')); | ||
deleteCallbacks(); | ||
if(cb === null) { | ||
return; | ||
} | ||
cb(new Error('download timeout')); | ||
cb = null; | ||
}; | ||
} | ||
if(typeof xhr.onerror !== 'undefined') { | ||
xhr.onerror = function(progressEvent) { | ||
if(cb) { | ||
cb(new Error('download error')); | ||
deleteCallbacks(); | ||
xhr.onerror = function() { | ||
if(cb === null) { | ||
return; | ||
} | ||
cb(new Error('download error')); | ||
cb = null; | ||
}; | ||
@@ -166,8 +182,20 @@ } | ||
xhr.onprogress = function(progressEvent) { | ||
if(downloadProgressCb && progressEvent.lengthComputable) { | ||
downloadProgressCb(0, progressEvent.loaded, outputLength); | ||
if(cb === null) { | ||
return; | ||
} | ||
// TODO query xhr.responseText.length as a fallback | ||
if(typeof progressEvent !== 'undefined' && progressEvent.lengthComputable) { | ||
if(outputLength === null) { | ||
outputLength = progressEvent.total; | ||
downloadProgressCb(0, outputLength); | ||
} | ||
downloadProgressCb(progressEvent.loaded, outputLength); | ||
} | ||
}; | ||
} | ||
var onHeadersReceived = function() { | ||
var onHeadersReceived = function(lastTry) { | ||
if(cb === null) { | ||
return; | ||
} | ||
if(statusCb === null) { | ||
@@ -183,36 +211,90 @@ return; | ||
} | ||
fillOutputHeaders(xhr, outputHeaders); | ||
outputLength = Number(outputHeaders['content-length']); | ||
uploadProgressCb(0, inputLength, inputLength); | ||
uploadProgressCb = null; | ||
try { | ||
fillOutputHeaders(xhr, outputHeaders); | ||
} catch(err) { | ||
if(!lastTry) { | ||
throw err; | ||
} | ||
for(var i = 0; i < exposedHeaders.length; i += 1) { | ||
try { | ||
var header = xhr.getResponseHeader(exposedHeaders[i]); | ||
if(typeof header === 'string') { | ||
outputHeaders[exposedHeaders[i].toLowerCase()] = header; | ||
} | ||
} catch(err) { | ||
} | ||
} | ||
} | ||
if(!uploadProgressCbCalled) { | ||
uploadProgressCbCalled = true; | ||
uploadProgressCb(0, inputLength); | ||
} | ||
uploadProgressCb(inputLength, inputLength); | ||
if(cb === null) { | ||
return; | ||
} | ||
statusCb(xhr.status, outputHeaders); | ||
statusCb = null; | ||
downloadProgressCb(0, 0, outputLength); | ||
if(cb === null) { | ||
return; | ||
} | ||
if(outputLength === null && typeof outputHeaders['content-length'] !== 'undefined') { | ||
outputLength = Number(outputHeaders['content-length']); | ||
downloadProgressCb(0, outputLength); | ||
} | ||
}; | ||
xhr.onreadystatechange = function() { | ||
if(!cb) { | ||
var onLoad = function(a, b, c) { | ||
if(cb === null) { | ||
return; | ||
} | ||
var readyState = readyStates[xhr.readyState]; | ||
if(readyState === 'HEADERS_RECEIVED') { | ||
onHeadersReceived(); | ||
} else if(readyState === 'DONE') { | ||
if(xhr.status === 0) { | ||
cb(new Error('"some type" of network error')); | ||
deleteCallbacks(); | ||
return; | ||
} | ||
onHeadersReceived(); | ||
downloadProgressCb(0, outputLength, outputLength); | ||
downloadProgressCb = null; | ||
output = (typeof xhr.responseType === 'undefined' || xhr.responseType === '') ? 'text' : xhr.responseType; | ||
if(output === 'text') { | ||
cb(null, xhr.responseText); | ||
} else { | ||
cb(new Error('Unknown response body format ' + output)); | ||
} | ||
deleteCallbacks(); | ||
if(xhr.status === 0) { | ||
cb(new Error('"some type" of network error')); | ||
cb = null; | ||
return; | ||
} | ||
onHeadersReceived(true); | ||
if(cb === null) { | ||
return; | ||
} | ||
output = (typeof xhr.responseType === 'undefined' || xhr.responseType === '') ? 'text' : xhr.responseType; | ||
if(output === 'text') { | ||
output = xhr.responseText; | ||
} else { | ||
cb(new Error('Unknown response body format ' + output)); | ||
cb = null; | ||
return; | ||
} | ||
if(outputLength === null) { | ||
outputLength = output.length; | ||
downloadProgressCb(0, outputLength); | ||
} | ||
if(cb === null) { | ||
return; | ||
} | ||
downloadProgressCb(outputLength, outputLength); | ||
if(cb === null) { | ||
return; | ||
} | ||
cb(null, output); | ||
cb = null; | ||
}; | ||
xhr.open(method, uri, true); | ||
xhr.onreadystatechange = function() { | ||
if(xhr.readyState === 2) { | ||
// HEADERS_RECEIVED | ||
onHeadersReceived(false); | ||
} else if(xhr.readyState === 4) { | ||
// DONE | ||
onLoad(); | ||
} | ||
}; | ||
xhr.onload = onLoad; | ||
for(var inputHeaderName in inputHeaders) { | ||
@@ -225,14 +307,82 @@ if(inputHeaders.hasOwnProperty(inputHeaderName)) { | ||
xhr.send(input); | ||
uploadProgressCb(0, 0, inputLength); | ||
setTimeout(function() { | ||
if(cb === null) { | ||
return; | ||
} | ||
if(!uploadProgressCbCalled) { | ||
uploadProgressCbCalled = true; | ||
uploadProgressCb(0, inputLength); | ||
} | ||
}, 0); | ||
return function() { | ||
if(cb) { | ||
cb(new Error('abort')); | ||
deleteCallbacks(); | ||
try { | ||
xhr.abort(); | ||
} catch(err){ | ||
} | ||
if(cb === null) { | ||
return; | ||
} | ||
// these statements are in case "abort" is called in "finished" callback | ||
var _cb = cb; | ||
cb = null; | ||
_cb(new Error('abort')); | ||
try { | ||
xhr.abort(); | ||
} catch(err){ | ||
} | ||
}; | ||
}; | ||
httpinvoke.corsCredentials = false; | ||
httpinvoke.cors = false; | ||
(function() { | ||
try { | ||
createXHR = function() { | ||
return new XMLHttpRequest(); | ||
}; | ||
httpinvoke.cors = 'withCredentials' in createXHR(); | ||
if(!httpinvoke.cors) { | ||
throw ''; | ||
} | ||
httpinvoke.corsCredentials = true; | ||
return; | ||
} catch(err) { | ||
} | ||
try { | ||
if(typeof XDomainRequest === 'undefined') { | ||
createXHR = function() { | ||
return new XMLHttpRequest(); | ||
}; | ||
createXHR(); | ||
} else { | ||
createXHR = function(cors) { | ||
return cors ? new XDomainRequest() : new XMLHttpRequest(); | ||
}; | ||
createXHR(true); | ||
httpinvoke.cors = true; | ||
} | ||
return; | ||
} catch(err) { | ||
} | ||
try { | ||
createXHR(); | ||
return; | ||
} catch(err) { | ||
} | ||
var candidates = ['Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP']; | ||
var i = candidates.length - 1; | ||
while(i >= 0) { | ||
try { | ||
createXHR = function() { | ||
return new ActiveXObject(candidates[i]); | ||
}; | ||
createXHR(); | ||
return; | ||
} catch(err) { | ||
} | ||
i -= 1; | ||
} | ||
createXHR = function() { | ||
throw new Error('Cannot construct XMLHttpRequest'); | ||
}; | ||
})(); | ||
return httpinvoke; | ||
})); |
@@ -5,3 +5,3 @@ var http = require('http'); | ||
var noop = function() {}; | ||
module.exports = function(uri, method, options) { | ||
var httpinvoke = function(uri, method, options) { | ||
if(typeof method === 'undefined') { | ||
@@ -18,3 +18,6 @@ method = 'GET'; | ||
} | ||
options = options || {}; | ||
options = typeof options === 'function' ? { | ||
finished: options | ||
} : options; | ||
var uploadProgressCb = options.uploading || noop; | ||
@@ -24,8 +27,2 @@ var downloadProgressCb = options.downloading || noop; | ||
var cb = options.finished || noop; | ||
var deleteCallbacks = function() { | ||
uploadProgressCb = null; | ||
downloadProgressCb = null; | ||
statusCb = null; | ||
cb = null; | ||
}; | ||
var input = options.input || null, inputLength = input === null ? 0 : input.length, inputHeaders = options.headers || []; | ||
@@ -41,20 +38,39 @@ var output, outputLength, outputHeaders = {}; | ||
}, function(res) { | ||
if(statusCb) { | ||
statusCb(res.statusCode, res.headers); | ||
statusCb = null; | ||
if(cb === null) { | ||
return; | ||
} | ||
if(cb) { | ||
var output = ''; | ||
res.setEncoding('utf8'); | ||
res.on('data', function(chunk) { | ||
output += chunk; | ||
}); | ||
res.on('end', function() { | ||
if(cb) { | ||
cb(null, output); | ||
} | ||
}); | ||
uploadProgressCb(inputLength, inputLength); | ||
statusCb(res.statusCode, res.headers); | ||
if(typeof res.headers['content-length'] === 'undefined') { | ||
downloadProgressCb(0, 0); | ||
downloadProgressCb(0, 0); | ||
cb(null, ''); | ||
return; | ||
} | ||
outputLength = Number(res.headers['content-length']); | ||
downloadProgressCb(0, outputLength); | ||
var output = ''; | ||
res.setEncoding('utf8'); | ||
res.on('data', function(chunk) { | ||
if(cb === null) { | ||
return; | ||
} | ||
downloadProgressCb(output.length, outputLength); | ||
output += chunk; | ||
}); | ||
res.on('end', function() { | ||
if(cb === null) { | ||
return; | ||
} | ||
downloadProgressCb(outputLength, outputLength); | ||
cb(null, output); | ||
}); | ||
}); | ||
process.nextTick(function() { | ||
if(cb === null) { | ||
return; | ||
} | ||
uploadProgressCb(0, inputLength); | ||
}); | ||
if(input !== null) { | ||
@@ -64,6 +80,23 @@ req.write(input); | ||
req.on('error', function(e) { | ||
if(cb === null) { | ||
return; | ||
} | ||
cb(e); | ||
deleteCallbacks(); | ||
cb = null; | ||
}); | ||
req.end(); | ||
return function() { | ||
if(cb === null) { | ||
return; | ||
} | ||
// these statements are in case "abort" is called in "finished" callback | ||
var _cb = cb; | ||
cb = null; | ||
_cb(new Error('abort')); | ||
}; | ||
}; | ||
httpinvoke.cors = true; | ||
httpinvoke.corsCredentials = true; | ||
module.exports = httpinvoke; |
{ | ||
"name": "httpinvoke", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"description": "HTTP client for JavaScript", | ||
@@ -29,85 +29,9 @@ "keywords": [ | ||
"devDependencies": { | ||
"jasmine-node": "1.11.x", | ||
"serve": "1.3.x" | ||
"mocha": "1.12.x", | ||
"karma": "0.10.x", | ||
"karma-mocha": "0.1.x" | ||
}, | ||
"testling": { | ||
"scripts": [ | ||
"test/browser/lib/jasmine-2.0.0-rc2/jasmine.js", | ||
"test/testling/jasmine-tap.js", | ||
"test/testling/init.js", | ||
"httpinvoke-browser.js", | ||
"test/browser/requireHack.js", | ||
"test/specs/basicSpec.js" | ||
], | ||
"files": [ | ||
"test/testling/execute.js" | ||
], | ||
"browsers": [ | ||
"iexplore/6.0", | ||
"iexplore/7.0", | ||
"iexplore/8.0", | ||
"iexplore/10.0", | ||
"iexplore/9.0", | ||
"chrome/4.0", | ||
"chrome/5.0", | ||
"chrome/6.0", | ||
"chrome/7.0", | ||
"chrome/8.0", | ||
"chrome/9.0", | ||
"chrome/10.0", | ||
"chrome/11.0", | ||
"chrome/12.0", | ||
"chrome/13.0", | ||
"chrome/14.0", | ||
"chrome/15.0", | ||
"chrome/16.0", | ||
"chrome/17.0", | ||
"chrome/18.0", | ||
"chrome/19.0", | ||
"chrome/20.0", | ||
"chrome/21.0", | ||
"chrome/22.0", | ||
"chrome/23.0", | ||
"chrome/24.0", | ||
"chrome/25.0", | ||
"firefox/3.0", | ||
"firefox/3.5", | ||
"firefox/3.6", | ||
"firefox/4.0", | ||
"firefox/5.0", | ||
"firefox/6.0", | ||
"firefox/7.0", | ||
"firefox/8.0", | ||
"firefox/9.0", | ||
"firefox/10.0", | ||
"firefox/11.0", | ||
"firefox/12.0", | ||
"firefox/13.0", | ||
"firefox/14.0", | ||
"firefox/15.0", | ||
"firefox/16.0", | ||
"firefox/17.0", | ||
"firefox/18.0", | ||
"firefox/19.0", | ||
"opera/10.0", | ||
"opera/10.5", | ||
"opera/11.0", | ||
"opera/11.5", | ||
"opera/11.6", | ||
"opera/12.0", | ||
"safari/4.0", | ||
"safari/5.0.5", | ||
"safari/5.1", | ||
"firefox/nightly", | ||
"opera/next", | ||
"chrome/canary", | ||
"iphone/6.0", | ||
"ipad/6.0", | ||
"safari/6.0", | ||
"android-browser/4.2" | ||
] | ||
}, | ||
"scripts": { | ||
"install": "make", | ||
"test": "make test" | ||
"test": "make test-node-singlerun" | ||
}, | ||
@@ -114,0 +38,0 @@ "repository": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
45593
3
1089
133