Comparing version 2.44.0 to 2.45.0
27
index.js
@@ -15,5 +15,6 @@ // Copyright 2010-2012 Mikeal Rogers | ||
'use strict'; | ||
var extend = require('util')._extend | ||
, cookies = require('./lib/cookies') | ||
, copy = require('./lib/copy') | ||
, helpers = require('./lib/helpers') | ||
@@ -106,3 +107,3 @@ , isFunction = helpers.isFunction | ||
request.defaults = function (options, requester) { | ||
var self = this | ||
var wrap = function (method) { | ||
@@ -130,3 +131,3 @@ var headerlessOptions = function (options) { | ||
if (isFunction(requester)) { | ||
if (method === request) { | ||
if (method === self) { | ||
method = requester | ||
@@ -142,12 +143,12 @@ } else { | ||
defaults = wrap(this) | ||
defaults.get = wrap(this.get) | ||
defaults.patch = wrap(this.patch) | ||
defaults.post = wrap(this.post) | ||
defaults.put = wrap(this.put) | ||
defaults.head = wrap(this.head) | ||
defaults.del = wrap(this.del) | ||
defaults.cookie = wrap(this.cookie) | ||
defaults.jar = this.jar | ||
defaults.defaults = this.defaults | ||
var defaults = wrap(self) | ||
defaults.get = wrap(self.get) | ||
defaults.patch = wrap(self.patch) | ||
defaults.post = wrap(self.post) | ||
defaults.put = wrap(self.put) | ||
defaults.head = wrap(self.head) | ||
defaults.del = wrap(self.del) | ||
defaults.cookie = wrap(self.cookie) | ||
defaults.jar = self.jar | ||
defaults.defaults = self.defaults | ||
return defaults | ||
@@ -154,0 +155,0 @@ } |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var optional = require('./optional') | ||
@@ -16,2 +18,16 @@ , tough = optional('tough-cookie') | ||
// Adapt the sometimes-Async api of tough.CookieJar to our requirements | ||
function RequestJar() { | ||
this._jar = new CookieJar(); | ||
} | ||
RequestJar.prototype.setCookie = function(cookieOrStr, uri, options) { | ||
return this._jar.setCookieSync(cookieOrStr, uri, options || {}); | ||
}; | ||
RequestJar.prototype.getCookieString = function(uri) { | ||
return this._jar.getCookieStringSync(uri); | ||
}; | ||
RequestJar.prototype.getCookies = function(uri) { | ||
return this._jar.getCookiesSync(uri); | ||
}; | ||
exports.jar = function() { | ||
@@ -21,10 +37,8 @@ if (!CookieJar) { | ||
return { | ||
setCookieSync: function(){}, | ||
getCookieStringSync: function(){}, | ||
getCookiesSync: function(){} | ||
setCookie: function(){}, | ||
getCookieString: function(){}, | ||
getCookies: function(){} | ||
}; | ||
} | ||
var jar = new CookieJar(); | ||
jar._jar = jar; // For backwards compatibility | ||
return jar; | ||
return new RequestJar(); | ||
}; |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
module.exports = | ||
@@ -8,2 +10,2 @@ function copy (obj) { | ||
return o | ||
} | ||
} |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var util = require('util') | ||
@@ -2,0 +4,0 @@ , request = require('../index') |
@@ -0,2 +1,7 @@ | ||
'use strict'; | ||
var extend = require('util')._extend | ||
, jsonSafeStringify = require('json-stringify-safe') | ||
, crypto = require('crypto') | ||
; | ||
@@ -46,2 +51,24 @@ function constructObject(initialObject) { | ||
function safeStringify (obj) { | ||
var ret | ||
try { | ||
ret = JSON.stringify(obj) | ||
} catch (e) { | ||
ret = jsonSafeStringify(obj) | ||
} | ||
return ret | ||
} | ||
function md5 (str) { | ||
return crypto.createHash('md5').update(str).digest('hex') | ||
} | ||
function isReadStream (rs) { | ||
return rs.readable && rs.path && rs.mode; | ||
} | ||
function toBase64 (str) { | ||
return (new Buffer(str || "", "ascii")).toString("base64") | ||
} | ||
exports.isFunction = isFunction | ||
@@ -52,1 +79,5 @@ exports.constructObject = constructObject | ||
exports.paramsHaveRequestBody = paramsHaveRequestBody | ||
exports.safeStringify = safeStringify | ||
exports.md5 = md5 | ||
exports.isReadStream = isReadStream | ||
exports.toBase64 = toBase64 |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
module.exports = function(moduleName) { | ||
@@ -2,0 +4,0 @@ try { |
@@ -10,3 +10,3 @@ { | ||
], | ||
"version": "2.44.0", | ||
"version": "2.45.0", | ||
"author": "Mikeal Rogers <mikeal.rogers@gmail.com>", | ||
@@ -21,5 +21,5 @@ "repository": { | ||
"license": "Apache-2.0", | ||
"engines": [ | ||
"node >= 0.8.0" | ||
], | ||
"engines": { | ||
"node": ">=0.8.0" | ||
}, | ||
"main": "index.js", | ||
@@ -34,7 +34,7 @@ "dependencies": { | ||
"node-uuid": "~1.4.0", | ||
"tunnel-agent": "~0.4.0" | ||
"tunnel-agent": "~0.4.0", | ||
"form-data": "~0.1.0" | ||
}, | ||
"optionalDependencies": { | ||
"tough-cookie": ">=0.12.0", | ||
"form-data": "~0.1.0", | ||
"http-signature": "~0.10.0", | ||
@@ -47,7 +47,9 @@ "oauth-sign": "~0.4.0", | ||
"scripts": { | ||
"test": "node tests/run.js" | ||
"test": "npm run lint && node tests/run.js", | ||
"lint": "./node_modules/eslint/bin/eslint.js lib/ *.js" | ||
}, | ||
"devDependencies": { | ||
"rimraf": "~2.2.8" | ||
"rimraf": "~2.2.8", | ||
"eslint": "0.5.1" | ||
} | ||
} |
126
README.md
@@ -171,2 +171,21 @@ # Request — Simplified HTTP client | ||
### Controlling proxy behaviour using environment variables | ||
The following environment variables are respected by `request`: | ||
* `HTTP_PROXY` / `http_proxy` | ||
* `HTTPS_PROXY` / `https_proxy` | ||
* `NO_PROXY` / `no_proxy` | ||
When `HTTP_PROXY` / `http_proxy` are set, they will be used to proxy non-SSL requests that do not have an explicit `proxy` configuration option present. Similarly, `HTTPS_PROXY` / `https_proxy` will be respected for SSL requests that do not have an explicit `proxy` configuration option. It is valid to define a proxy in one of the environment variables, but then override it for a specific request, using the `proxy` configuration option. Furthermore, the `proxy` configuration option can be explicitly set to false / null to opt out of proxying altogether for that request. | ||
`request` is also aware of the `NO_PROXY`/`no_proxy` environment variables. These variables provide a granular way to opt out of proxying, on a per-host basis. It should contain a comma separated list of hosts to opt out of proxying. It is also possible to opt of proxying when a particular destination port is used. Finally, the variable may be set to `*` to opt out of the implicit proxy configuration of the other environment variables. | ||
Here's some examples of valid `no_proxy` values: | ||
* `google.com` - don't proxy HTTP/HTTPS requests to Google. | ||
* `google.com:443` - don't proxy HTTPS requests to Google, but *do* proxy HTTP requests to Google. | ||
* `google.com:443, yahoo.com:80` - don't proxy HTTPS requests to Google, and don't proxy HTTP requests to Yahoo! | ||
* `*` - ignore `https_proxy`/`http_proxy` environment variables altogether. | ||
## UNIX Socket | ||
@@ -196,6 +215,13 @@ | ||
For `multipart/form-data` we use the [form-data](https://github.com/felixge/node-form-data) library by [@felixge](https://github.com/felixge). You don’t need to worry about piping the form object or setting the headers, `request` will handle that for you. | ||
For `multipart/form-data` we use the [form-data](https://github.com/felixge/node-form-data) library by [@felixge](https://github.com/felixge). For the most basic case, you can pass your upload form data via the `formData` option. | ||
```javascript | ||
var r = request.post('http://service.com/upload', function optionalCallback (err, httpResponse, body) { | ||
var formData = { | ||
my_field: 'my_value', | ||
my_buffer: new Buffer([1, 2, 3]), | ||
my_file: fs.createReadStream(__dirname + '/unicycle.jpg'), | ||
remote_file: request(remoteFile) | ||
}; | ||
request.post({url:'http://service.com/upload', formData: formData}, function optionalCallback(err, httpResponse, body) { | ||
if (err) { | ||
@@ -205,13 +231,49 @@ return console.error('upload failed:', err); | ||
console.log('Upload successful! Server responded with:', body); | ||
}); | ||
``` | ||
For more advanced cases (like appending form data options) you'll need access to the form itself. | ||
```javascript | ||
var r = request.post('http://service.com/upload', function optionalCallback(err, httpResponse, body) { | ||
if (err) { | ||
return console.error('upload failed:', err); | ||
} | ||
console.log('Upload successful! Server responded with:', body); | ||
}) | ||
var form = r.form() | ||
form.append('my_field', 'my_value') | ||
form.append('my_buffer', new Buffer([1, 2, 3])) | ||
form.append('my_file', fs.createReadStream(path.join(__dirname, 'doodle.png'))) | ||
form.append('remote_file', request('http://google.com/doodle.png')) | ||
// Just like always, `r` is a writable stream, and can be used as such (you have until nextTick to pipe it, etc.) | ||
// Alternatively, you can provide a callback (that's what this example does — see `optionalCallback` above). | ||
var form = r.form(); | ||
form.append('my_field', 'my_value'); | ||
form.append('my_buffer', new Buffer([1, 2, 3])); | ||
form.append('my_buffer', fs.createReadStream(__dirname + '/unicycle.jpg'), {filename: 'unicycle.jpg'}); | ||
``` | ||
See the [form-data](https://github.com/felixge/node-form-data) README for more information & examples. | ||
Some variations in different HTTP implementations require a newline/CRLF before, after, or both before and after the boundary of a `multipart/form-data` request. This has been observed in the .NET WebAPI version 4.0. You can turn on a boundary preambleCRLF or postamble by passing them as `true` to your request options. | ||
```javascript | ||
request( | ||
{ method: 'PUT' | ||
, preambleCRLF: true | ||
, postambleCRLF: true | ||
, uri: 'http://service.com/upload' | ||
, multipart: | ||
[ { 'content-type': 'application/json' | ||
, body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}}) | ||
} | ||
, { body: 'I am an attachment' } | ||
] | ||
} | ||
, function (error, response, body) { | ||
if (err) { | ||
return console.error('upload failed:', err); | ||
} | ||
console.log('Upload successful! Server responded with:', body); | ||
} | ||
) | ||
``` | ||
## HTTP Authentication | ||
@@ -349,6 +411,8 @@ | ||
* `multipart` - (experimental) array of objects which contains their own headers and `body` attribute. Sends `multipart/related` request. See example below. | ||
* `preambleCRLF` - append a newline/CRLF before the boundary of your `multipart/form-data` request. | ||
* `postambleCRLF` - append a newline/CRLF at the end of the boundary of your `multipart/form-data` request. | ||
* `followRedirect` - follow HTTP 3xx responses as redirects (default: `true`). This property can also be implemented as function which gets `response` object as a single argument and should return `true` if redirects should continue or `false` otherwise. | ||
* `followAllRedirects` - follow non-GET HTTP 3xx responses as redirects (default: `false`) | ||
* `maxRedirects` - the maximum number of redirects to follow (default: `10`) | ||
* `encoding` - Encoding to be used on `setEncoding` of response data. If `null`, the `body` is returned as a `Buffer`. | ||
* `encoding` - Encoding to be used on `setEncoding` of response data. If `null`, the `body` is returned as a `Buffer`. Anything else **(including the default value of `undefined`)** will be passed as the [encoding](http://nodejs.org/api/buffer.html#buffer_buffer) parameter to `toString()` (meaning this is effectively `utf8` by default). | ||
* `pool` - A hash object containing the agents for these requests. If omitted, the request will use the global pool (which is set to node's default `maxSockets`) | ||
@@ -365,3 +429,3 @@ * `pool.maxSockets` - Integer containing the maximum amount of sockets in the pool. | ||
* `localAddress` - Local interface to bind for network connections. | ||
* `gzip` - If `true`, add an `Accept-Encoding` header to request compressed content encodings from the server (if not already present) and decode supported content encodings in the response. | ||
* `gzip` - If `true`, add an `Accept-Encoding` header to request compressed content encodings from the server (if not already present) and decode supported content encodings in the response. **Note:** Automatic decoding of the response content is performed on the body data returned through `request` (both through the `request` stream and passed to the callback function) but is not performed on the `response` stream (available from the `response` event) which is the unmodified `http.IncomingMessage` object which may contain compressed data. See example below. | ||
* `tunnel` - If `true`, then *always* use a tunneling proxy. If | ||
@@ -495,2 +559,33 @@ `false` (default), then tunneling will only be used if the | ||
For backwards-compatibility, response compression is not supported by default. | ||
To accept gzip-compressed responses, set the `gzip` option to `true`. Note | ||
that the body data passed through `request` is automatically decompressed | ||
while the response object is unmodified and will contain compressed data if | ||
the server sent a compressed response. | ||
```javascript | ||
var request = require('request') | ||
request( | ||
{ method: 'GET' | ||
, uri: 'http://www.google.com' | ||
, gzip: true | ||
} | ||
, function (error, response, body) { | ||
// body is the decompressed response body | ||
console.log('server encoded the data as: ' + (response.headers['content-encoding'] || 'identity')) | ||
console.log('the decoded data is: ' + body) | ||
} | ||
).on('data', function(data) { | ||
// decompressed data as it is received | ||
console.log('decoded chunk: ' + data) | ||
}) | ||
.on('response', function(response) { | ||
// unmodified http.IncomingMessage object | ||
response.on('data', function(data) { | ||
// compressed data as it is received | ||
console.log('received ' + data.length + ' bytes of compressed data') | ||
}) | ||
}) | ||
``` | ||
Cookies are disabled by default (else, they would be used in subsequent requests). To enable cookies, set `jar` to `true` (either in `defaults` or `options`) and install `tough-cookie`. | ||
@@ -519,6 +614,7 @@ | ||
// `npm install --save tough-cookie` before this works | ||
var j = request.jar() | ||
var cookie = request.cookie('your_cookie_here') | ||
j.setCookie(cookie, uri); | ||
request({url: 'http://www.google.com', jar: j}, function () { | ||
var j = request.jar(); | ||
var cookie = request.cookie('key1=value1'); | ||
var url = 'http://www.google.com'; | ||
j.setCookieSync(cookie, url); | ||
request({url: url, jar: j}, function () { | ||
request('http://images.google.com') | ||
@@ -533,4 +629,4 @@ }) | ||
request({url: 'http://www.google.com', jar: j}, function () { | ||
var cookie_string = j.getCookieStringSync(uri); // "key1=value1; key2=value2; ..." | ||
var cookies = j.getCookiesSync(uri); | ||
var cookie_string = j.getCookieString(uri); // "key1=value1; key2=value2; ..." | ||
var cookies = j.getCookies(uri); | ||
// [{key: 'key1', value: 'value1', domain: "www.google.com", ...}, ...] | ||
@@ -537,0 +633,0 @@ }) |
313
request.js
@@ -0,5 +1,6 @@ | ||
'use strict'; | ||
var optional = require('./lib/optional') | ||
, http = require('http') | ||
, https = optional('https') | ||
, tls = optional('tls') | ||
, url = require('url') | ||
@@ -10,5 +11,8 @@ , util = require('util') | ||
, querystring = require('querystring') | ||
, crypto = require('crypto') | ||
, zlib = require('zlib') | ||
, helpers = require('./lib/helpers') | ||
, safeStringify = helpers.safeStringify | ||
, md5 = helpers.md5 | ||
, isReadStream = helpers.isReadStream | ||
, toBase64 = helpers.toBase64 | ||
, bl = require('bl') | ||
@@ -22,3 +26,2 @@ , oauth = optional('oauth-sign') | ||
, tunnel = require('tunnel-agent') | ||
, _safeStringify = require('json-stringify-safe') | ||
, stringstream = optional('stringstream') | ||
@@ -38,9 +41,2 @@ , caseless = require('caseless') | ||
function safeStringify (obj) { | ||
var ret | ||
try { ret = JSON.stringify(obj) } | ||
catch (e) { ret = _safeStringify(obj) } | ||
return ret | ||
} | ||
var globalPool = {} | ||
@@ -76,69 +72,36 @@ var isUrl = /^https?:|^unix:/ | ||
function isReadStream (rs) { | ||
return rs.readable && rs.path && rs.mode; | ||
} | ||
function toBase64 (str) { | ||
return (new Buffer(str || "", "ascii")).toString("base64") | ||
} | ||
function md5 (str) { | ||
return crypto.createHash('md5').update(str).digest('hex') | ||
} | ||
// Return a simpler request object to allow serialization | ||
function requestToJSON() { | ||
return { | ||
uri: this.uri, | ||
method: this.method, | ||
headers: this.headers | ||
} | ||
} | ||
// Return a simpler response object to allow serialization | ||
function responseToJSON() { | ||
return { | ||
statusCode: this.statusCode, | ||
body: this.body, | ||
headers: this.headers, | ||
request: requestToJSON.call(this.request) | ||
} | ||
} | ||
function Request (options) { | ||
stream.Stream.call(this) | ||
this.readable = true | ||
this.writable = true | ||
// if tunnel property of options was not given default to false | ||
// if given the method property in options, set property explicitMethod to true | ||
if (typeof options === 'string') { | ||
options = {uri:options} | ||
} | ||
// extend the Request instance with any non-reserved properties | ||
// remove any reserved functions from the options object | ||
// set Request instance to be readable and writable | ||
// call init | ||
var self = this | ||
stream.Stream.call(self) | ||
var reserved = Object.keys(Request.prototype) | ||
for (var i in options) { | ||
if (reserved.indexOf(i) === -1) { | ||
this[i] = options[i] | ||
} else { | ||
if (typeof options[i] === 'function') { | ||
delete options[i] | ||
} | ||
} | ||
var nonReserved = filterForNonReserved(reserved, options) | ||
util._extend(this, nonReserved) | ||
options = filterOutReservedFunctions(reserved, options) | ||
self.readable = true | ||
self.writable = true | ||
if (typeof options.tunnel === 'undefined') { | ||
options.tunnel = false | ||
} | ||
if (options.method) { | ||
this.explicitMethod = true | ||
self.explicitMethod = true | ||
} | ||
self.canTunnel = options.tunnel !== false && tunnel | ||
self.init(options) | ||
} | ||
// Assume that we're not going to tunnel unless we need to | ||
if (typeof options.tunnel === 'undefined') options.tunnel = false | ||
this.init(options) | ||
} | ||
util.inherits(Request, stream.Stream) | ||
// Set up the tunneling agent if necessary | ||
Request.prototype.setupTunnel = function () { | ||
var self = this | ||
if (typeof self.proxy == 'string') self.proxy = url.parse(self.proxy) | ||
if (typeof self.proxy === 'string') self.proxy = url.parse(self.proxy) | ||
@@ -148,4 +111,3 @@ if (!self.proxy) return false | ||
// Don't need to use a tunneling proxy | ||
if (!self.tunnel && self.uri.protocol !== 'https:') | ||
return | ||
if (!self.tunnel && self.uri.protocol !== 'https:') return false | ||
@@ -257,4 +219,4 @@ // do the HTTP CONNECT dance using koichik/node-tunnel | ||
return self.emit('error', new Error("options.uri is a required argument")) | ||
} else { | ||
if (typeof self.uri == "string") self.uri = url.parse(self.uri) | ||
} else if (typeof self.uri === "string") { | ||
self.uri = url.parse(self.uri) | ||
} | ||
@@ -268,8 +230,47 @@ | ||
// check for HTTP(S)_PROXY environment variables | ||
if(self.uri.protocol == "http:") { | ||
if(self.uri.protocol === "http:") { | ||
self.proxy = process.env.HTTP_PROXY || process.env.http_proxy || null; | ||
} else if(self.uri.protocol == "https:") { | ||
} else if(self.uri.protocol === "https:") { | ||
self.proxy = process.env.HTTPS_PROXY || process.env.https_proxy || | ||
process.env.HTTP_PROXY || process.env.http_proxy || null; | ||
} | ||
// respect NO_PROXY environment variables | ||
// ref: http://lynx.isc.org/current/breakout/lynx_help/keystrokes/environments.html | ||
var noProxy = process.env.NO_PROXY || process.env.no_proxy || null | ||
// easy case first - if NO_PROXY is '*' | ||
if (noProxy === '*') { | ||
self.proxy = null | ||
} else if (noProxy !== null) { | ||
var noProxyItem, hostname, port, noProxyItemParts, noProxyHost, noProxyPort, noProxyList | ||
// canonicalize the hostname, so that 'oogle.com' won't match 'google.com' | ||
hostname = self.uri.hostname.replace(/^\.*/, '.').toLowerCase() | ||
noProxyList = noProxy.split(',') | ||
for (var i = 0, len = noProxyList.length; i < len; i++) { | ||
noProxyItem = noProxyList[i].trim().toLowerCase() | ||
// no_proxy can be granular at the port level, which complicates things a bit. | ||
if (noProxyItem.indexOf(':') > -1) { | ||
noProxyItemParts = noProxyItem.split(':', 2) | ||
noProxyHost = noProxyItemParts[0].replace(/^\.*/, '.') | ||
noProxyPort = noProxyItemParts[1] | ||
port = self.uri.port || (self.uri.protocol === 'https:' ? '443' : '80') | ||
if (port === noProxyPort && hostname.indexOf(noProxyHost) === hostname.length - noProxyHost.length) { | ||
// we've found a match - ports are same and host ends with no_proxy entry. | ||
self.proxy = null | ||
break | ||
} | ||
} else { | ||
noProxyItem = noProxyItem.replace(/^\.*/, '.') | ||
if (hostname.indexOf(noProxyItem) === hostname.length - noProxyItem.length) { | ||
self.proxy = null | ||
break | ||
} | ||
} | ||
} | ||
} | ||
} | ||
@@ -285,3 +286,3 @@ | ||
if (!self.uri.host && !self.protocol=='unix:') { | ||
if (!self.uri.host && self.uri.protocol !== 'unix:') { | ||
// Invalid URI: it may generate lot of bad errors, like "TypeError: Cannot call method 'indexOf' of undefined" in CookieJar | ||
@@ -297,4 +298,4 @@ // Detect and reject it as soon as possible | ||
} | ||
self.emit('error', new Error(message)) | ||
return // This error was fatal | ||
// This error was fatal | ||
return self.emit('error', new Error(message)) | ||
} | ||
@@ -318,3 +319,3 @@ | ||
!(self.uri.port === 443 && self.uri.protocol === 'https:') ) | ||
self.setHeader('host', self.getHeader('host') + (':'+self.uri.port) ) | ||
self.setHeader('host', self.getHeader('host') + (':' + self.uri.port) ) | ||
} | ||
@@ -327,4 +328,4 @@ self.setHost = true | ||
if (!self.uri.port) { | ||
if (self.uri.protocol == 'http:') {self.uri.port = 80} | ||
else if (self.uri.protocol == 'https:') {self.uri.port = 443} | ||
if (self.uri.protocol === 'http:') {self.uri.port = 80} | ||
else if (self.uri.protocol === 'https:') {self.uri.port = 443} | ||
} | ||
@@ -375,2 +376,12 @@ | ||
if (options.formData) { | ||
var formData = options.formData | ||
var requestForm = self.form() | ||
for (var formKey in formData) { | ||
if (formData.hasOwnProperty(formKey)) { | ||
requestForm.append(formKey, formData[formKey]) | ||
} | ||
} | ||
} | ||
if (options.qs) self.qs(options.qs) | ||
@@ -421,4 +432,4 @@ | ||
if (self.uri.auth && !self.hasHeader('authorization')) { | ||
var authPieces = self.uri.auth.split(':').map(function(item){ return querystring.unescape(item) }) | ||
self.auth(authPieces[0], authPieces.slice(1).join(':'), true) | ||
var uriAuthPieces = self.uri.auth.split(':').map(function(item){ return querystring.unescape(item) }) | ||
self.auth(uriAuthPieces[0], uriAuthPieces.slice(1).join(':'), true) | ||
} | ||
@@ -428,6 +439,6 @@ | ||
if (self.proxy.auth && !self.proxyAuthorization) { | ||
var authPieces = self.proxy.auth.split(':').map(function(item){ | ||
var proxyAuthPieces = self.proxy.auth.split(':').map(function(item){ | ||
return querystring.unescape(item) | ||
}) | ||
var authHeader = 'Basic ' + toBase64(authPieces.join(':')) | ||
var authHeader = 'Basic ' + toBase64(proxyAuthPieces.join(':')) | ||
self.proxyAuthorization = authHeader | ||
@@ -582,18 +593,17 @@ } | ||
var full_path = self.uri.href.replace(self.uri.protocol+'/', ''); | ||
var full_path = self.uri.href.replace(self.uri.protocol + '/', ''); | ||
var lookup = full_path.split('/'); | ||
var error_connecting = true; | ||
var lookup_table = {}; | ||
do { lookup_table[lookup.join('/')]={} } while(lookup.pop()) | ||
for (r in lookup_table){ | ||
do { lookup_table[lookup.join('/')] = {} } while(lookup.pop()) | ||
for (var r in lookup_table){ | ||
try_next(r); | ||
} | ||
function try_next(table_row){ | ||
function try_next(table_row) { | ||
var client = net.connect( table_row ); | ||
client.path = table_row | ||
client.on('error', function(){ lookup_table[this.path].error_connecting=true; this.end(); }); | ||
client.on('connect', function(){ lookup_table[this.path].error_connecting=false; this.end(); }); | ||
client.on('error', function(){ lookup_table[this.path].error_connecting = true; this.end(); }); | ||
client.on('connect', function(){ lookup_table[this.path].error_connecting = false; this.end(); }); | ||
table_row.client = client; | ||
@@ -604,7 +614,7 @@ } | ||
response_counter = 0; | ||
var response_counter = 0; | ||
function wait_for_socket_response(){ | ||
var detach; | ||
if('undefined' == typeof setImmediate ) detach = process.nextTick | ||
if(typeof setImmediate === 'undefined') detach = process.nextTick | ||
else detach = setImmediate; | ||
@@ -616,6 +626,6 @@ detach(function(){ | ||
for (r in lookup_table){ | ||
if('undefined' == typeof lookup_table[r].error_connecting) | ||
if(typeof lookup_table[r].error_connecting === 'undefined') | ||
trying = true; | ||
} | ||
if(trying && response_counter<1000) | ||
if(trying && response_counter < 1000) | ||
wait_for_socket_response() | ||
@@ -635,3 +645,3 @@ else | ||
if(!host){ | ||
self.emit('error', new Error("Failed to connect to any socket in "+full_path)) | ||
self.emit('error', new Error("Failed to connect to any socket in " + full_path)) | ||
} | ||
@@ -790,6 +800,6 @@ var path = full_path.replace(host, '') | ||
// already generated an agent for this setting | ||
if (this.pool[poolKey]) return this.pool[poolKey] | ||
// generate a new agent for this setting if none yet exists | ||
if (!this.pool[poolKey]) this.pool[poolKey] = new Agent(options) | ||
return this.pool[poolKey] = new Agent(options) | ||
return this.pool[poolKey] | ||
} | ||
@@ -825,3 +835,3 @@ | ||
self.timeoutTimer = setTimeout(function () { | ||
self.req.abort() | ||
self.abort() | ||
var e = new Error("ETIMEDOUT") | ||
@@ -850,2 +860,6 @@ e.code = "ETIMEDOUT" | ||
}) | ||
self.req.on('socket', function(socket) { | ||
self.emit('socket', socket) | ||
}) | ||
self.on('end', function() { | ||
@@ -874,4 +888,4 @@ if ( self.req.connection ) self.req.connection.removeListener('error', self._parserErrorHandler) | ||
if (self._paused) response.pause() | ||
// Check that response.resume is defined. Workaround for browserify. | ||
else response.resume && response.resume() | ||
// response.resume should be defined, but check anyway before calling. Workaround for browserify. | ||
else if (response.resume) response.resume() | ||
@@ -888,3 +902,3 @@ self.response = response | ||
var sslErr = response.hasOwnProperty('client') ? response.client.authorizationError : self.uri.href + " does not support SSL"; | ||
self.emit('error', new Error('SSL Error: '+ sslErr)) | ||
self.emit('error', new Error('SSL Error: ' + sslErr)) | ||
return | ||
@@ -899,7 +913,7 @@ } | ||
var targetCookieJar = (self._jar && self._jar.setCookieSync)?self._jar:globalCookieJar; | ||
var targetCookieJar = (self._jar && self._jar.setCookie) ? self._jar : globalCookieJar; | ||
var addCookie = function (cookie) { | ||
//set the cookie if it's domain in the href's domain. | ||
try { | ||
targetCookieJar.setCookieSync(cookie, self.uri.href, {ignoreError: true}); | ||
targetCookieJar.setCookie(cookie, self.uri.href, {ignoreError: true}); | ||
} catch (e) { | ||
@@ -938,3 +952,3 @@ self.emit('error', e); | ||
} | ||
} else if (response.statusCode == 401 && self._hasAuth && !self._sentAuth) { | ||
} else if (response.statusCode === 401 && self._hasAuth && !self._sentAuth) { | ||
var authHeader = response.caseless.get('www-authenticate') | ||
@@ -997,8 +1011,8 @@ var authVerb = authHeader && authHeader.split(' ')[0].toLowerCase() | ||
for (var k in authValues) { | ||
if (!authValues[k]) { | ||
//ignore | ||
} else if (k === 'qop' || k === 'nc' || k === 'algorithm') { | ||
authHeader.push(k + '=' + authValues[k]) | ||
} else { | ||
authHeader.push(k + '="' + authValues[k] + '"') | ||
if (authValues[k]) { | ||
if (k === 'qop' || k === 'nc' || k === 'algorithm') { | ||
authHeader.push(k + '=' + authValues[k]) | ||
} else { | ||
authHeader.push(k + '="' + authValues[k] + '"') | ||
} | ||
} | ||
@@ -1023,3 +1037,3 @@ } | ||
if (self._redirectsFollowed >= self.maxRedirects) { | ||
self.emit('error', new Error("Exceeded maxRedirects. Probably stuck in a redirect loop "+self.uri.href)) | ||
self.emit('error', new Error("Exceeded maxRedirects. Probably stuck in a redirect loop " + self.uri.href)) | ||
return | ||
@@ -1046,3 +1060,3 @@ } | ||
) | ||
if (self.followAllRedirects && response.statusCode != 401 && response.statusCode != 307) self.method = 'GET' | ||
if (self.followAllRedirects && response.statusCode !== 401 && response.statusCode !== 307) self.method = 'GET' | ||
// self.method = 'GET' // Force all redirects to use GET || commented out fixes #215 | ||
@@ -1053,3 +1067,3 @@ delete self.src | ||
delete self._started | ||
if (response.statusCode != 401 && response.statusCode != 307) { | ||
if (response.statusCode !== 401 && response.statusCode !== 307) { | ||
// Remove parameters from the previous response, unless this is the second request | ||
@@ -1172,3 +1186,3 @@ // for a server that requires digest authentication. | ||
debug('emitting complete', self.uri.href) | ||
if(response.body == undefined && !self._json) { | ||
if(typeof response.body === 'undefined' && !self._json) { | ||
response.body = ""; | ||
@@ -1283,3 +1297,3 @@ } | ||
var body = part.body | ||
if(body == null) throw Error('Body attribute missing in multipart.') | ||
if(typeof body === 'undefined') throw new Error('Body attribute missing in multipart.') | ||
delete part.body | ||
@@ -1296,2 +1310,7 @@ var preamble = '--' + self.boundary + '\r\n' | ||
self.body.push(new Buffer('--' + self.boundary + '--')) | ||
if (self.postambleCRLF) { | ||
self.body.push(new Buffer('\r\n')) | ||
} | ||
return self | ||
@@ -1336,3 +1355,3 @@ } | ||
this._hasAuth = true | ||
if (sendImmediately || typeof sendImmediately == 'undefined') { | ||
if (sendImmediately || typeof sendImmediately === 'undefined') { | ||
if (typeof bearer === 'function') { | ||
@@ -1353,3 +1372,3 @@ bearer = bearer() | ||
var header = typeof pass !== 'undefined' ? user + ':' + pass : user | ||
if (sendImmediately || typeof sendImmediately == 'undefined') { | ||
if (sendImmediately || typeof sendImmediately === 'undefined') { | ||
this.setHeader('authorization', 'Basic ' + toBase64(header)) | ||
@@ -1426,3 +1445,3 @@ this._sentAuth = true | ||
var oa = {} | ||
for (var i in _oauth) oa['oauth_'+i] = _oauth[i] | ||
for (var i in _oauth) oa['oauth_' + i] = _oauth[i] | ||
if ('oauth_realm' in oa) delete oa.oauth_realm | ||
@@ -1447,3 +1466,3 @@ | ||
var authHeader = 'OAuth ' + realm + | ||
Object.keys(oa).sort().map(function (i) {return i+'="'+oauth.rfc3986(oa[i])+'"'}).join(',') | ||
Object.keys(oa).sort().map(function (i) {return i + '="' + oauth.rfc3986(oa[i]) + '"'}).join(',') | ||
authHeader += ',oauth_signature="' + oauth.rfc3986(signature) + '"' | ||
@@ -1465,7 +1484,7 @@ this.setHeader('Authorization', authHeader) | ||
} else { | ||
var targetCookieJar = (jar && jar.getCookieStringSync)?jar:globalCookieJar; | ||
var targetCookieJar = (jar && jar.getCookieString) ? jar : globalCookieJar; | ||
var urihref = this.uri.href | ||
//fetch cookie in the Specified host | ||
if (targetCookieJar) { | ||
cookies = targetCookieJar.getCookieStringSync(urihref); | ||
cookies = targetCookieJar.getCookieString(urihref); | ||
} | ||
@@ -1528,8 +1547,58 @@ } | ||
Request.prototype.toJSON = requestToJSON | ||
Request.defaultProxyHeaderWhiteList = | ||
defaultProxyHeaderWhiteList.slice() | ||
// Helpers | ||
// Return a simpler request object to allow serialization | ||
function requestToJSON() { | ||
return { | ||
uri: this.uri, | ||
method: this.method, | ||
headers: this.headers | ||
} | ||
} | ||
// Return a simpler response object to allow serialization | ||
function responseToJSON() { | ||
return { | ||
statusCode: this.statusCode, | ||
body: this.body, | ||
headers: this.headers, | ||
request: requestToJSON.call(this.request) | ||
} | ||
} | ||
function filterForNonReserved(reserved, options) { | ||
// Filter out properties that are not reserved. | ||
// Reserved values are passed in at call site. | ||
var object = {} | ||
for (var i in options) { | ||
var notReserved = (reserved.indexOf(i) === -1) | ||
if (notReserved) { | ||
object[i] = options[i] | ||
} | ||
} | ||
return object | ||
} | ||
function filterOutReservedFunctions(reserved, options) { | ||
// Filter out properties that are functions and are reserved. | ||
// Reserved values are passed in at call site. | ||
var object = {} | ||
for (var i in options) { | ||
var isReserved = !(reserved.indexOf(i) === -1) | ||
var isFunction = (typeof options[i] === 'function') | ||
if (!(isReserved && isFunction)) { | ||
object[i] = options[i] | ||
} | ||
} | ||
return object | ||
} | ||
// Exports | ||
Request.prototype.toJSON = requestToJSON | ||
module.exports = Request |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
221032
17
1631
640
2
11
3
+ Addedform-data@~0.1.0