Comparing version 2.9.100 to 2.9.150
731
main.js
@@ -1,2 +0,2 @@ | ||
// Copyright 2010-2011 Mikeal Rogers | ||
// Copyright 2010-2012 Mikeal Rogers | ||
// | ||
@@ -70,3 +70,5 @@ // Licensed under the Apache License, Version 2.0 (the "License"); | ||
var o = {} | ||
for (var i in obj) o[i] = obj[i] | ||
Object.keys(obj).forEach(function (i) { | ||
o[i] = obj[i] | ||
}) | ||
return o | ||
@@ -80,5 +82,6 @@ } | ||
function Request (options) { | ||
stream.Stream.call(this) | ||
this.readable = true | ||
this.writable = true | ||
var self = this | ||
stream.Stream.call(self) | ||
self.readable = true | ||
self.writable = true | ||
@@ -89,19 +92,18 @@ if (typeof options === 'string') { | ||
var reserved = Object.keys(Request.prototype) | ||
for (var i in options) { | ||
this[i] = options[i] | ||
if (reserved.indexOf(i) === -1) { | ||
self[i] = options[i] | ||
} else { | ||
if (typeof options[i] === 'function') { | ||
delete options[i] | ||
} | ||
} | ||
} | ||
if (!this.pool) this.pool = globalPool | ||
this.dests = [] | ||
this.__isRequestRequest = true | ||
} | ||
util.inherits(Request, stream.Stream) | ||
Request.prototype.getAgent = function (host, port) { | ||
if (!this.pool[host+':'+port]) { | ||
this.pool[host+':'+port] = new this.httpModule.Agent({host:host, port:port}) | ||
} | ||
return this.pool[host+':'+port] | ||
} | ||
Request.prototype.request = function () { | ||
var self = this | ||
options = copy(options) | ||
if (!self.pool) self.pool = globalPool | ||
self.dests = [] | ||
self.__isRequestRequest = true | ||
// Protect against double callback | ||
@@ -135,3 +137,4 @@ if (!self._callback && self.callback) { | ||
self.followRedirect = (self.followRedirect !== undefined) ? self.followRedirect : true | ||
if (self.followRedirect) | ||
self.followAllRedirects = (self.followAllRedirects !== undefined) ? self.followAllRedirects : false; | ||
if (self.followRedirect || self.followAllRedirects) | ||
self.redirects = self.redirects || [] | ||
@@ -141,3 +144,3 @@ | ||
var setHost = false | ||
self.setHost = false | ||
if (!self.headers.host) { | ||
@@ -150,24 +153,7 @@ self.headers.host = self.uri.hostname | ||
} | ||
setHost = true | ||
self.setHost = true | ||
} | ||
self.jar(options.jar) | ||
if (self.jar === false) { | ||
// disable cookies | ||
var cookies = false; | ||
self._disableCookies = true; | ||
} else if (self.jar) { | ||
// fetch cookie from the user defined cookie jar | ||
var cookies = self.jar.get({ url: self.uri.href }) | ||
} else { | ||
// fetch cookie from the global cookie jar | ||
var cookies = cookieJar.get({ url: self.uri.href }) | ||
} | ||
if (cookies) { | ||
var cookieString = cookies.map(function (c) { | ||
return c.name + "=" + c.value; | ||
}).join("; "); | ||
self.headers.Cookie = cookieString; | ||
} | ||
if (!self.uri.pathname) {self.uri.pathname = '/'} | ||
@@ -192,4 +178,4 @@ if (!self.uri.port) { | ||
var clientErrorHandler = function (error) { | ||
if (setHost) delete self.headers.host | ||
self.clientErrorHandler = function (error) { | ||
if (self.setHost) delete self.headers.host | ||
if (self.req._reusedSocket && error.code === 'ECONNRESET') { | ||
@@ -201,3 +187,6 @@ self.agent = {addRequest: ForeverAgent.prototype.addRequestNoreuse.bind(self.agent)} | ||
} | ||
if (self.timeout && self.timeoutTimer) clearTimeout(self.timeoutTimer) | ||
if (self.timeout && self.timeoutTimer) { | ||
clearTimeout(self.timeoutTimer); | ||
self.timeoutTimer = null; | ||
} | ||
self.emit('error', error) | ||
@@ -208,47 +197,8 @@ } | ||
if (self.form) { | ||
self.headers['content-type'] = 'application/x-www-form-urlencoded; charset=utf-8' | ||
self.body = qs.stringify(self.form).toString('utf8') | ||
if (options.form) { | ||
self.form(options.form) | ||
} | ||
if (self.oauth) { | ||
var form | ||
if (self.headers['content-type'] && | ||
self.headers['content-type'].slice(0, 'application/x-www-form-urlencoded'.length) === | ||
'application/x-www-form-urlencoded' | ||
) { | ||
form = qs.parse(self.body) | ||
} | ||
if (self.uri.query) { | ||
form = qs.parse(self.uri.query) | ||
} | ||
if (!form) form = {} | ||
var oa = {} | ||
for (var i in form) oa[i] = form[i] | ||
for (var i in self.oauth) oa['oauth_'+i] = self.oauth[i] | ||
if (!oa.oauth_version) oa.oauth_version = '1.0' | ||
if (!oa.oauth_timestamp) oa.oauth_timestamp = Math.floor( (new Date()).getTime() / 1000 ).toString() | ||
if (!oa.oauth_nonce) oa.oauth_nonce = uuid().replace(/-/g, '') | ||
oa.oauth_signature_method = 'HMAC-SHA1' | ||
var consumer_secret = oa.oauth_consumer_secret | ||
delete oa.oauth_consumer_secret | ||
var token_secret = oa.oauth_token_secret | ||
delete oa.oauth_token_secret | ||
var baseurl = self.uri.protocol + '//' + self.uri.host + self.uri.pathname | ||
var signature = oauth.hmacsign(self.method, baseurl, oa, consumer_secret, token_secret) | ||
// oa.oauth_signature = signature | ||
for (var i in form) { | ||
if ( i.slice(0, 'oauth_') in self.oauth) { | ||
// skip | ||
} else { | ||
delete oa['oauth_'+i] | ||
} | ||
} | ||
self.headers.authorization = | ||
'OAuth '+Object.keys(oa).sort().map(function (i) {return i+'="'+oauth.rfc3986(oa[i])+'"'}).join(',') | ||
self.headers.authorization += ',oauth_signature="'+oauth.rfc3986(signature)+'"' | ||
if (options.oauth) { | ||
self.oauth(options.oauth) | ||
} | ||
@@ -263,2 +213,4 @@ | ||
if (options.qs) self.qs(options.qs) | ||
if (self.uri.path) { | ||
@@ -274,35 +226,6 @@ self.path = self.uri.path | ||
if (self.json) { | ||
self.headers['content-type'] = 'application/json' | ||
if (typeof self.json === 'boolean') { | ||
if (typeof self.body === 'object') self.body = JSON.stringify(self.body) | ||
} else { | ||
self.body = JSON.stringify(self.json) | ||
} | ||
} else if (self.multipart) { | ||
self.body = [] | ||
if (!self.headers['content-type']) { | ||
self.headers['content-type'] = 'multipart/related;boundary="frontier"'; | ||
} else { | ||
self.headers['content-type'] = self.headers['content-type'].split(';')[0] + ';boundary="frontier"'; | ||
} | ||
if (!self.multipart.forEach) throw new Error('Argument error, options.multipart.') | ||
self.multipart.forEach(function (part) { | ||
var body = part.body | ||
if(!body) throw Error('Body attribute missing in multipart.') | ||
delete part.body | ||
var preamble = '--frontier\r\n' | ||
Object.keys(part).forEach(function(key){ | ||
preamble += key + ': ' + part[key] + '\r\n' | ||
}) | ||
preamble += '\r\n' | ||
self.body.push(new Buffer(preamble)) | ||
self.body.push(new Buffer(body)) | ||
self.body.push(new Buffer('\r\n')) | ||
}) | ||
self.body.push(new Buffer('--frontier--')) | ||
if (options.json) { | ||
self.json(options.json) | ||
} else if (options.multipart) { | ||
self.multipart(options.multipart) | ||
} | ||
@@ -354,158 +277,2 @@ | ||
self.start = function () { | ||
self._started = true | ||
self.method = self.method || 'GET' | ||
self.href = self.uri.href | ||
if (log) log('%method %href', self) | ||
self.req = self.httpModule.request(self, function (response) { | ||
self.response = response | ||
response.request = self | ||
if (self.httpModule === https && | ||
self.strictSSL && | ||
!response.client.authorized) { | ||
var sslErr = response.client.authorizationError | ||
self.emit('error', new Error('SSL Error: '+ sslErr)) | ||
return | ||
} | ||
if (setHost) delete self.headers.host | ||
if (self.timeout && self.timeoutTimer) clearTimeout(self.timeoutTimer) | ||
if (response.headers['set-cookie'] && (!self._disableCookies)) { | ||
response.headers['set-cookie'].forEach(function(cookie) { | ||
if (self.jar) self.jar.add(new Cookie(cookie)) | ||
else cookieJar.add(new Cookie(cookie)) | ||
}) | ||
} | ||
if (response.statusCode >= 300 && | ||
response.statusCode < 400 && | ||
self.followRedirect && | ||
self.method !== 'PUT' && | ||
self.method !== 'POST' && | ||
response.headers.location) { | ||
if (self._redirectsFollowed >= self.maxRedirects) { | ||
self.emit('error', new Error("Exceeded maxRedirects. Probably stuck in a redirect loop.")) | ||
return | ||
} | ||
self._redirectsFollowed += 1 | ||
if (!isUrl.test(response.headers.location)) { | ||
response.headers.location = url.resolve(self.uri.href, response.headers.location) | ||
} | ||
self.uri = response.headers.location | ||
self.redirects.push( | ||
{ statusCode : response.statusCode | ||
, redirectUri: response.headers.location | ||
} | ||
) | ||
delete self.req | ||
delete self.agent | ||
delete self._started | ||
if (self.headers) { | ||
delete self.headers.host | ||
} | ||
if (log) log('Redirect to %uri', self) | ||
request(self, self.callback) | ||
return // Ignore the rest of the response | ||
} else { | ||
self._redirectsFollowed = self._redirectsFollowed || 0 | ||
// Be a good stream and emit end when the response is finished. | ||
// Hack to emit end on close because of a core bug that never fires end | ||
response.on('close', function () { | ||
if (!self._ended) self.response.emit('end') | ||
}) | ||
if (self.encoding) { | ||
if (self.dests.length !== 0) { | ||
console.error("Ingoring encoding parameter as this stream is being piped to another stream which makes the encoding option invalid.") | ||
} else { | ||
response.setEncoding(self.encoding) | ||
} | ||
} | ||
self.pipeDest = function (dest) { | ||
if (dest.headers) { | ||
dest.headers['content-type'] = response.headers['content-type'] | ||
if (response.headers['content-length']) { | ||
dest.headers['content-length'] = response.headers['content-length'] | ||
} | ||
} | ||
if (dest.setHeader) { | ||
for (var i in response.headers) { | ||
dest.setHeader(i, response.headers[i]) | ||
} | ||
dest.statusCode = response.statusCode | ||
} | ||
if (self.pipefilter) self.pipefilter(response, dest) | ||
} | ||
self.dests.forEach(function (dest) { | ||
self.pipeDest(dest) | ||
}) | ||
response.on("data", function (chunk) { | ||
self._destdata = true | ||
self.emit("data", chunk) | ||
}) | ||
response.on("end", function (chunk) { | ||
self._ended = true | ||
self.emit("end", chunk) | ||
}) | ||
response.on("close", function () {self.emit("close")}) | ||
self.emit('response', response) | ||
if (self.onResponse) { | ||
self.onResponse(null, response) | ||
} | ||
if (self.callback) { | ||
var buffer = [] | ||
var bodyLen = 0 | ||
self.on("data", function (chunk) { | ||
buffer.push(chunk) | ||
bodyLen += chunk.length | ||
}) | ||
self.on("end", function () { | ||
if (buffer.length && Buffer.isBuffer(buffer[0])) { | ||
var body = new Buffer(bodyLen) | ||
var i = 0 | ||
buffer.forEach(function (chunk) { | ||
chunk.copy(body, i, 0, chunk.length) | ||
i += chunk.length | ||
}) | ||
if (self.encoding === null) { | ||
response.body = body | ||
} else { | ||
response.body = body.toString() | ||
} | ||
} else if (buffer.length) { | ||
response.body = buffer.join('') | ||
} | ||
if (self.json) { | ||
try { | ||
response.body = JSON.parse(response.body) | ||
} catch (e) {} | ||
} | ||
self.callback(null, response, response.body) | ||
}) | ||
} | ||
} | ||
}) | ||
if (self.timeout && !self.timeoutTimer) { | ||
self.timeoutTimer = setTimeout(function() { | ||
self.req.abort() | ||
var e = new Error("ETIMEDOUT") | ||
e.code = "ETIMEDOUT" | ||
self.emit("error", e) | ||
}, self.timeout) | ||
} | ||
self.req.on('error', clientErrorHandler) | ||
} | ||
self.once('pipe', function (src) { | ||
@@ -555,3 +322,329 @@ if (self.ntick) throw new Error("You cannot pipe to this stream after the first nextTick() after creation of the request stream.") | ||
} | ||
Request.prototype.pipe = function (dest) { | ||
util.inherits(Request, stream.Stream) | ||
Request.prototype.getAgent = function (host, port) { | ||
if (!this.pool[host+':'+port]) { | ||
this.pool[host+':'+port] = new this.httpModule.Agent({host:host, port:port}) | ||
} | ||
return this.pool[host+':'+port] | ||
} | ||
Request.prototype.start = function () { | ||
var self = this | ||
self._started = true | ||
self.method = self.method || 'GET' | ||
self.href = self.uri.href | ||
if (log) log('%method %href', self) | ||
self.req = self.httpModule.request(self, function (response) { | ||
self.response = response | ||
response.request = self | ||
if (self.httpModule === https && | ||
self.strictSSL && | ||
!response.client.authorized) { | ||
var sslErr = response.client.authorizationError | ||
self.emit('error', new Error('SSL Error: '+ sslErr)) | ||
return | ||
} | ||
if (self.setHost) delete self.headers.host | ||
if (self.timeout && self.timeoutTimer) { | ||
clearTimeout(self.timeoutTimer); | ||
self.timeoutTimer = null; | ||
} | ||
if (response.headers['set-cookie'] && (!self._disableCookies)) { | ||
response.headers['set-cookie'].forEach(function(cookie) { | ||
if (self._jar) self._jar.add(new Cookie(cookie)) | ||
else cookieJar.add(new Cookie(cookie)) | ||
}) | ||
} | ||
if (response.statusCode >= 300 && response.statusCode < 400 && | ||
(self.followAllRedirects || | ||
(self.followRedirect && (self.method !== 'PUT' && self.method !== 'POST'))) && | ||
response.headers.location) { | ||
if (self._redirectsFollowed >= self.maxRedirects) { | ||
self.emit('error', new Error("Exceeded maxRedirects. Probably stuck in a redirect loop.")) | ||
return | ||
} | ||
self._redirectsFollowed += 1 | ||
if (!isUrl.test(response.headers.location)) { | ||
response.headers.location = url.resolve(self.uri.href, response.headers.location) | ||
} | ||
self.uri = response.headers.location | ||
self.redirects.push( | ||
{ statusCode : response.statusCode | ||
, redirectUri: response.headers.location | ||
} | ||
) | ||
self.method = 'GET'; // Force all redirects to use GET | ||
delete self.req | ||
delete self.agent | ||
delete self._started | ||
if (self.headers) { | ||
delete self.headers.host | ||
} | ||
if (log) log('Redirect to %uri', self) | ||
request(self, self.callback) | ||
return // Ignore the rest of the response | ||
} else { | ||
self._redirectsFollowed = self._redirectsFollowed || 0 | ||
// Be a good stream and emit end when the response is finished. | ||
// Hack to emit end on close because of a core bug that never fires end | ||
response.on('close', function () { | ||
if (!self._ended) self.response.emit('end') | ||
}) | ||
if (self.encoding) { | ||
if (self.dests.length !== 0) { | ||
console.error("Ingoring encoding parameter as this stream is being piped to another stream which makes the encoding option invalid.") | ||
} else { | ||
response.setEncoding(self.encoding) | ||
} | ||
} | ||
self.dests.forEach(function (dest) { | ||
self.pipeDest(dest) | ||
}) | ||
response.on("data", function (chunk) { | ||
self._destdata = true | ||
self.emit("data", chunk) | ||
}) | ||
response.on("end", function (chunk) { | ||
self._ended = true | ||
self.emit("end", chunk) | ||
}) | ||
response.on("close", function () {self.emit("close")}) | ||
self.emit('response', response) | ||
if (self.onResponse) { | ||
self.onResponse(null, response) | ||
} | ||
if (self.callback) { | ||
var buffer = [] | ||
var bodyLen = 0 | ||
self.on("data", function (chunk) { | ||
buffer.push(chunk) | ||
bodyLen += chunk.length | ||
}) | ||
self.on("end", function () { | ||
if (buffer.length && Buffer.isBuffer(buffer[0])) { | ||
var body = new Buffer(bodyLen) | ||
var i = 0 | ||
buffer.forEach(function (chunk) { | ||
chunk.copy(body, i, 0, chunk.length) | ||
i += chunk.length | ||
}) | ||
if (self.encoding === null) { | ||
response.body = body | ||
} else { | ||
response.body = body.toString() | ||
} | ||
} else if (buffer.length) { | ||
response.body = buffer.join('') | ||
} | ||
if (self.json) { | ||
try { | ||
response.body = JSON.parse(response.body) | ||
} catch (e) {} | ||
} | ||
self.callback(null, response, response.body) | ||
}) | ||
} | ||
} | ||
}) | ||
if (self.timeout && !self.timeoutTimer) { | ||
self.timeoutTimer = setTimeout(function() { | ||
self.req.abort() | ||
var e = new Error("ETIMEDOUT") | ||
e.code = "ETIMEDOUT" | ||
self.emit("error", e) | ||
}, self.timeout) | ||
// Set additional timeout on socket - in case if remote | ||
// server freeze after sending headers | ||
self.req.setTimeout(self.timeout, function(){ | ||
if (self.req) { | ||
self.req.abort() | ||
var e = new Error("ESOCKETTIMEDOUT") | ||
e.code = "ESOCKETTIMEDOUT" | ||
self.emit("error", e) | ||
} | ||
}); | ||
} | ||
self.req.on('error', self.clientErrorHandler) | ||
self.emit('request', self.req) | ||
} | ||
Request.prototype.pipeDest = function (dest) { | ||
var response = this.response | ||
// Called after the response is received | ||
if (dest.headers) { | ||
dest.headers['content-type'] = response.headers['content-type'] | ||
if (response.headers['content-length']) { | ||
dest.headers['content-length'] = response.headers['content-length'] | ||
} | ||
} | ||
if (dest.setHeader) { | ||
for (var i in response.headers) { | ||
dest.setHeader(i, response.headers[i]) | ||
} | ||
dest.statusCode = response.statusCode | ||
} | ||
if (this.pipefilter) this.pipefilter(response, dest) | ||
} | ||
// Composable API | ||
Request.prototype.setHeader = function (name, value, clobber) { | ||
if (clobber === undefined) clobber = true | ||
if (clobber || !this.headers.hasOwnProperty(name)) this.headers[name] = value | ||
else this.headers[name] += ',' + value | ||
return this | ||
} | ||
Request.prototype.setHeaders = function (headers) { | ||
for (i in headers) {this.setHeader(i, headers[i])} | ||
return this | ||
} | ||
Request.prototype.qs = function (q, clobber) { | ||
var uri = { | ||
protocol: this.uri.protocol, | ||
host: this.uri.host, | ||
pathname: this.uri.pathname, | ||
query: clobber ? q : qs.parse(this.uri.query), | ||
hash: this.uri.hash | ||
}; | ||
if (!clobber) for (var i in q) uri.query[i] = q[i] | ||
this.uri= url.parse(url.format(uri)) | ||
return this | ||
} | ||
Request.prototype.form = function (form) { | ||
this.headers['content-type'] = 'application/x-www-form-urlencoded; charset=utf-8' | ||
this.body = qs.stringify(form).toString('utf8') | ||
return this | ||
} | ||
Request.prototype.multipart = function (multipart) { | ||
var self = this | ||
self.body = [] | ||
if (!self.headers['content-type']) { | ||
self.headers['content-type'] = 'multipart/related;boundary="frontier"'; | ||
} else { | ||
self.headers['content-type'] = self.headers['content-type'].split(';')[0] + ';boundary="frontier"'; | ||
} | ||
if (!multipart.forEach) throw new Error('Argument error, options.multipart.') | ||
multipart.forEach(function (part) { | ||
var body = part.body | ||
if(!body) throw Error('Body attribute missing in multipart.') | ||
delete part.body | ||
var preamble = '--frontier\r\n' | ||
Object.keys(part).forEach(function(key){ | ||
preamble += key + ': ' + part[key] + '\r\n' | ||
}) | ||
preamble += '\r\n' | ||
self.body.push(new Buffer(preamble)) | ||
self.body.push(new Buffer(body)) | ||
self.body.push(new Buffer('\r\n')) | ||
}) | ||
self.body.push(new Buffer('--frontier--')) | ||
return self | ||
} | ||
Request.prototype.json = function (val) { | ||
this.setHeader('content-type', 'application/json') | ||
if (typeof val === 'boolean') { | ||
if (typeof this.body === 'object') this.body = JSON.stringify(this.body) | ||
} else { | ||
this.body = JSON.stringify(val) | ||
} | ||
return this | ||
} | ||
Request.prototype.oauth = function (_oauth) { | ||
var form | ||
if (this.headers['content-type'] && | ||
this.headers['content-type'].slice(0, 'application/x-www-form-urlencoded'.length) === | ||
'application/x-www-form-urlencoded' | ||
) { | ||
form = qs.parse(this.body) | ||
} | ||
if (this.uri.query) { | ||
form = qs.parse(this.uri.query) | ||
} | ||
if (!form) form = {} | ||
var oa = {} | ||
for (var i in form) oa[i] = form[i] | ||
for (var i in _oauth) oa['oauth_'+i] = _oauth[i] | ||
if (!oa.oauth_version) oa.oauth_version = '1.0' | ||
if (!oa.oauth_timestamp) oa.oauth_timestamp = Math.floor( (new Date()).getTime() / 1000 ).toString() | ||
if (!oa.oauth_nonce) oa.oauth_nonce = uuid().replace(/-/g, '') | ||
oa.oauth_signature_method = 'HMAC-SHA1' | ||
var consumer_secret = oa.oauth_consumer_secret | ||
delete oa.oauth_consumer_secret | ||
var token_secret = oa.oauth_token_secret | ||
delete oa.oauth_token_secret | ||
var baseurl = this.uri.protocol + '//' + this.uri.host + this.uri.pathname | ||
var signature = oauth.hmacsign(this.method, baseurl, oa, consumer_secret, token_secret) | ||
// oa.oauth_signature = signature | ||
for (var i in form) { | ||
if ( i.slice(0, 'oauth_') in _oauth) { | ||
// skip | ||
} else { | ||
delete oa['oauth_'+i] | ||
} | ||
} | ||
this.headers.authorization = | ||
'OAuth '+Object.keys(oa).sort().map(function (i) {return i+'="'+oauth.rfc3986(oa[i])+'"'}).join(',') | ||
this.headers.authorization += ',oauth_signature="'+oauth.rfc3986(signature)+'"' | ||
return this | ||
} | ||
Request.prototype.jar = function (jar) { | ||
var cookies | ||
if (this._redirectsFollowed === 0) { | ||
this.originalCookieHeader = this.headers.cookie | ||
} | ||
if (jar === false) { | ||
// disable cookies | ||
cookies = false; | ||
this._disableCookies = true; | ||
} else if (jar) { | ||
// fetch cookie from the user defined cookie jar | ||
cookies = jar.get({ url: this.uri.href }) | ||
} else { | ||
// fetch cookie from the global cookie jar | ||
cookies = cookieJar.get({ url: this.uri.href }) | ||
} | ||
if (cookies && cookies.length) { | ||
var cookieString = cookies.map(function (c) { | ||
return c.name + "=" + c.value | ||
}).join("; ") | ||
if (this.originalCookieHeader) { | ||
// Don't overwrite existing Cookie header | ||
this.headers.cookie = this.originalCookieHeader + '; ' + cookieString | ||
} else { | ||
this.headers.cookie = cookieString | ||
} | ||
} | ||
this._jar = jar | ||
return this | ||
} | ||
// Stream API | ||
Request.prototype.pipe = function (dest, opts) { | ||
if (this.response) { | ||
@@ -563,3 +656,3 @@ if (this._destdata) { | ||
} else { | ||
stream.Stream.prototype.pipe.call(this, dest) | ||
stream.Stream.prototype.pipe.call(this, dest, opts) | ||
this.pipeDest(dest) | ||
@@ -570,3 +663,3 @@ return dest | ||
this.dests.push(dest) | ||
stream.Stream.prototype.pipe.call(this, dest) | ||
stream.Stream.prototype.pipe.call(this, dest, opts) | ||
return dest | ||
@@ -580,6 +673,7 @@ } | ||
} | ||
Request.prototype.end = function () { | ||
Request.prototype.end = function (chunk) { | ||
if (chunk) this.write(chunk) | ||
if (!this._started) this.start() | ||
if (!this.req) throw new Error("This request has been piped before http.request() was called.") | ||
this.req.end.apply(this.req, arguments) | ||
this.req.end() | ||
} | ||
@@ -594,8 +688,32 @@ Request.prototype.pause = function () { | ||
} | ||
Request.prototype.destroy = function () { | ||
if (!this._ended) this.end() | ||
} | ||
function request (options, callback) { | ||
if (typeof options === 'string') options = {uri:options} | ||
if (callback) options.callback = callback | ||
// organize params for post, put, head, del | ||
function initParams(uri, options, callback) { | ||
if ((typeof options === 'function') && !callback) callback = options; | ||
if (typeof options === 'object') { | ||
options.uri = uri; | ||
} else if (typeof uri === 'string') { | ||
options = {uri:uri}; | ||
} else { | ||
options = uri; | ||
uri = options.uri; | ||
} | ||
return { uri: uri, options: options, callback: callback }; | ||
} | ||
function request (uri, options, callback) { | ||
if ((typeof options === 'function') && !callback) callback = options; | ||
if (typeof options === 'object') { | ||
options.uri = uri; | ||
} else if (typeof uri === 'string') { | ||
options = {uri:uri}; | ||
} else { | ||
options = uri; | ||
} | ||
if (callback) options.callback = callback; | ||
var r = new Request(options) | ||
r.request() | ||
return r | ||
@@ -608,8 +726,8 @@ } | ||
var def = function (method) { | ||
var d = function (opts, callback) { | ||
if (typeof opts === 'string') opts = {uri:opts} | ||
var d = function (uri, opts, callback) { | ||
var params = initParams(uri, opts, callback); | ||
for (var i in options) { | ||
if (opts[i] === undefined) opts[i] = options[i] | ||
if (params.options[i] === undefined) params.options[i] = options[i] | ||
} | ||
return method(opts, callback) | ||
return method(params.uri, params.options, params.callback) | ||
} | ||
@@ -641,24 +759,24 @@ return d | ||
request.get = request | ||
request.post = function (options, callback) { | ||
if (typeof options === 'string') options = {uri:options} | ||
options.method = 'POST' | ||
return request(options, callback) | ||
request.post = function (uri, options, callback) { | ||
var params = initParams(uri, options, callback); | ||
params.options.method = 'POST'; | ||
return request(params.uri, params.options, params.callback) | ||
} | ||
request.put = function (options, callback) { | ||
if (typeof options === 'string') options = {uri:options} | ||
options.method = 'PUT' | ||
return request(options, callback) | ||
request.put = function (uri, options, callback) { | ||
var params = initParams(uri, options, callback); | ||
params.options.method = 'PUT' | ||
return request(params.uri, params.options, params.callback) | ||
} | ||
request.head = function (options, callback) { | ||
if (typeof options === 'string') options = {uri:options} | ||
options.method = 'HEAD' | ||
request.head = function (uri, options, callback) { | ||
var params = initParams(uri, options, callback); | ||
params.options.method = 'HEAD' | ||
if (options.body || options.requestBodyStream || options.json || options.multipart) { | ||
throw new Error("HTTP HEAD requests MUST NOT include a request body.") | ||
} | ||
return request(options, callback) | ||
return request(params.uri, params.options, params.callback) | ||
} | ||
request.del = function (options, callback) { | ||
if (typeof options === 'string') options = {uri:options} | ||
options.method = 'DELETE' | ||
return request(options, callback) | ||
request.del = function (uri, options, callback) { | ||
var params = initParams(uri, options, callback); | ||
params.options.method = 'DELETE' | ||
return request(params.uri, params.options, params.callback) | ||
} | ||
@@ -669,4 +787,5 @@ request.jar = function () { | ||
request.cookie = function (str) { | ||
if (str && str.uri) str = str.uri | ||
if (typeof str !== 'string') throw new Error("The cookie function only accepts STRING as param") | ||
return new Cookie(str) | ||
} |
// from http://github.com/felixge/node-paperboy | ||
exports.types = { | ||
"3gp":"video/3gpp", | ||
"aiff":"audio/x-aiff", | ||
@@ -53,2 +54,3 @@ "arj":"application/x-arj-compressed", | ||
"m3u":"audio/x-mpegurl", | ||
"m4v":"video/mp4", | ||
"man":"application/x-troff-man", | ||
@@ -59,8 +61,11 @@ "me":"application/x-troff-me", | ||
"mime":"www/mime", | ||
"mkv":" video/x-matrosk", | ||
"movie":"video/x-sgi-movie", | ||
"mustache":"text/plain", | ||
"mp4":"video/mp4", | ||
"mp41":"video/mp4", | ||
"mp42":"video/mp4", | ||
"mpg":"video/mpeg", | ||
"mpga":"audio/mpeg", | ||
"ms":"application/x-troff-ms", | ||
"mustache":"text/plain", | ||
"nc":"application/x-netcdf", | ||
@@ -128,2 +133,3 @@ "oda":"application/oda", | ||
"wax":"audio/x-ms-wax", | ||
"webm":"video/webm", | ||
"wma":"audio/x-ms-wma", | ||
@@ -140,3 +146,3 @@ "wmv":"video/x-ms-wmv", | ||
"xyz":"chemical/x-pdb", | ||
"zip":"application/zip", | ||
"zip":"application/zip" | ||
}; | ||
@@ -143,0 +149,0 @@ |
@@ -22,3 +22,3 @@ var crypto = require('crypto') | ||
var base = | ||
httpMethod + "&" + | ||
(httpMethod || 'GET') + "&" + | ||
encodeURIComponent( base_uri ) + "&" + | ||
@@ -25,0 +25,0 @@ Object.keys(params).sort().map(function (i) { |
{ "name" : "request" | ||
, "description" : "Simplified HTTP request client." | ||
, "tags" : ["http", "simple", "util", "utility"] | ||
, "version" : "2.9.100" | ||
, "version" : "2.9.150" | ||
, "author" : "Mikeal Rogers <mikeal.rogers@gmail.com>" | ||
@@ -14,3 +14,3 @@ , "repository" : | ||
, "main" : "./main" | ||
, "scripts": { "test": "bash tests/run.sh" } | ||
, "scripts": { "test": "node tests/run.js" } | ||
} |
@@ -41,3 +41,3 @@ # Request -- Simplified HTTP request method | ||
```javascript | ||
fs.readStream('file.json').pipe(request.put('http://mysite.com/obj.json')) | ||
fs.createReadStream('file.json').pipe(request.put('http://mysite.com/obj.json')) | ||
``` | ||
@@ -150,2 +150,3 @@ | ||
* `uri` || `url` - fully qualified uri or a parsed url object from url.parse() | ||
* `qs` - object containing querystring values to be appended to the uri | ||
* `method` - http method, defaults to GET | ||
@@ -158,2 +159,3 @@ * `headers` - http headers, defaults to {} | ||
* `followRedirect` - follow HTTP 3xx responses as redirects. defaults to true. | ||
* `followAllRedirects` - follow non-GET HTTP 3xx responses as redirects. defaults to false. | ||
* `maxRedirects` - the maximum number of redirects to follow, defaults to 10. | ||
@@ -160,0 +162,0 @@ * `onResponse` - If true the callback will be fired on the "response" event instead of "end". If a function it will be called on "response" and not effect the regular semantics of the main callback on "end". |
@@ -30,2 +30,9 @@ var server = require('./server') | ||
try { | ||
request(local, {multipart: [{}]}) | ||
assert.fail("Should have throw") | ||
} catch(e) { | ||
assert.equal(e.message, 'Body attribute missing in multipart.') | ||
} | ||
console.log("All tests passed.") |
@@ -63,6 +63,6 @@ var http = require('http') | ||
function run_tests(httpModules) { | ||
var to_https = {'httpModules':httpModules, 'uri':'http://localhost:'+plain_server.port+'/to_https'} | ||
var to_plain = {'httpModules':httpModules, 'uri':'https://localhost:'+https_server.port+'/to_plain'} | ||
var to_https = 'http://localhost:'+plain_server.port+'/to_https' | ||
var to_plain = 'https://localhost:'+https_server.port+'/to_plain' | ||
request(to_https, function (er, res, body) { | ||
request(to_https, {'httpModules':httpModules}, function (er, res, body) { | ||
assert.ok(!er, 'Bounce to SSL worked') | ||
@@ -73,3 +73,3 @@ assert.equal(body, 'https', 'Received HTTPS server body') | ||
request(to_plain, function (er, res, body) { | ||
request(to_plain, {'httpModules':httpModules}, function (er, res, body) { | ||
assert.ok(!er, 'Bounce to plaintext server worked') | ||
@@ -76,0 +76,0 @@ assert.equal(body, 'plain', 'Received HTTPS server body') |
@@ -182,2 +182,22 @@ var server = require('./server') | ||
// Test pipe options | ||
s.once('/opts', server.createGetResponse('opts response')); | ||
var optsStream = new stream.Stream(); | ||
optsStream.writable = true | ||
var optsData = ''; | ||
optsStream.write = function (buf) { | ||
optsData += buf; | ||
if (optsData === 'opts response') { | ||
setTimeout(check, 10); | ||
} | ||
} | ||
optsStream.end = function () { | ||
assert.fail('end called') | ||
}; | ||
counter++ | ||
request({url:'http://localhost:3453/opts'}).pipe(optsStream, { end : false }) | ||
}) |
var server = require('./server') | ||
, assert = require('assert') | ||
, request = require('../main.js') | ||
, Cookie = require('../vendor/cookie') | ||
, Jar = require('../vendor/cookie/jar') | ||
@@ -26,2 +28,10 @@ var s = server.createServer() | ||
s.on('/'+landing, function (req, res) { | ||
if (req.method !== 'GET') { // We should only accept GET redirects | ||
console.error("Got a non-GET request to the redirect destination URL"); | ||
resp.writeHead(400); | ||
resp.end(); | ||
return; | ||
} | ||
// Make sure the cookie doesn't get included twice, see #139: | ||
assert.equal(req.headers.cookie, 'foo=bar; quux=baz'); | ||
hits[landing] = true; | ||
@@ -34,3 +44,5 @@ res.writeHead(200) | ||
// Permanent bounce | ||
request(server+'/perm', function (er, res, body) { | ||
var jar = new Jar() | ||
jar.add(new Cookie('quux=baz')) | ||
request({uri: server+'/perm', jar: jar, headers: {cookie: 'foo=bar'}}, function (er, res, body) { | ||
try { | ||
@@ -47,3 +59,3 @@ assert.ok(hits.perm, 'Original request is to /perm') | ||
// Temporary bounce | ||
request(server+'/temp', function (er, res, body) { | ||
request({uri: server+'/temp', jar: jar, headers: {cookie: 'foo=bar'}}, function (er, res, body) { | ||
try { | ||
@@ -60,3 +72,3 @@ assert.ok(hits.temp, 'Original request is to /temp') | ||
// Prevent bouncing. | ||
request({uri:server+'/nope', followRedirect:false}, function (er, res, body) { | ||
request({uri:server+'/nope', jar: jar, headers: {cookie: 'foo=bar'}, followRedirect:false}, function (er, res, body) { | ||
try { | ||
@@ -72,6 +84,41 @@ assert.ok(hits.nope, 'Original request to /nope') | ||
// Should not follow post redirects by default | ||
request.post(server+'/temp', { jar: jar, headers: {cookie: 'foo=bar'}}, function (er, res, body) { | ||
try { | ||
assert.ok(hits.temp, 'Original request is to /temp') | ||
assert.ok(!hits.temp_landing, 'No chasing the redirect when post') | ||
assert.equal(res.statusCode, 301, 'Response is the bounce itself') | ||
passed += 1 | ||
} finally { | ||
done() | ||
} | ||
}) | ||
// Should follow post redirects when followAllRedirects true | ||
request.post({uri:server+'/temp', followAllRedirects:true, jar: jar, headers: {cookie: 'foo=bar'}}, function (er, res, body) { | ||
try { | ||
assert.ok(hits.temp, 'Original request is to /temp') | ||
assert.ok(hits.temp_landing, 'Forward to temporary landing URL') | ||
assert.equal(body, 'temp_landing', 'Got temporary landing content') | ||
passed += 1 | ||
} finally { | ||
done() | ||
} | ||
}) | ||
request.post({uri:server+'/temp', followAllRedirects:false, jar: jar, headers: {cookie: 'foo=bar'}}, function (er, res, body) { | ||
try { | ||
assert.ok(hits.temp, 'Original request is to /temp') | ||
assert.ok(!hits.temp_landing, 'No chasing the redirect') | ||
assert.equal(res.statusCode, 301, 'Response is the bounce itself') | ||
passed += 1 | ||
} finally { | ||
done() | ||
} | ||
}) | ||
var reqs_done = 0; | ||
function done() { | ||
reqs_done += 1; | ||
if(reqs_done == 3) { | ||
if(reqs_done == 6) { | ||
console.log(passed + ' tests passed.') | ||
@@ -78,0 +125,0 @@ s.close() |
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
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance 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
130717
30
2244
289
10