Comparing version 0.4.9 to 0.5.0
@@ -8,8 +8,9 @@ ////////////////////////////////////////// | ||
var fs = require('fs'), | ||
http = require('http'), | ||
https = require('https'), | ||
url = require('url'), | ||
var fs = require('fs'), | ||
http = require('http'), | ||
https = require('https'), | ||
url = require('url'), | ||
stringify = require('qs').stringify, | ||
multipart = require('./multipart'); | ||
multipart = require('./multipart'), | ||
auth = require('./auth'); | ||
@@ -92,5 +93,8 @@ var version = JSON.parse(fs.readFileSync(__dirname + '/../package.json').toString()).version, | ||
if (options.username && options.password) { | ||
var b = new Buffer([options.username, options.password].join(':')); | ||
var auth_header = options.proxy ? 'Proxy-Authorization' : 'Authorization'; | ||
config.headers[auth_header] = 'Basic ' + b.toString('base64'); | ||
if (options.auth && (options.auth == 'auto' || options.auth == 'digest')) { | ||
config.credentials = [options.username, options.password]; | ||
} else { | ||
var auth_header = options.proxy ? 'Proxy-Authorization' : 'Authorization'; | ||
config.headers[auth_header] = auth.basic(options.username, options.password); | ||
} | ||
} | ||
@@ -134,3 +138,15 @@ | ||
}, | ||
get_auth_header: function(header, credentials, request_opts) { | ||
var type = header.split(' ')[0], | ||
user = credentials[0], | ||
pass = credentials[1]; | ||
if (type == 'Digest') { | ||
return auth.digest(header, user, pass, request_opts.method, request_opts.path); | ||
} else if (type == 'Basic') { | ||
return auth.basic(user, pass); | ||
} | ||
}, | ||
send_request: function(count, method, uri, config, post_data, callback){ | ||
@@ -144,14 +160,26 @@ | ||
var headers = resp.headers; | ||
if (timer) clearTimeout(timer); | ||
if ([301, 302].indexOf(resp.statusCode) != -1 && resp.headers.location){ | ||
if ([301, 302].indexOf(resp.statusCode) != -1 && headers.location) { | ||
if (count <= config.follow) | ||
return self.send_request(++count, 'GET', url.resolve(uri, resp.headers.location), config, null, callback); | ||
return self.send_request(++count, 'GET', url.resolve(uri, headers.location), config, null, callback); | ||
else if (config.follow > 0) | ||
return callback(new Error('Redirect loop in ' + resp.headers.location)); | ||
return callback(new Error('Max redirects reached. Possible loop in: ' + headers.location)); | ||
} | ||
if (resp.statusCode == 401 && headers['www-authenticate'] && config.credentials) { | ||
if (!config.headers['Authorization']) { // only if authentication hasn't been sent | ||
var auth_header = self.get_auth_header(headers['www-authenticate'], config.credentials, request_opts); | ||
if (auth_header) { | ||
config.headers['Authorization'] = auth_header; | ||
return self.send_request(count, method, uri, config, post_data, callback); | ||
} | ||
} | ||
} | ||
var chunks = [], length = 0, | ||
compressed = /gzip|deflate/.test(resp.headers['content-encoding']), | ||
mime = self.parse_content_type(resp.headers['content-type']); | ||
compressed = /gzip|deflate/.test(headers['content-encoding']), | ||
mime = self.parse_content_type(headers['content-type']); | ||
@@ -183,2 +211,4 @@ var response_opts = { | ||
} | ||
resp.bytes = length; | ||
@@ -185,0 +215,0 @@ if (typeof unzip != 'undefined' && compressed) |
{ | ||
"name": "needle" | ||
, "version": "0.4.9" | ||
, "version": "0.5.0" | ||
, "description": "Tiny yet feature-packed HTTP client. With multipart, charset decoding and proxy support." | ||
, "keywords": ["http", "https", "simple", "client", "multipart", "upload", "proxy", "deflate", "timeout", "charset", "iconv"] | ||
, "tags": ["http", "https", "simple", "client", "multipart", "upload", "proxy", "deflate", "timeout", "charset", "iconv"] | ||
, "keywords": ["http", "https", "simple", "request", "client", "multipart", "upload", "proxy", "deflate", "timeout", "charset", "iconv"] | ||
, "tags": ["http", "https", "simple", "request", "client", "multipart", "upload", "proxy", "deflate", "timeout", "charset", "iconv"] | ||
, "author": "Tomás Pollak <tomas@forkhq.com>" | ||
@@ -8,0 +8,0 @@ , "repository": { "type": "git", "url": "https://github.com/tomas/needle.git" } |
Needle | ||
====== | ||
The most handsome HTTP client in the Nodelands. Supports SSL, basic auth, proxied requests, | ||
non-UTF-8 content decoding, multipart form-data (e.g. file uploads), gzip/deflate compression and, | ||
as you would expect, follows redirects. Simple, nimble and to the point. | ||
The leanest and most handsome HTTP client in the Nodelands. Supports SSL, basic & digest auth, proxied requests, multipart form-data (e.g. file uploads), gzip/deflate compression, automatic XML/JSON parsing, follows redirects and decodes non-UTF-8 content. Two dependencies only. | ||
Ideal for performing simple, quick HTTP requests in Node.js. If you need OAuth, stream piping or anything fancier, you should check out mikeal's request module. | ||
Usage | ||
@@ -29,8 +29,9 @@ ----- | ||
- `timeout`: Returns error if no response received in X milisecs. Defaults to `10000` (10 secs). `0` means no timeout. | ||
- `follow`: When `false`, Needle won't follow redirects. Can also be a number or `true` (the default, 10 max). | ||
- `multipart`: Enables multipart/form-data encoding. Defaults to `false`. | ||
- `proxy`: Forwards request through HTTP proxy. Eg. `proxy: 'http://proxy.server.com:3128'` | ||
- `agent`: Uses an http.Agent of your choice, instead of the global (default) one. | ||
- `headers`: Object containing custom HTTP headers for request. Overrides defaults described below. | ||
- `timeout` : Returns error if no response received in X milisecs. Defaults to `10000` (10 secs). `0` means no timeout. | ||
- `follow` : Number of redirects to follow. `false` means don't follow any (default), `true` means 10. | ||
- `multipart` : Enables multipart/form-data encoding. Defaults to `false`. | ||
- `proxy` : Forwards request through HTTP(s) proxy. Eg. `proxy: 'http://proxy.server.com:3128'` | ||
- `agent` : Uses an http.Agent of your choice, instead of the global (default) one. | ||
- `headers` : Object containing custom HTTP headers for request. Overrides defaults described below. | ||
- `auth` : Determines what to do with provided username/password. Options are `auto`, `digest` or `basic` (default). | ||
@@ -40,5 +41,5 @@ Response options | ||
- `decode`: Whether to decode response to UTF-8 if Content-Type charset is different. Defaults to `true`. | ||
- `parse`: Whether to parse XML or JSON response bodies automagically. Defaults to `true`. | ||
- `output`: Dump response output to file. When response is text, this occurs after parsing/decoding is done. | ||
- `decode` : Whether to decode response to UTF-8 if Content-Type charset is different. Defaults to `true`. | ||
- `parse` : Whether to parse XML or JSON response bodies automagically. Defaults to `true`. | ||
- `output` : Dump response output to file. When response is text, this occurs after parsing/decoding is done. | ||
@@ -53,5 +54,5 @@ Note: To stay light on dependencies, Needle doesn't include the `xml2js` module used for XML parsing. To enable it, simply do `npm install xml2js`. | ||
- `compressed`: If `true`, sets 'Accept-Encoding' header to 'gzip,deflate', and inflates content if zipped. Defaults to `false`. | ||
- `username`: For HTTP basic auth. | ||
- `password`: For HTTP basic auth. Requires username to be passed, obviously. | ||
- `accept`: Sets 'Accept' HTTP header. Defaults to `*/*`. | ||
- `username` : For HTTP basic auth. | ||
- `password` : For HTTP basic auth. Requires username to be passed, obviously. | ||
- `accept` : Sets 'Accept' HTTP header. Defaults to `*/*`. | ||
- `connection`: Sets 'Connection' HTTP header. Defaults to `close`. | ||
@@ -86,3 +87,3 @@ - `user_agent`: Sets the 'User-Agent' HTTP header. Defaults to `Needle/{version} (Node.js {node_version})`. | ||
Examples | ||
------------- | ||
-------- | ||
@@ -221,2 +222,2 @@ ### GET with querystring | ||
(c) 2012 Fork Ltd. Licensed under the MIT license. | ||
(c) 2013 Fork Ltd. Licensed under the MIT license. |
Sorry, the diff of this file is not supported yet
28498
12
541
219
6