diff options
author | isaacs <i@izs.me> | 2012-07-07 01:05:16 +0400 |
---|---|---|
committer | isaacs <i@izs.me> | 2012-07-07 01:05:16 +0400 |
commit | a18e1237cf917a5c60b6a6fdc39c189b3e319bde (patch) | |
tree | 8bf6a390499fecc7a2423ca46d7795241fd7004d | |
parent | a8d986e72842690350098c6527c074113f4bd8bf (diff) |
Update request to 2.9.203
-rw-r--r-- | node_modules/request/README.md | 2 | ||||
-rw-r--r-- | node_modules/request/aws.js | 190 | ||||
-rw-r--r-- | node_modules/request/aws2.js | 128 | ||||
-rw-r--r-- | node_modules/request/main.js | 107 | ||||
-rw-r--r-- | node_modules/request/oauth.js | 4 | ||||
-rw-r--r-- | node_modules/request/package.json | 23 | ||||
-rw-r--r-- | node_modules/request/tests/run.js | 1 | ||||
-rw-r--r-- | node_modules/request/tests/test-body.js | 17 | ||||
-rw-r--r-- | node_modules/request/tests/test-pool.js | 16 | ||||
-rw-r--r-- | node_modules/request/tests/test-s3.js | 13 | ||||
-rw-r--r-- | node_modules/request/tests/test-toJSON.js | 2 |
11 files changed, 442 insertions, 61 deletions
diff --git a/node_modules/request/README.md b/node_modules/request/README.md index 639d1a45a..8713a807c 100644 --- a/node_modules/request/README.md +++ b/node_modules/request/README.md @@ -16,7 +16,7 @@ Or from source: ## Super simple to use -Request is designed to be the simplest way possible to make http calls. It support HTTPS and follows redirects by default. +Request is designed to be the simplest way possible to make http calls. It supports HTTPS and follows redirects by default. ```javascript var request = require('request'); diff --git a/node_modules/request/aws.js b/node_modules/request/aws.js new file mode 100644 index 000000000..4e87bff49 --- /dev/null +++ b/node_modules/request/aws.js @@ -0,0 +1,190 @@ + +/*! + * knox - auth + * Copyright(c) 2010 LearnBoost <dev@learnboost.com> + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var crypto = require('crypto') + , parse = require('url').parse; + +/** + * Valid keys. + */ + +var keys = [ + 'acl' + , 'location' + , 'logging' + , 'notification' + , 'partNumber' + , 'policy' + , 'requestPayment' + , 'torrent' + , 'uploadId' + , 'uploads' + , 'versionId' + , 'versioning' + , 'versions' + , 'website' +]; + +/** + * Return an "Authorization" header value with the given `options` + * in the form of "AWS <key>:<signature>" + * + * @param {Object} options + * @return {String} + * @api private + */ + +exports.authorization = function(options){ + return 'AWS ' + options.key + ':' + exports.sign(options); +}; + +/** + * Simple HMAC-SHA1 Wrapper + * + * @param {Object} options + * @return {String} + * @api private + */ + +exports.hmacSha1 = function(options){ + return crypto.createHmac('sha1', options.secret).update(options.message).digest('base64'); +}; + +/** + * Create a base64 sha1 HMAC for `options`. + * + * @param {Object} options + * @return {String} + * @api private + */ + +exports.sign = function(options){ + options.message = exports.stringToSign(options); + return exports.hmacSha1(options); +}; + +/** + * Create a base64 sha1 HMAC for `options`. + * + * Specifically to be used with S3 presigned URLs + * + * @param {Object} options + * @return {String} + * @api private + */ + +exports.signQuery = function(options){ + options.message = exports.queryStringToSign(options); + return exports.hmacSha1(options); +}; + +/** + * Return a string for sign() with the given `options`. + * + * Spec: + * + * <verb>\n + * <md5>\n + * <content-type>\n + * <date>\n + * [headers\n] + * <resource> + * + * @param {Object} options + * @return {String} + * @api private + */ + +exports.stringToSign = function(options){ + var headers = options.amazonHeaders || ''; + if (headers) headers += '\n'; + return [ + options.verb + , options.md5 + , options.contentType + , options.date.toUTCString() + , headers + options.resource + ].join('\n'); +}; + +/** + * Return a string for sign() with the given `options`, but is meant exclusively + * for S3 presigned URLs + * + * Spec: + * + * <date>\n + * <resource> + * + * @param {Object} options + * @return {String} + * @api private + */ + +exports.queryStringToSign = function(options){ + return 'GET\n\n\n' + + options.date + '\n' + + options.resource; +}; + +/** + * Perform the following: + * + * - ignore non-amazon headers + * - lowercase fields + * - sort lexicographically + * - trim whitespace between ":" + * - join with newline + * + * @param {Object} headers + * @return {String} + * @api private + */ + +exports.canonicalizeHeaders = function(headers){ + var buf = [] + , fields = Object.keys(headers); + for (var i = 0, len = fields.length; i < len; ++i) { + var field = fields[i] + , val = headers[field] + , field = field.toLowerCase(); + if (0 !== field.indexOf('x-amz')) continue; + buf.push(field + ':' + val); + } + return buf.sort().join('\n'); +}; + +/** + * Perform the following: + * + * - ignore non sub-resources + * - sort lexicographically + * + * @param {String} resource + * @return {String} + * @api private + */ + +exports.canonicalizeResource = function(resource){ + var url = parse(resource, true) + , path = url.pathname + , buf = []; + + Object.keys(url.query).forEach(function(key){ + if (!~keys.indexOf(key)) return; + var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key]); + buf.push(key + val); + }); + + return path + (buf.length + ? '?' + buf.sort().join('&') + : ''); +}; diff --git a/node_modules/request/aws2.js b/node_modules/request/aws2.js new file mode 100644 index 000000000..eb683f765 --- /dev/null +++ b/node_modules/request/aws2.js @@ -0,0 +1,128 @@ +var crypto = require('crypto') + +// The Authentication Header +// +// The Amazon S3 REST API uses the standard HTTPAuthorization header to pass authentication information. (The name of the standard header is unfortunate because it carries authentication information, not authorization).Under the Amazon S3 authentication scheme, the Authorization header has the following form. +// +// Authorization: AWS AWSAccessKeyId:Signature +// +// Developers are issued an AWS Access Key ID and AWS SecretAccess Key when they register. For request authentication, theAWSAccessKeyId element identifies the secret key that was used to compute the signature, and (indirectly) the developer making the request. +// +// The Signature element is the RFC 2104HMAC-SHA1 of selected elements from the request, and so theSignature part of the Authorization header will vary from request to request. If the request signature calculated by the system matches theSignature included with the request, then the requester will have demonstrated possession to the AWSSecret Access Key. The request will then be processed under the identity, and with the authority, of the developer to whom the key was issued. +// +// Following is pseudo-grammar that illustrates the construction of the Authorization request header (\nmeans the Unicode code point U+000A commonly called newline). + +function authorizationHeader (accessKey) { + // Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature; + + var authorization = 'AWS' + " " + accessKey + ":" + signature() + + return authorization +} + +// + +function signature (secret, verb, md5, contenttype, date, amzheaders, bucket, path) { + // Signature = Base64( HMAC-SHA1( UTF-8-Encoding-Of( YourSecretAccessKeyID, StringToSign ) ) ); + + function encodeSignature (stringToSign) { + return crypto.createHash('sha1').update(stringToSign).digest('base64') + } + + // + // StringToSign = HTTP-Verb + "\n" + + // Content-MD5 + "\n" + + // Content-Type + "\n" + + // Date + "\n" + + // CanonicalizedAmzHeaders + + // CanonicalizedResource; + + function compileStringToSign () { + var s = + verb + '\n' + (md5 || '') + '\n' + (contenttype || '') + '\n' + date.toUTCString() + '\n' + canonicalizeAmzHeaders(amzheaders) + + canonicalizeResource() + return s + } + + // + // CanonicalizedResource = [ "/" + Bucket ] + + // <HTTP-Request-URI, from the protocol name up to the query string> + + // [ sub-resource, if present. For example "?acl", "?location", "?logging", or "?torrent"]; + + function canonicalizeResource () { + return '/' + bucket + path + } + + // + // CanonicalizedAmzHeaders = <described below> + // + // HMAC-SHA1 is an algorithm defined by RFC 2104 (go to RFC 2104 - Keyed-Hashing for Message Authentication ). The algorithm takes as input two byte-strings: a key and a message. For Amazon S3 Request authentication, use your AWS Secret Access Key (YourSecretAccessKeyID) as the key, and the UTF-8 encoding of the StringToSign as the message. The output of HMAC-SHA1 is also a byte string, called the digest. The Signature request parameter is constructed by Base64 encoding this digest. + // Request Canonicalization for Signing + // + // Recall that when the system receives an authenticated request, it compares the computed request signature with the signature provided in the request in StringToSign. For that reason, you must compute the signature using the same method used by Amazon S3. We call the process of putting a request in an agreed-upon form for signing "canonicalization". + +} + + + +// Constructing the CanonicalizedResource Element +// +// CanonicalizedResource represents the Amazon S3 resource targeted by the request. Construct it for a REST request as follows: +// +// Launch Process +// +// 1 +// +// +// Start with the empty string (""). +// +// 2 +// +// +// If the request specifies a bucket using the HTTP Host header (virtual hosted-style), append the bucket name preceded by a "/" (e.g., "/bucketname"). For path-style requests and requests that don't address a bucket, do nothing. For more information on virtual hosted-style requests, see Virtual Hosting of Buckets. +// +// 3 +// +// +// Append the path part of the un-decoded HTTP Request-URI, up-to but not including the query string. +// +// 4 +// +// +// If the request addresses a sub-resource, like ?versioning, ?location, ?acl, ?torrent, ?lifecycle, or ?versionid append the sub-resource, its value if it has one, and the question mark. Note that in case of multiple sub-resources, sub-resources must be lexicographically sorted by sub-resource name and separated by '&'. e.g. ?acl&versionId=value. +// +// The list of sub-resources that must be included when constructing the CanonicalizedResource Element are: acl, lifecycle, location, logging, notification, partNumber, policy, requestPayment, torrent, uploadId, uploads, versionId, versioning, versions and website. +// +// If the request specifies query string parameters overriding the response header values (see Get Object), append the query string parameters, and its values. When signing you do not encode these values. However, when making the request, you must encode these parameter values. The query string parameters in a GET request include response-content-type, response-content-language, response-expires, response-cache-control, response-content-disposition, response-content-encoding. +// +// The delete query string parameter must be including when creating the CanonicalizedResource for a Multi-Object Delete request. +// +// Elements of the CanonicalizedResource that come from the HTTP Request-URI should be signed literally as they appear in the HTTP request, including URL-Encoding meta characters. +// +// The CanonicalizedResource might be different than the HTTP Request-URI. In particular, if your request uses the HTTP Host header to specify a bucket, the bucket does appear in the HTTP Request-URI. However, the CanonicalizedResource continues to include the bucket. Query string parameters might also appear in the Request-URI but are not included in CanonicalizedResource. For more information, see Virtual Hosting of Buckets. +// Constructing the CanonicalizedAmzHeaders Element +// +// To construct the CanonicalizedAmzHeaders part of StringToSign, select all HTTP request headers that start with 'x-amz-' (using a case-insensitive comparison) and use the following process. +// +// CanonicalizedAmzHeaders Process +// 1 Convert each HTTP header name to lower-case. For example, 'X-Amz-Date' becomes 'x-amz-date'. +// 2 Sort the collection of headers lexicographically by header name. +// 3 Combine header fields with the same name into one "header-name:comma-separated-value-list" pair as prescribed by RFC 2616, section 4.2, without any white-space between values. For example, the two metadata headers 'x-amz-meta-username: fred' and 'x-amz-meta-username: barney' would be combined into the single header 'x-amz-meta-username: fred,barney'. +// 4 "Unfold" long headers that span multiple lines (as allowed by RFC 2616, section 4.2) by replacing the folding white-space (including new-line) by a single space. +// 5 Trim any white-space around the colon in the header. For example, the header 'x-amz-meta-username: fred,barney' would become 'x-amz-meta-username:fred,barney' +// 6 Finally, append a new-line (U+000A) to each canonicalized header in the resulting list. Construct the CanonicalizedResource element by concatenating all headers in this list into a single string. +// +// Positional versus Named HTTP Header StringToSign Elements +// +// The first few header elements of StringToSign (Content-Type, Date, and Content-MD5) are positional in nature. StringToSign does not include the names of these headers, only their values from the request. In contrast, the 'x-amz-' elements are named; Both the header names and the header values appear in StringToSign. +// +// If a positional header called for in the definition of StringToSign is not present in your request, (Content-Type or Content-MD5, for example, are optional for PUT requests, and meaningless for GET requests), substitute the empty string ("") in for that position. +// Time Stamp Requirement +// +// A valid time stamp (using either the HTTP Date header or an x-amz-date alternative) is mandatory for authenticated requests. Furthermore, the client time-stamp included with an authenticated request must be within 15 minutes of the Amazon S3 system time when the request is received. If not, the request will fail with the RequestTimeTooSkewed error status code. The intention of these restrictions is to limit the possibility that intercepted requests could be replayed by an adversary. For stronger protection against eavesdropping, use the HTTPS transport for authenticated requests. +// +// Some HTTP client libraries do not expose the ability to set the Date header for a request. If you have trouble including the value of the 'Date' header in the canonicalized headers, you can set the time-stamp for the request using an 'x-amz-date' header instead. The value of the x-amz-date header must be in one of the RFC 2616 formats (http://www.ietf.org/rfc/rfc2616.txt). When an x-amz-date header is present in a request, the system will ignore any Date header when computing the request signature. Therefore, if you include the x-amz-date header, use the empty string for the Date when constructing the StringToSign. See the next section for an example. diff --git a/node_modules/request/main.js b/node_modules/request/main.js index d734b0858..2407a9349 100644 --- a/node_modules/request/main.js +++ b/node_modules/request/main.js @@ -27,6 +27,7 @@ var http = require('http') , CookieJar = require('./vendor/cookie/jar') , cookieJar = new CookieJar , tunnel = require('./tunnel') + , aws = require('./aws') ; if (process.logging) { @@ -51,8 +52,8 @@ if (https && !https.Agent) { http.Agent.call(this, options) } util.inherits(https.Agent, http.Agent) - https.Agent.prototype._getConnection = function(host, port, cb) { - var s = tls.connect(port, host, this.options, function() { + https.Agent.prototype._getConnection = function (host, port, cb) { + var s = tls.connect(port, host, this.options, function () { // do other checks here? if (cb) cb() }) @@ -107,7 +108,7 @@ Request.prototype.init = function (options) { if (!options) options = {} - if (!self.pool) self.pool = globalPool + if (!self.pool && self.pool !== false) self.pool = globalPool self.dests = [] self.__isRequestRequest = true @@ -153,6 +154,21 @@ Request.prototype.init = function (options) { } } + if (!self.uri.host || !self.uri.pathname) { + // Invalid URI: it may generate lot of bad errors, like "TypeError: Cannot call method 'indexOf' of undefined" in CookieJar + // Detect and reject it as soon as possible + var faultyUri = url.format(self.uri) + var message = 'Invalid URI "' + faultyUri + '"' + if (Object.keys(options).length === 0) { + // No option ? This can be the sign of a redirect + // As this is a case where the user cannot do anything (he didn't call request directly with this URL) + // he should be warned that it can be caused by a redirection (can save some hair) + message += '. This can be caused by a crappy redirection.' + } + self.emit('error', new Error(message)) + return // This error was fatal + } + self._redirectsFollowed = self._redirectsFollowed || 0 self.maxRedirects = (self.maxRedirects !== undefined) ? self.maxRedirects : 10 self.followRedirect = (self.followRedirect !== undefined) ? self.followRedirect : true @@ -214,6 +230,10 @@ Request.prototype.init = function (options) { if (options.oauth) { self.oauth(options.oauth) } + + if (options.aws) { + self.aws(options.aws) + } if (self.uri.auth && !self.headers.authorization) { self.headers.authorization = "Basic " + toBase64(self.uri.auth.split(':').map(function(item){ return qs.unescape(item)}).join(':')) @@ -237,6 +257,7 @@ Request.prototype.init = function (options) { if (options.json) { self.json(options.json) } else if (options.multipart) { + self.boundary = uuid() self.multipart(options.multipart) } @@ -326,7 +347,7 @@ Request.prototype.init = function (options) { if (self.body) { if (Array.isArray(self.body)) { - self.body.forEach(function(part) { + self.body.forEach(function (part) { self.write(part) }) } else { @@ -337,8 +358,10 @@ Request.prototype.init = function (options) { console.warn("options.requestBodyStream is deprecated, please pass the request object to stream.pipe.") self.requestBodyStream.pipe(self) } else if (!self.src) { - self.headers['content-length'] = 0 - self.end() + if (self.method !== 'GET' && typeof self.method !== 'undefined') { + self.headers['content-length'] = 0; + } + self.end(); } self.ntick = true }) @@ -394,6 +417,14 @@ Request.prototype.start = function () { self.method = self.method || 'GET' self.href = self.uri.href if (log) log('%method %href', self) + + if (self.src && self.src.stat && self.src.stat.size) { + self.headers['content-length'] = self.src.stat.size + } + if (self._aws) { + self.aws(self._aws, true) + } + self.req = self.httpModule.request(self, function (response) { if (self._aborted) return if (self._paused) response.pause() @@ -416,11 +447,14 @@ Request.prototype.start = function () { self.timeoutTimer = null } + var addCookie = function (cookie) { + if (self._jar) self._jar.add(new Cookie(cookie)) + else cookieJar.add(new Cookie(cookie)) + } + 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 (Array.isArray(response.headers['set-cookie'])) response.headers['set-cookie'].forEach(addCookie) + else addCookie(response.headers['set-cookie']) } if (response.statusCode >= 300 && response.statusCode < 400 && @@ -525,7 +559,7 @@ Request.prototype.start = function () { }) if (self.timeout && !self.timeoutTimer) { - self.timeoutTimer = setTimeout(function() { + self.timeoutTimer = setTimeout(function () { self.req.abort() var e = new Error("ETIMEDOUT") e.code = "ETIMEDOUT" @@ -535,7 +569,7 @@ Request.prototype.start = function () { // Set additional timeout on socket - in case if remote // server freeze after sending headers if (self.req.setTimeout) { // only works on node 0.6+ - self.req.setTimeout(self.timeout, function(){ + self.req.setTimeout(self.timeout, function () { if (self.req) { self.req.abort() var e = new Error("ESOCKETTIMEDOUT") @@ -547,11 +581,14 @@ Request.prototype.start = function () { } self.req.on('error', self.clientErrorHandler) + self.req.on('drain', function() { + self.emit('drain') + }) self.emit('request', self.req) } -Request.prototype.abort = function() { +Request.prototype.abort = function () { this._aborted = true; if (this.req) { @@ -590,7 +627,7 @@ Request.prototype.setHeader = function (name, value, clobber) { return this } Request.prototype.setHeaders = function (headers) { - for (i in headers) {this.setHeader(i, headers[i])} + for (var i in headers) {this.setHeader(i, headers[i])} return this } Request.prototype.qs = function (q, clobber) { @@ -617,19 +654,21 @@ Request.prototype.multipart = function (multipart) { self.body = [] if (!self.headers['content-type']) { - self.headers['content-type'] = 'multipart/related; boundary=frontier'; + self.headers['content-type'] = 'multipart/related; boundary=' + self.boundary; } else { - self.headers['content-type'] = self.headers['content-type'].split(';')[0] + '; boundary=frontier'; + self.headers['content-type'] = self.headers['content-type'].split(';')[0] + '; boundary=' + self.boundary; } + console.log('boundary >> ' + self.boundary) + 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.') + if(body == null) throw Error('Body attribute missing in multipart.') delete part.body - var preamble = '--frontier\r\n' - Object.keys(part).forEach(function(key){ + var preamble = '--' + self.boundary + '\r\n' + Object.keys(part).forEach(function (key) { preamble += key + ': ' + part[key] + '\r\n' }) preamble += '\r\n' @@ -637,7 +676,7 @@ Request.prototype.multipart = function (multipart) { self.body.push(new Buffer(body)) self.body.push(new Buffer('\r\n')) }) - self.body.push(new Buffer('--frontier--')) + self.body.push(new Buffer('--' + self.boundary + '--')) return self } Request.prototype.json = function (val) { @@ -651,6 +690,28 @@ Request.prototype.json = function (val) { } return this } +Request.prototype.aws = function (opts, now) { + if (!now) { + this._aws = opts + return this + } + var date = new Date() + this.setHeader('date', date.toUTCString()) + this.setHeader('authorization', aws.authorization( + { key: opts.key + , secret: opts.secret + , verb: this.method + , date: date + , resource: aws.canonicalizeResource('/' + opts.bucket + this.path) + , contentType: this.headers['content-type'] || '' + , md5: this.headers['content-md5'] || '' + , amazonHeaders: aws.canonicalizeHeaders(this.headers) + } + )) + + return this +} + Request.prototype.oauth = function (_oauth) { var form if (this.headers['content-type'] && @@ -749,7 +810,7 @@ Request.prototype.pipe = function (dest, opts) { } Request.prototype.write = function () { if (!this._started) this.start() - this.req.write.apply(this.req, arguments) + return this.req.write.apply(this.req, arguments) } Request.prototype.end = function (chunk) { if (chunk) this.write(chunk) @@ -771,7 +832,7 @@ Request.prototype.destroy = function () { // organize params for post, put, head, del function initParams(uri, options, callback) { if ((typeof options === 'function') && !callback) callback = options; - if (typeof options === 'object') { + if (options && typeof options === 'object') { options.uri = uri; } else if (typeof uri === 'string') { options = {uri:uri}; @@ -785,7 +846,7 @@ function initParams(uri, options, callback) { function request (uri, options, callback) { if (typeof uri === 'undefined') throw new Error('undefined is not a valid uri or options object.') if ((typeof options === 'function') && !callback) callback = options; - if (typeof options === 'object') { + if (options && typeof options === 'object') { options.uri = uri; } else if (typeof uri === 'string') { options = {uri:uri}; diff --git a/node_modules/request/oauth.js b/node_modules/request/oauth.js index f6abae33c..ebde3fd26 100644 --- a/node_modules/request/oauth.js +++ b/node_modules/request/oauth.js @@ -25,8 +25,8 @@ function hmacsign (httpMethod, base_uri, params, consumer_secret, token_secret, // big WTF here with the escape + encoding but it's what twitter wants return escape(rfc3986(i)) + "%3D" + escape(rfc3986(params[i])) }).join("%26") - var key = consumer_secret + '&' - if (token_secret) key += token_secret + var key = encodeURIComponent(consumer_secret) + '&' + if (token_secret) key += encodeURIComponent(token_secret) return sha1(key, base) } diff --git a/node_modules/request/package.json b/node_modules/request/package.json index 1fe21b1e7..1f093f449 100644 --- a/node_modules/request/package.json +++ b/node_modules/request/package.json @@ -7,14 +7,14 @@ "util", "utility" ], - "version": "2.9.202", + "version": "2.9.203", "author": { "name": "Mikeal Rogers", "email": "mikeal.rogers@gmail.com" }, "repository": { "type": "git", - "url": "git://github.com/mikeal/request.git" + "url": "http://github.com/mikeal/request.git" }, "bugs": { "url": "http://github.com/mikeal/request/issues" @@ -26,20 +26,7 @@ "scripts": { "test": "node tests/run.js" }, - "_npmUser": { - "name": "isaacs", - "email": "i@izs.me" - }, - "_id": "request@2.9.202", - "dependencies": {}, - "devDependencies": {}, - "optionalDependencies": {}, - "_engineSupported": true, - "_npmVersion": "1.1.24", - "_nodeVersion": "v0.7.10-pre", - "_defaultsLoaded": true, - "dist": { - "shasum": "f762430e0080df88bd7917330acb00d1c1b3481d" - }, - "_from": "request@2.9.202" + "readme": "# Request -- Simplified HTTP request method\n\n## Install\n\n<pre>\n npm install request\n</pre>\n\nOr from source:\n\n<pre>\n git clone git://github.com/mikeal/request.git \n cd request\n npm link\n</pre>\n\n## Super simple to use\n\nRequest is designed to be the simplest way possible to make http calls. It supports HTTPS and follows redirects by default.\n\n```javascript\nvar request = require('request');\nrequest('http://www.google.com', function (error, response, body) {\n if (!error && response.statusCode == 200) {\n console.log(body) // Print the google web page.\n }\n})\n```\n\n## Streaming\n\nYou can stream any response to a file stream.\n\n```javascript\nrequest('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))\n```\n\nYou can also stream a file to a PUT or POST request. This method will also check the file extension against a mapping of file extensions to content-types, in this case `application/json`, and use the proper content-type in the PUT request if one is not already provided in the headers.\n\n```javascript\nfs.createReadStream('file.json').pipe(request.put('http://mysite.com/obj.json'))\n```\n\nRequest can also pipe to itself. When doing so the content-type and content-length will be preserved in the PUT headers.\n\n```javascript\nrequest.get('http://google.com/img.png').pipe(request.put('http://mysite.com/img.png'))\n```\n\nNow let's get fancy.\n\n```javascript\nhttp.createServer(function (req, resp) {\n if (req.url === '/doodle.png') {\n if (req.method === 'PUT') {\n req.pipe(request.put('http://mysite.com/doodle.png'))\n } else if (req.method === 'GET' || req.method === 'HEAD') {\n request.get('http://mysite.com/doodle.png').pipe(resp)\n } \n }\n})\n```\n\nYou can also pipe() from a http.ServerRequest instance and to a http.ServerResponse instance. The HTTP method and headers will be sent as well as the entity-body data. Which means that, if you don't really care about security, you can do:\n\n```javascript\nhttp.createServer(function (req, resp) {\n if (req.url === '/doodle.png') {\n var x = request('http://mysite.com/doodle.png')\n req.pipe(x)\n x.pipe(resp)\n }\n})\n```\n\nAnd since pipe() returns the destination stream in node 0.5.x you can do one line proxying :)\n\n```javascript\nreq.pipe(request('http://mysite.com/doodle.png')).pipe(resp)\n```\n\nAlso, none of this new functionality conflicts with requests previous features, it just expands them.\n\n```javascript\nvar r = request.defaults({'proxy':'http://localproxy.com'})\n\nhttp.createServer(function (req, resp) {\n if (req.url === '/doodle.png') {\n r.get('http://google.com/doodle.png').pipe(resp)\n }\n})\n```\n\nYou can still use intermediate proxies, the requests will still follow HTTP forwards, etc.\n\n## OAuth Signing\n\n```javascript\n// Twitter OAuth\nvar qs = require('querystring')\n , oauth =\n { callback: 'http://mysite.com/callback/'\n , consumer_key: CONSUMER_KEY\n , consumer_secret: CONSUMER_SECRET\n }\n , url = 'https://api.twitter.com/oauth/request_token'\n ;\nrequest.post({url:url, oauth:oauth}, function (e, r, body) {\n // Assume by some stretch of magic you aquired the verifier\n var access_token = qs.parse(body)\n , oauth = \n { consumer_key: CONSUMER_KEY\n , consumer_secret: CONSUMER_SECRET\n , token: access_token.oauth_token\n , verifier: VERIFIER\n , token_secret: access_token.oauth_token_secret\n }\n , url = 'https://api.twitter.com/oauth/access_token'\n ;\n request.post({url:url, oauth:oauth}, function (e, r, body) {\n var perm_token = qs.parse(body)\n , oauth = \n { consumer_key: CONSUMER_KEY\n , consumer_secret: CONSUMER_SECRET\n , token: perm_token.oauth_token\n , token_secret: perm_token.oauth_token_secret\n }\n , url = 'https://api.twitter.com/1/users/show.json?'\n , params = \n { screen_name: perm_token.screen_name\n , user_id: perm_token.user_id\n }\n ;\n url += qs.stringify(params)\n request.get({url:url, oauth:oauth, json:true}, function (e, r, user) {\n console.log(user)\n })\n })\n})\n```\n\n\n\n### request(options, callback)\n\nThe first argument can be either a url or an options object. The only required option is uri, all others are optional.\n\n* `uri` || `url` - fully qualified uri or a parsed url object from url.parse()\n* `qs` - object containing querystring values to be appended to the uri\n* `method` - http method, defaults to GET\n* `headers` - http headers, defaults to {}\n* `body` - entity body for POST and PUT requests. Must be buffer or string.\n* `form` - sets `body` but to querystring representation of value and adds `Content-type: application/x-www-form-urlencoded; charset=utf-8` header.\n* `json` - sets `body` but to JSON representation of value and adds `Content-type: application/json` header.\n* `multipart` - (experimental) array of objects which contains their own headers and `body` attribute. Sends `multipart/related` request. See example below.\n* `followRedirect` - follow HTTP 3xx responses as redirects. defaults to true.\n* `followAllRedirects` - follow non-GET HTTP 3xx responses as redirects. defaults to false.\n* `maxRedirects` - the maximum number of redirects to follow, defaults to 10.\n* `encoding` - Encoding to be used on `setEncoding` of response data. If set to `null`, the body is returned as a Buffer.\n* `pool` - A hash object containing the agents for these requests. If omitted this request will use the global pool which is set to node's default maxSockets.\n* `pool.maxSockets` - Integer containing the maximum amount of sockets in the pool.\n* `timeout` - Integer containing the number of milliseconds to wait for a request to respond before aborting the request\t\n* `proxy` - An HTTP proxy to be used. Support proxy Auth with Basic Auth the same way it's supported with the `url` parameter by embedding the auth info in the uri.\n* `oauth` - Options for OAuth HMAC-SHA1 signing, see documentation above.\n* `strictSSL` - Set to `true` to require that SSL certificates be valid. Note: to use your own certificate authority, you need to specify an agent that was created with that ca as an option.\n* `jar` - Set to `false` if you don't want cookies to be remembered for future use or define your custom cookie jar (see examples section)\n\n\nThe callback argument gets 3 arguments. The first is an error when applicable (usually from the http.Client option not the http.ClientRequest object). The second in an http.ClientResponse object. The third is the response body String or Buffer.\n\n## Convenience methods\n\nThere are also shorthand methods for different HTTP METHODs and some other conveniences.\n\n### request.defaults(options) \n \nThis method returns a wrapper around the normal request API that defaults to whatever options you pass in to it.\n\n### request.put\n\nSame as request() but defaults to `method: \"PUT\"`.\n\n```javascript\nrequest.put(url)\n```\n\n### request.post\n\nSame as request() but defaults to `method: \"POST\"`.\n\n```javascript\nrequest.post(url)\n```\n\n### request.head\n\nSame as request() but defaults to `method: \"HEAD\"`.\n\n```javascript\nrequest.head(url)\n```\n\n### request.del\n\nSame as request() but defaults to `method: \"DELETE\"`.\n\n```javascript\nrequest.del(url)\n```\n\n### request.get\n\nAlias to normal request method for uniformity.\n\n```javascript\nrequest.get(url)\n```\n### request.cookie\n\nFunction that creates a new cookie.\n\n```javascript\nrequest.cookie('cookie_string_here')\n```\n### request.jar\n\nFunction that creates a new cookie jar.\n\n```javascript\nrequest.jar()\n```\n\n\n## Examples:\n\n```javascript\n var request = require('request')\n , rand = Math.floor(Math.random()*100000000).toString()\n ;\n request(\n { method: 'PUT'\n , uri: 'http://mikeal.iriscouch.com/testjs/' + rand\n , multipart: \n [ { 'content-type': 'application/json'\n , body: JSON.stringify({foo: 'bar', _attachments: {'message.txt': {follows: true, length: 18, 'content_type': 'text/plain' }}})\n }\n , { body: 'I am an attachment' }\n ] \n }\n , function (error, response, body) {\n if(response.statusCode == 201){\n console.log('document saved as: http://mikeal.iriscouch.com/testjs/'+ rand)\n } else {\n console.log('error: '+ response.statusCode)\n console.log(body)\n }\n }\n )\n```\nCookies are enabled by default (so they can be used in subsequent requests). To disable cookies set jar to false (either in defaults or in the options sent).\n\n```javascript\nvar request = request.defaults({jar: false})\nrequest('http://www.google.com', function () {\n request('http://images.google.com')\n})\n```\n\nIf you to use a custom cookie jar (instead of letting request use its own global cookie jar) you do so by setting the jar default or by specifying it as an option:\n\n```javascript\nvar j = request.jar()\nvar request = request.defaults({jar:j})\nrequest('http://www.google.com', function () {\n request('http://images.google.com')\n})\n```\nOR\n\n```javascript\nvar j = request.jar()\nvar cookie = request.cookie('your_cookie_here')\nj.add(cookie)\nrequest({url: 'http://www.google.com', jar: j}, function () {\n request('http://images.google.com')\n})\n```\n", + "_id": "request@2.9.203", + "_from": "request@~2.9" } diff --git a/node_modules/request/tests/run.js b/node_modules/request/tests/run.js index 205fc3ae5..f3a30d354 100644 --- a/node_modules/request/tests/run.js +++ b/node_modules/request/tests/run.js @@ -14,6 +14,7 @@ var tests = [ , 'test-https-strict.js' , 'test-oauth.js' , 'test-pipes.js' + , 'test-pool.js' , 'test-proxy.js' , 'test-qs.js' , 'test-redirect.js' diff --git a/node_modules/request/tests/test-body.js b/node_modules/request/tests/test-body.js index 9d2e18851..e3fc75d97 100644 --- a/node_modules/request/tests/test-body.js +++ b/node_modules/request/tests/test-body.js @@ -50,22 +50,7 @@ var tests = , method: "PUT" , json: {foo: 'bar'} } - , testPutMultipart : - { resp: server.createPostValidator( - '--frontier\r\n' + - 'content-type: text/html\r\n' + - '\r\n' + - '<html><body>Oh hi.</body></html>' + - '\r\n--frontier\r\n\r\n' + - 'Oh hi.' + - '\r\n--frontier--' - ) - , method: "PUT" - , multipart: - [ {'content-type': 'text/html', 'body': '<html><body>Oh hi.</body></html>'} - , {'body': 'Oh hi.'} - ] - } + } s.listen(s.port, function () { diff --git a/node_modules/request/tests/test-pool.js b/node_modules/request/tests/test-pool.js new file mode 100644 index 000000000..1e7d5786a --- /dev/null +++ b/node_modules/request/tests/test-pool.js @@ -0,0 +1,16 @@ +var request = require('../main') + , http = require('http') + , assert = require('assert') + ; + +var s = http.createServer(function (req, resp) { + resp.statusCode = 200; + resp.end('asdf'); +}).listen(8080, function () { + request({'url': 'http://localhost:8080', 'pool': false}, function (e, resp) { + var agent = resp.request.agent; + assert.strictEqual(typeof agent, 'boolean'); + assert.strictEqual(agent, false); + s.close(); + }); +});
\ No newline at end of file diff --git a/node_modules/request/tests/test-s3.js b/node_modules/request/tests/test-s3.js new file mode 100644 index 000000000..5f59c4ad0 --- /dev/null +++ b/node_modules/request/tests/test-s3.js @@ -0,0 +1,13 @@ +var request = require('../main') + +var r = request.get('https://log.curlybracecast.com.s3.amazonaws.com/', + { aws: + { key: 'AKIAI6KIQRRVMGK3WK5Q' + , secret: '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' + , bucket: 'log.curlybracecast.com' + } + }, function (e, resp, body) { + console.log(r.headers) + console.log(body) + } +)
\ No newline at end of file diff --git a/node_modules/request/tests/test-toJSON.js b/node_modules/request/tests/test-toJSON.js index c81dfb568..b7c67effc 100644 --- a/node_modules/request/tests/test-toJSON.js +++ b/node_modules/request/tests/test-toJSON.js @@ -8,7 +8,7 @@ var s = http.createServer(function (req, resp) { resp.end('asdf') }).listen(8080, function () { var r = request('http://localhost:8080', function (e, resp) { - assert(JSON.parse(JSON.stringify(r)).response.statusCode, 200) + assert.equal(JSON.parse(JSON.stringify(r)).response.statusCode, 200) s.close() }) })
\ No newline at end of file |