Coverage

99%
100
99
1

/Users/mk2/git/urllib/lib/urllib.js

99%
100
99
1
LineHitsSource
1/**
2 * Module dependencies.
3 */
4
51require('buffer-concat');
61var http = require('http');
71var https = require('https');
81var urlutil = require('url');
91var qs = require('querystring');
10
111var USER_AGENT = exports.USER_AGENT = 'node-urllib/1.0';
121var TIME_OUT = exports.TIME_OUT = 60000; // 60 seconds
13
14// change Agent.maxSockets to 1000
151exports.agent = new http.Agent();
161exports.agent.maxSockets = 1000;
17
181exports.httpsAgent = new https.Agent();
191exports.httpsAgent.maxSockets = 1000;
20
21/**
22 * The default request timeout(in milliseconds).
23 * @type {Number}
24 * @const
25 */
261exports.TIMEOUT = 5000;
27
28
29/**
30 * Handle all http request, both http and https support well.
31 *
32 * @example
33 *
34 * var urllib = require('urllib');
35 * // GET http://httptest.cnodejs.net
36 * urllib.request('http://httptest.cnodejs.net/test/get', function(err, data, res) {});
37 * // POST http://httptest.cnodejs.net
38 * var args = { type: 'post', data: { foo: 'bar' } };
39 * urllib.request('http://httptest.cnodejs.net/test/post', args, function(err, data, res) {});
40 *
41 * @param {String|Object} url
42 * @param {Object} [args], optional
43 * - {Object} [data]: request data, will auto be query stringify.
44 * - {String|Buffer} [content]: optional, if set content, `data` will ignore.
45 * - {ReadStream} [stream]: read stream to sent.
46 * - {WriteStream} [writeStream]: writable stream to save response data.
47 * If you use this, callback's data should be null.
48 * - {String} [type]: optional, could be GET | POST | DELETE | PUT, default is GET
49 * - {String} [dataType]: optional, `text` or `json`, default is text
50 * - {Object} [headers]: optional, request headers
51 * - {Number} [timeout]: request timeout(in milliseconds), default is `exports.TIMEOUT`
52 * - {Agent} [agent]: optional, http agent
53 * - {Agent} [httpsAgent]: optional, https agent
54 * - {String} auth: Basic authentication i.e. 'user:password' to compute an Authorization header.
55 * @param {Function} callback, callback(error, data, res)
56 * @param {Object} optional context of callback, callback.call(context, error, data, res)
57 * @return {HttpRequest} req object.
58 * @api public
59 */
601exports.request = function (url, args, callback, context) {
6126 if (typeof args === 'function') {
625 context = callback;
635 callback = args;
645 args = null;
65 }
6626 args = args || {};
6726 args.timeout = args.timeout || exports.TIMEOUT;
6826 var info = typeof url === 'string' ? urlutil.parse(url) : url;
6926 args.type = (args.type || args.method || info.method || 'GET').toUpperCase();
7026 var method = args.type;
7126 var port = info.port || 80;
7226 var httplib = http;
7326 var agent = args.agent || exports.agent;
7426 if (info.protocol === 'https:') {
752 httplib = https;
762 agent = args.httpsAgent || exports.httpsAgent;
772 if (!info.port) {
782 port = 443;
79 }
80 }
8126 var options = {
82 host: info.hostname || info.host || 'localhost',
83 path: info.path || '/',
84 method: method,
85 port: port,
86 agent: agent,
87 headers: args.headers || {}
88 };
89
9026 var auth = args.auth || info.auth;
9126 if (auth) {
922 options.auth = auth;
93 }
94
9526 var body = args.content || args.data;
9626 if (!args.content) {
9725 if (body && !(typeof body === 'string' || Buffer.isBuffer(body))) {
985 body = qs.stringify(body);
995 if (method === 'POST' || method === 'PUT') {
100 // auto add application/x-www-form-urlencoded when using urlencode form request
1013 if (!options.headers['Content-Type'] && !options.headers['content-type']) {
1022 options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
103 }
104 }
105 }
106 }
10726 if ((method === 'GET' || method === 'HEAD') && body) {
1082 options.path += (info.query ? '' : '?') + body;
1092 body = null;
110 }
11126 if (body) {
1126 var length = body.length;
1136 if (!Buffer.isBuffer(body)) {
1143 length = Buffer.byteLength(body);
115 }
1166 options.headers['Content-Length'] = length;
117 }
11826 if (args.dataType === 'json') {
1193 options.headers.Accept = 'application/json';
120 }
121
12226 var timer = null;
12326 var done = function (err, data, res) {
12425 if (timer) {
12524 clearTimeout(timer);
12624 timer = null;
127 }
12825 if (!callback) {
1290 return;
130 }
13125 var cb = callback;
13225 callback = null;
13325 cb.call(context, err, data, res);
134 };
135
13626 var writeStream = args.writeStream;
137
13826 var req = httplib.request(options, function (res) {
13921 if (writeStream) {
1401 res.on('end', callback.bind(null, null, null, res));
1411 return res.pipe(writeStream);
142 }
14320 var chunks = [], size = 0;
14420 res.on('data', function (chunk) {
145249 size += chunk.length;
146249 chunks.push(chunk);
147 });
14820 res.on('end', function () {
14920 var data = Buffer.concat(chunks, size);
15020 var err = null;
15120 if (args.dataType === 'json') {
1523 try {
1533 data = JSON.parse(data);
154 } catch (e) {
1551 err = e;
156 }
157 }
15820 done(err, data, res);
159 });
160 });
161
16226 var timeout = args.timeout;
16326 var __err = null;
16426 timer = setTimeout(function () {
1651 timer = null;
1661 __err = new Error('Request timeout for ' + timeout + 'ms.');
1671 __err.name = 'RequestTimeoutError';
1681 req.abort();
169 }, timeout);
17026 req.once('error', function (err) {
1715 if (!__err && err.name === 'Error') {
1722 err.name = 'RequestError';
173 }
1745 done(__err || err);
175 });
176
17726 if (writeStream) {
1783 writeStream.once('error', function (err) {
1791 __err = err;
1801 req.abort();
181 });
182 }
183
18426 if (args.stream) {
1853 args.stream.pipe(req);
1863 args.stream.once('error', function (err) {
1871 __err = err;
1881 req.abort();
189 });
190 } else {
19123 req.end(body);
192 }
19326 return req;
194};
195