@nathanfaucett/request
Version:
http requests for the browser and node.js
202 lines (167 loc) • 5.97 kB
JavaScript
var http = require("http"),
url = require("url"),
once = require("@nathanfaucett/once"),
PromisePolyfill = require("@nathanfaucett/promise_polyfill"),
isString = require("@nathanfaucett/is_string"),
isNull = require("@nathanfaucett/is_null"),
isFunction = require("@nathanfaucett/is_function"),
extend = require("@nathanfaucett/extend"),
objectForEach = require("@nathanfaucett/object-for_each"),
objectFilter = require("@nathanfaucett/object-filter"),
trim = require("@nathanfaucett/trim"),
Response = require("./Response"),
defaults = require("./defaults"),
camelcaseHeader = require("./camelcaseHeader"),
parseContentType = require("./parseContentType");
var defaultHeaders = {
"Transfer-Encoding": "chunked"
};
module.exports = request;
function request(options) {
var results = "",
resolved = false,
plugins = request.plugins,
defer = null,
fullUrl,
nodeOptions,
req;
options = defaults(options);
fullUrl = url.parse(options.url);
nodeOptions = {
hostname: fullUrl.hostname,
port: fullUrl.port || 80,
path: fullUrl.path,
method: options.method,
auth:
options.user && options.password
? options.user + ":" + options.password
: null,
agent: options.agent,
headers: objectFilter(options.headers, isString)
};
req = http.request(nodeOptions);
plugins.emit("before", req, options);
if (options.isPromise) {
defer = PromisePolyfill.defer();
}
function onSuccess(response) {
plugins.emit("response", response, req, options);
plugins.emit("load", response, req, options);
if (options.isPromise) {
defer.resolve(response);
} else {
if (isFunction(options.success)) {
options.success(response);
}
}
}
function onError(response) {
plugins.emit("response", response, req, options);
plugins.emit("error", response, req, options);
if (options.isPromise) {
defer.reject(response);
} else {
if (isFunction(options.error)) {
options.error(response);
}
}
}
function onComplete(res) {
res.on("data", function ondata(chunk) {
results += chunk;
});
res.on(
"end",
once(function onload() {
var statusCode = +res.statusCode,
response = new Response(),
responseText = results;
response.url = fullUrl.href;
response.method = options.method;
response.statusCode = statusCode;
response.responseHeaders = parseResponseHeadersNode(
res.headers
);
response.requestHeaders = options.headers
? extend({}, defaultHeaders, options.headers)
: extend({}, defaultHeaders);
response.body = response.data = null;
if (responseText) {
if (options.transformResponse) {
response.body = response.data = options.transformResponse(
responseText
);
} else {
if (
parseContentType(
response.responseHeaders["Content-Type"]
) === "application/json"
) {
try {
response.body = response.data = JSON.parse(
responseText
);
} catch (e) {
response.body = response.data = e;
onError(response);
return;
}
} else if (responseText) {
response.body = response.data = responseText;
}
}
}
if (
(statusCode > 199 && statusCode < 301) ||
statusCode === 304
) {
onSuccess(response);
} else {
onError(response);
}
})
);
}
function onCompleteError(error) {
var response = {};
response.url = fullUrl.href;
response.method = options.method;
response.statusCode = 0;
response.responseHeaders = {};
response.requestHeaders = options.headers
? extend({}, options.headers)
: {};
response.body = response.data = error;
onError(response);
}
if (options.transformRequest) {
options.data = options.transformRequest(options.data);
} else {
if (!isString(options.data)) {
if (options.headers["Content-Type"] === "application/json") {
options.data = JSON.stringify(options.data);
} else {
options.data = options.data + "";
}
}
}
req.on("response", onComplete);
req.on("error", onCompleteError);
req.end(options.data);
plugins.emit("request", req, options);
return isNull(defer) ? undefined : defer.promise;
}
function parseResponseHeadersNode(responseHeaders) {
var headers = {};
objectForEach(Object(responseHeaders), function(value, key) {
if (key && value) {
key = camelcaseHeader(key);
value = trim(value);
if (key === "Content-Length") {
value = +value;
}
headers[key] = value;
}
});
return headers;
}