ahr2
Version:
An Abstract Http Request for Node.JS (http/https) and the Browser (XMLHttpRequeuest2). For `npm install ahr2` for Node and `pakmanager build` for Ender / Pakmanager. It should be required as `var request = require('ahr2')`
127 lines (106 loc) • 3.47 kB
JavaScript
/*jshint strict:true node:true es5:true onevar:true laxcomma:true laxbreak:true eqeqeq:true immed:true latedef:true*/
(function (undefined) {
"use strict";
require('bufferjs');
var url = require('url')
, utils = require('../utils')
, parseJsonp = utils.parseJsonp
, extend = utils.extend;
// TODO NewEvent(type, size, total, data, chunk, err)
function onResponse(req, res) {
var data = []
, response = res.nodeResponse
, options = req.userOptions;
function onRedirect() {
// Redirect when requested
options.href = response.headers.location;
extend(options, url.parse(options.href));
options.redirectCount += 1;
if (options.headers) {
delete options.headers.host;
}
// Seems to work just fine
// TODO
// XXX wrap loadstart, error, load, progress
// TODO
req.on = function () {};
req.emit = function () {};
req.nodeHttpRequest(req, res);
}
function onTimeout() {
var err = new Error('timeout');
res.error = err;
res.cancelled = true;
res.emit('error', err);
}
function onData(chunk) {
clearTimeout(res.timeoutToken);
//res.timeoutToken = setTimeout(onTimeout, options.timeout);
res.size += chunk.length;
data.push(chunk);
res.emit('data', chunk);
res.emit('progress', {
// TODO check the content-length if available
lengthComputable: false
, loaded: res.size
, total: undefined
, nodePart: chunk
});
}
function onError(err) {
res.emit('error', err);
}
function onEnd() {
if (res.cancelled) {
return;
}
// TODO try/catch to use https://github.com/bnoordhuis/node-buffertools
data = Buffer.concat(data);
clearTimeout(res.timeoutToken); // Clear request timeout
if ('undefined' === typeof res.error && options.jsonp && data) {
data = data.toString('utf8');
data = parseJsonp(options.jsonpCallback, data);
}
// TODO this should go into a connect-like system
// this will handle bad json headers such as javascript/ or x-json
// but shouldn't match headers such as foobar/rajsonite
if (/[^a-z]json\b/i.exec(res.headers['content-type'])) {
try {
data = JSON.parse(data.toString('utf8'));
} catch(e) {
res.emit('error', e);
return;
}
}
res.emit('load', {
lengthComputable: true
, loaded: data.length
, total: data.length
, target: {
result: data
}
});
}
res.statusCode = response.statusCode;
res.headers = response.headers;
if (res.statusCode >= 400) {
// Error on Error
res.error = res.error || new Error(res.statusCode);
} else if (response.statusCode >= 300 &&
response.statusCode !== 304 &&
response.headers.location &&
options.followRedirect &&
options.redirectCount < options.redirectCountMax) {
return onRedirect();
}
// Set timeout for request
//res.timeoutToken = setTimeout(onTimeout, options.timeout);
res.size = 0;
// TODO use headers to determine size
res.emit('loadstart', {});
response.on('data', onData);
response.on('error', onError);
response.on('end', onEnd);
}
module.exports = onResponse;
}());