From a37135daa728d25046823f06909f47255e833dda Mon Sep 17 00:00:00 2001 From: Edmund von der Burg Date: Thu, 17 May 2012 15:15:04 +0200 Subject: [PATCH 01/49] Correct README to specify 'delete' instead of 'del' for 'method' option. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a98b844..4e2f92f 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ All of these attempt to turn the response into a JavaScript object. In order to ### Options -* `method` Request method, can be get, post, put, del. Defaults to `"get"`. +* `method` Request method, can be get, post, put, delete. Defaults to `"get"`. * `query` Query string variables as a javascript object, will override the querystring in the URL. Defaults to empty. * `data` The data to be added to the body of the request. Can be a string or any object. Note that if you want your request body to be JSON with the `Content-Type: application/json`, you need to From da1f3dab859d9fe66dfb568abae0ebc3bc9efed5 Mon Sep 17 00:00:00 2001 From: Ben Kittrell Date: Fri, 18 May 2012 11:20:10 -0500 Subject: [PATCH 02/49] Added HTTP Code 307 (Temp redirect) to list of redirect codes --- lib/restler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/restler.js b/lib/restler.js index bf6cc57..fcdaa27 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -92,7 +92,7 @@ Request.prototype = new process.EventEmitter(); mixin(Request.prototype, { _isRedirect: function(response) { - return ([301, 302, 303].indexOf(response.statusCode) >= 0); + return ([301, 302, 303, 307].indexOf(response.statusCode) >= 0); }, _fullPath: function() { var path = this.url.pathname || '/'; From 8a2ca18a8e942cd8dd85046bf7bb1a0ddf4cc1f9 Mon Sep 17 00:00:00 2001 From: Macrauder Date: Wed, 13 Mar 2013 20:39:06 +0100 Subject: [PATCH 03/49] Changed EventEmitter inheritens to Node0.10 style. --- lib/restler.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/restler.js b/lib/restler.js index 2664233..fda78fc 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -1,4 +1,5 @@ -var sys = require('util'); +var util = require('util'); +var events = require("events"); var http = require('http'); var https = require('https'); var url = require('url'); @@ -25,6 +26,7 @@ function mixin(target, source) { } function Request(uri, options) { + events.EventEmitter.call(this); this.url = url.parse(uri); this.options = options; this.headers = { @@ -88,7 +90,7 @@ function Request(uri, options) { this._makeRequest(); } -Request.prototype = new process.EventEmitter(); +util.inherits(Request, events.EventEmitter); mixin(Request.prototype, { _isRedirect: function(response) { @@ -302,7 +304,7 @@ function request(url, options) { var request = new Request(url, options); request.on('error', function() {}); process.nextTick(request.run.bind(request)); - return request; + return request; } function get(url, options) { From fcbed667853d23046aea367c483d203bd8d4810e Mon Sep 17 00:00:00 2001 From: Matt Loar Date: Sat, 1 Jun 2013 21:46:29 -0700 Subject: [PATCH 04/49] Fix Data object support. --- lib/multipartform.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/multipartform.js b/lib/multipartform.js index e917676..f72eb06 100644 --- a/lib/multipartform.js +++ b/lib/multipartform.js @@ -68,7 +68,7 @@ Part.prototype = { header = "Content-Disposition: form-data; name=\"" + this.name + "\"; filename=\"" + this.value.filename + "\"\r\n" + "Content-Type: " + this.value.contentType; - } if (this.value instanceof File) { + } else if (this.value instanceof File) { header = "Content-Disposition: form-data; name=\"" + this.name + "\"; filename=\"" + this.value.filename + "\"\r\n" + "Content-Length: " + this.value.fileSize + "\r\n" + @@ -127,6 +127,9 @@ Part.prototype = { }); })(); // reader() }); + } else if (this.value instanceof Data) { + stream.write(this.value.data + "\r\n"); + callback(); } else { stream.write(this.value + "\r\n"); callback(); From 85d7862a82e8e9d59434c3098cbe5629e1a85603 Mon Sep 17 00:00:00 2001 From: Matt Loar Date: Sat, 1 Jun 2013 22:36:17 -0700 Subject: [PATCH 05/49] Add Content-Length and properly handle Buffers. --- lib/multipartform.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/multipartform.js b/lib/multipartform.js index f72eb06..7196724 100644 --- a/lib/multipartform.js +++ b/lib/multipartform.js @@ -67,6 +67,7 @@ Part.prototype = { if (this.value.data) { header = "Content-Disposition: form-data; name=\"" + this.name + "\"; filename=\"" + this.value.filename + "\"\r\n" + + "Content-Length: " + this.value.data.length + "\r\n" + "Content-Type: " + this.value.contentType; } else if (this.value instanceof File) { header = "Content-Disposition: form-data; name=\"" + this.name + @@ -128,7 +129,8 @@ Part.prototype = { })(); // reader() }); } else if (this.value instanceof Data) { - stream.write(this.value.data + "\r\n"); + stream.write(this.value.data); + stream.write("\r\n"); callback(); } else { stream.write(this.value + "\r\n"); From 954774efa5ec41ff5eec36d159eb7b1925d58c45 Mon Sep 17 00:00:00 2001 From: Jason Pincin Date: Sun, 30 Jun 2013 01:14:09 -0400 Subject: [PATCH 06/49] Added support for auth without password Including Authorization header if an empty password (not undefined) is specified to handle the case where an api key is passed via username but no password is required (for example, asana.com) --- lib/restler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/restler.js b/lib/restler.js index 2664233..9b66059 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -109,7 +109,7 @@ mixin(Request.prototype, { this.options.password = authParts[1]; } - if (this.options.username && this.options.password) { + if (this.options.username && this.options.password !== undefined) { var b = new Buffer([this.options.username, this.options.password].join(':')); this.headers['Authorization'] = "Basic " + b.toString('base64'); } From d60b988c0e9e36c92266b57d6e8247789f8b77e7 Mon Sep 17 00:00:00 2001 From: Tomas Aparicio Date: Sat, 31 Aug 2013 16:35:39 +0200 Subject: [PATCH 07/49] Added missing documentation for PATCH HTTP method --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index a98b844..c0d5c2e 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,10 @@ Create a DELETE request. Create a HEAD request. +### patch(url, options) + +Create a PATCH request. + ### json(url, data, options) Send json `data` via GET method. From e2b0fc60cdae65e723f98229b2bfba1a68dfd4ba Mon Sep 17 00:00:00 2001 From: Bhasker Kode Date: Wed, 4 Sep 2013 20:16:18 +0530 Subject: [PATCH 08/49] timeout event, and timeout option implemented. added docs & example --- README.md | 8 ++++++++ lib/restler.js | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/README.md b/README.md index a98b844..9ec0bb8 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Basic method to make a request of any type. The function returns a RestRequest o * `fail: function(data, response)` - emitted when the request was successful, but 4xx status code returned. Gets passed the response data and the response object as arguments. * `error: function(err, response)` - emitted when some errors have occurred (eg. connection aborted, parse, encoding, decoding failed or some other unhandled errors). Gets passed the `Error` object and the response object (when available) as arguments. * `abort: function()` - emitted when `request.abort()` is called. +* `timeout: function(ms)` - when a request takes more than the timeout option eg: {timeout:5000}, the request will be aborted. error and abort events will not be called, instead timeout will be emitted. * `2XX`, `3XX`, `4XX`, `5XX: function(data, response)` - emitted for all requests with response codes in the range (eg. `2XX` emitted for 200, 201, 203). * actual response code: function(data, response) - emitted for every single response code (eg. 404, 201, etc). @@ -113,6 +114,7 @@ Also you can use `json()` and `postJson()` methods. * `multipart` If set the data passed will be formated as `multipart/form-encoded`. See multipart example below. Defaults to `false`. * `client` A http.Client instance if you want to reuse or implement some kind of connection pooling. Defaults to empty. * `followRedirects` If set will recursively follow redirects. Defaults to `true`. +* `timeout` If set, will emit the timeout event when the response does not return within the said value (in ms) Example usage @@ -139,6 +141,12 @@ rest.get('http://twaud.io/api/v1/users/danwrong.xml').on('complete', function(da sys.puts(data[0].sounds[0].sound[0].message); // auto convert to object }); +rest.get('http://tianji.com',{timeout: 10000}).on('timeout' function(ms){ + sys.puts('did not return within '+ms+' ms'); +}).on('complete',function(data,response){ + sys.puts('did not time out'); +}); + rest.post('http://user:pass@service.com/action', { data: { id: 334 }, }).on('complete', function(data, response) { diff --git a/lib/restler.js b/lib/restler.js index fda78fc..c81077f 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -209,6 +209,12 @@ mixin(Request.prototype, { this.emit('error', err, response); this.emit('complete', err, response); }, + _fireTimeout: function(err){ + this.emit('timeout', err); + this.aborted = true; + this.timedout = true; + this.request.abort(); + }, _fireSuccess: function(body, response) { if (parseInt(response.statusCode) >= 400) { this.emit('fail', body, response); @@ -221,7 +227,16 @@ mixin(Request.prototype, { }, _makeRequest: function() { var self = this; + var timeoutMs = self.options.timeout,timeout; + if(timeoutMs){ + self.options.timeout = setTimeout(function(){ + self._fireTimeout(timeoutMs); + },timeoutMs); + } this.request.on('response', function(response) { + if(self.options.timeout){ + clearTimeout(self.options.timeout); + } self.emit('response', response); self._responseHandler(response); }).on('error', function(err) { From 2e031252d51c030dcc4a2ed8d026d6b1e8197ff7 Mon Sep 17 00:00:00 2001 From: Bhasker Kode Date: Wed, 4 Sep 2013 23:19:28 +0530 Subject: [PATCH 09/49] refactored code into _fireCancelTimeout, which is now also called when an error is emitted. --- lib/restler.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/restler.js b/lib/restler.js index c81077f..63f5215 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -206,9 +206,16 @@ mixin(Request.prototype, { } }, _fireError: function(err, response) { + this._fireCancelTimeout(); this.emit('error', err, response); this.emit('complete', err, response); }, + _fireCancelTimeout: function(){ + var self = this; + if(self.options.timeout){ + clearTimeout(self.options.timeoutFn); + } + }, _fireTimeout: function(err){ this.emit('timeout', err); this.aborted = true; @@ -227,19 +234,18 @@ mixin(Request.prototype, { }, _makeRequest: function() { var self = this; - var timeoutMs = self.options.timeout,timeout; + var timeoutMs = self.options.timeout; if(timeoutMs){ - self.options.timeout = setTimeout(function(){ + self.options.timeoutFn = setTimeout(function(){ self._fireTimeout(timeoutMs); },timeoutMs); } this.request.on('response', function(response) { - if(self.options.timeout){ - clearTimeout(self.options.timeout); - } + self._fireCancelTimeout(); self.emit('response', response); self._responseHandler(response); }).on('error', function(err) { + self._fireCancelTimeout(); if (!self.aborted) { self._fireError(err, null); } From 628979c3a549d895728255740aef55458635fa77 Mon Sep 17 00:00:00 2001 From: Terin Stock Date: Fri, 4 Oct 2013 15:13:06 -0700 Subject: [PATCH 10/49] Fixes #115: Allow users to pass through rejectUnauthorized --- lib/restler.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/restler.js b/lib/restler.js index fda78fc..8c7c9ca 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -84,7 +84,8 @@ function Request(uri, options) { port: this.url.port, path: this._fullPath(), method: this.options.method, - headers: this.headers + headers: this.headers, + rejectUnauthorized: this.options.rejectUnauthorized || true }); this._makeRequest(); From b7f3c9f00f9ce130dfc8004e0802a3ac32c29add Mon Sep 17 00:00:00 2001 From: Terin Stock Date: Fri, 4 Oct 2013 15:31:44 -0700 Subject: [PATCH 11/49] Ugh, idiot --- lib/restler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/restler.js b/lib/restler.js index 8c7c9ca..466107a 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -85,7 +85,7 @@ function Request(uri, options) { path: this._fullPath(), method: this.options.method, headers: this.headers, - rejectUnauthorized: this.options.rejectUnauthorized || true + rejectUnauthorized: this.options.rejectUnauthorized }); this._makeRequest(); From 669ede27b03c01f2cf8db90f6b9bafe682d8186d Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Fri, 6 Dec 2013 16:35:58 +0000 Subject: [PATCH 12/49] Updated packages to latest version. Fixed tests that were failing against xml2js. Added a npm test script to the package.json Minor refactor of the tests. --- package.json | 40 +++++++++++++++++----------- test/restler.js | 71 +++++++++++++++++++++++-------------------------- 2 files changed, 59 insertions(+), 52 deletions(-) diff --git a/package.json b/package.json index c96f316..027d538 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,28 @@ { - "name": "restler", - "version": "2.0.1", - "description": "An HTTP client library for node.js", - "contributors": [{ "name": "Dan Webb", "email": "dan@danwebb.net" }], - "homepage": "https://github.com/danwrong/restler", - "directories" : { "lib" : "./lib" }, - "main" : "./lib/restler", - "engines": { "node": ">= 0.6.x" }, - "dependencies": { - }, - "devDependencies": { - "nodeunit": ">=0.5.0", - "xml2js" : ">=0.1.0", - "yaml" : ">=0.2.0", - "iconv": ">=1.0.0" + "name": "restler", + "version": "2.0.1", + "description": "An HTTP client library for node.js", + "contributors": [ + { + "name": "Dan Webb", + "email": "dan@danwebb.net" } + ], + "homepage": "https://github.com/danwrong/restler", + "directories": { + "lib": "./lib" + }, + "main": "./lib/restler", + "engines": { + "node": ">= 0.6.x" + }, + "scripts": { + "test": "node test/all.js" + }, + "devDependencies": { + "nodeunit": "0.8.2", + "xml2js": "0.4.0", + "yaml": "0.2.3", + "iconv": "2.0.7" + } } diff --git a/test/restler.js b/test/restler.js index 77e531b..c56759d 100644 --- a/test/restler.js +++ b/test/restler.js @@ -1,7 +1,6 @@ - var rest = require('../lib/restler'); var http = require('http'); -var sys = require('util'); +var util = require('util'); var path = require('path'); var fs = require('fs'); var crypto = require('crypto'); @@ -16,8 +15,6 @@ try { Iconv = require('iconv').Iconv; } catch (err) {} -var p = sys.inspect; - var port = 9000; var hostname = 'localhost'; var host = 'http://' + hostname + ':' + port; @@ -380,21 +377,21 @@ module.exports['Deserialization'] = { 'Should parse JSON': function(test) { rest.get(host + '/json').on('complete', function(data) { - test.equal(data.ok, true, 'returned: ' + p(data)); + test.equal(data.ok, true, 'returned: ' + util.inspect(data)); test.done(); }); }, 'Should parse XML': function(test) { rest.get(host + '/xml').on('complete', function(data, response) { - test.equal(data.ok, 'true', 'returned: ' + response.raw + ' || ' + p(data)); + test.equal(data.document.ok[0], 'true', 'returned: ' + response.raw + ' parsed to ' + util.inspect(data)); test.done(); }); }, 'Should parse YAML': function(test) { rest.get(host + '/yaml').on('complete', function(data) { - test.equal(data.ok, true, 'returned: ' + p(data)); + test.equal(data.ok, true, 'returned: ' + util.inspect(data)); test.done(); }); }, @@ -402,7 +399,7 @@ module.exports['Deserialization'] = { 'Should gunzip': function(test) { if (zlib) { rest.get(host + '/gzip').on('complete', function(data) { - test.re(data, /^(compressed data){10}$/, 'returned: ' + p(data)); + test.re(data, /^(compressed data){10}$/, 'returned: ' + util.inspect(data)); test.done(); }); } else { @@ -413,7 +410,7 @@ module.exports['Deserialization'] = { 'Should inflate': function(test) { if (zlib) { rest.get(host + '/deflate').on('complete', function(data) { - test.re(data, /^(compressed data){10}$/, 'returned: ' + p(data)); + test.re(data, /^(compressed data){10}$/, 'returned: ' + util.inspect(data)); test.done(); }) } else { @@ -428,9 +425,9 @@ module.exports['Deserialization'] = { with (data) { var result = what + (is + the + answer + to + life + the + universe + and + everything).length; } - test.equal(result, 42, 'returned: ' + p(data)); + test.equal(result, 42, 'returned: ' + util.inspect(data)); } catch (err) { - test.ok(false, 'returned: ' + p(data)); + test.ok(false, 'returned: ' + util.inspect(data)); } test.done(); }) @@ -442,23 +439,23 @@ module.exports['Deserialization'] = { 'Should decode as buffer': function(test) { rest.get(host + '/binary', { decoding: 'buffer' }).on('complete', function(data) { test.ok(data instanceof Buffer, 'should be buffer'); - test.equal(data.toString('base64'), 'CR5Ah8g=', 'returned: ' + p(data)); + test.equal(data.toString('base64'), 'CR5Ah8g=', 'returned: ' + util.inspect(data)); test.done(); }) }, 'Should decode as binary': function(test) { rest.get(host + '/binary', { decoding: 'binary' }).on('complete', function(data) { - test.ok(typeof data == 'string', 'should be string: ' + p(data)); - test.equal(data, '\t\u001e@‡È', 'returned: ' + p(data)); + test.ok(typeof data == 'string', 'should be string: ' + util.inspect(data)); + test.equal(data, '\t\u001e@‡È', 'returned: ' + util.inspect(data)); test.done(); }) }, 'Should decode as base64': function(test) { rest.get(host + '/binary', { decoding: 'base64' }).on('complete', function(data) { - test.ok(typeof data == 'string', 'should be string: ' + p(data)); - test.equal(data, 'CR5Ah8g=', 'returned: ' + p(data)); + test.ok(typeof data == 'string', 'should be string: ' + util.inspect(data)); + test.equal(data, 'CR5Ah8g=', 'returned: ' + util.inspect(data)); test.done(); }) }, @@ -471,7 +468,7 @@ module.exports['Deserialization'] = { }, data: JSON.stringify(obj) }).on('complete', function(data) { - test.equal(obj.secret, data.secret, 'returned: ' + p(data)); + test.equal(obj.secret, data.secret, 'returned: ' + util.inspect(data)); test.done(); }) }, @@ -479,7 +476,7 @@ module.exports['Deserialization'] = { 'Should post and parse JSON via shortcut method': function(test) { var obj = { secret : 'very secret string' }; rest.postJson(host + '/push-json', obj).on('complete', function(data) { - test.equal(obj.secret, data.secret, 'returned: ' + p(data)); + test.equal(obj.secret, data.secret, 'returned: ' + util.inspect(data)); test.done(); }); }, @@ -493,9 +490,9 @@ module.exports['Deserialization'] = { }; rest.get(host + '/custom-mime').on('complete', function(data) { test.expect(3); - test.ok(Array.isArray(data), 'should be array, returned: ' + p(data)); - test.equal(data.join(''), '666', 'should be [6,6,6], returned: ' + p(data)); - test.equal(data.__parsedBy__, 'github', 'should use vendor-specific parser, returned: ' + p(data.__parsedBy__)); + test.ok(Array.isArray(data), 'should be array, returned: ' + util.inspect(data)); + test.equal(data.join(''), '666', 'should be [6,6,6], returned: ' + util.inspect(data)); + test.equal(data.__parsedBy__, 'github', 'should use vendor-specific parser, returned: ' + util.inspect(data.__parsedBy__)); test.done(); }); }, @@ -521,11 +518,11 @@ module.exports['Deserialization'] = { 'Should correctly hard-abort request': function(test) { test.expect(4); rest.get(host + '/abort').on('complete', function(data) { - test.ok(data instanceof Error, 'should be error, got: ' + p(data)); + test.ok(data instanceof Error, 'should be error, got: ' + util.inspect(data)); test.equal(this.aborted, true, 'should be aborted'); test.done(); }).on('error', function(err) { - test.ok(err instanceof Error, 'should be error, got: ' + p(err)); + test.ok(err instanceof Error, 'should be error, got: ' + util.inspect(err)); }).on('abort', function(err) { test.equal(this.aborted, true, 'should be aborted'); }).on('success', function() { @@ -538,12 +535,12 @@ module.exports['Deserialization'] = { 'Should correctly handle malformed JSON': function(test) { test.expect(4); rest.get(host + '/mal-json').on('complete', function(data, response) { - test.ok(data instanceof Error, 'should be instanceof Error, got: ' + p(data)); - test.re(data.message, /^Failed to parse/, 'should contain "Failed to parse", got: ' + p(data.message)); - test.equal(response.raw, 'Чебурашка', 'should be "Чебурашка", got: ' + p(response.raw)); + test.ok(data instanceof Error, 'should be instanceof Error, got: ' + util.inspect(data)); + test.re(data.message, /^Failed to parse/, 'should contain "Failed to parse", got: ' + util.inspect(data.message)); + test.equal(response.raw, 'Чебурашка', 'should be "Чебурашка", got: ' + util.inspect(response.raw)); test.done(); }).on('error', function(err) { - test.ok(err instanceof Error, 'should be instanceof Error, got: ' + p(err)); + test.ok(err instanceof Error, 'should be instanceof Error, got: ' + util.inspect(err)); }).on('success', function() { test.ok(false, 'should not have got here'); }).on('fail', function() { @@ -554,12 +551,12 @@ module.exports['Deserialization'] = { 'Should correctly handle malformed XML': function(test) { test.expect(4); rest.get(host + '/mal-xml').on('complete', function(data, response) { - test.ok(data instanceof Error, 'should be instanceof Error, got: ' + p(data)); - test.re(data.message, /^Failed to parse/, 'should contain "Failed to parse", got: ' + p(data.message)); - test.equal(response.raw, 'Чебурашка', 'should be "Чебурашка", got: ' + p(response.raw)); + test.ok(data instanceof Error, 'should be instanceof Error, got: ' + util.inspect(data)); + test.re(data.message, /^Failed to parse/, 'should contain "Failed to parse", got: ' + util.inspect(data.message)); + test.equal(response.raw, 'Чебурашка', 'should be "Чебурашка", got: ' + util.inspect(response.raw)); test.done(); }).on('error', function(err) { - test.ok(err instanceof Error, 'should be instanceof Error, got: ' + p(err)); + test.ok(err instanceof Error, 'should be instanceof Error, got: ' + util.inspect(err)); }).on('success', function() { test.ok(false, 'should not have got here'); }).on('fail', function() { @@ -570,12 +567,12 @@ module.exports['Deserialization'] = { 'Should correctly handle malformed YAML': function(test) { test.expect(4); rest.get(host + '/mal-yaml').on('complete', function(data, response) { - test.ok(data instanceof Error, 'should be instanceof Error, got: ' + p(data)); - test.re(data.message, /^Failed to parse/, 'should contain "Failed to parse", got: ' + p(data.message)); - test.equal(response.raw, '{Чебурашка', 'should be "{Чебурашка", got: ' + p(response.raw)); + test.ok(data instanceof Error, 'should be instanceof Error, got: ' + util.inspect(data)); + test.re(data.message, /^Failed to parse/, 'should contain "Failed to parse", got: ' + util.inspect(data.message)); + test.equal(response.raw, '{Чебурашка', 'should be "{Чебурашка", got: ' + util.inspect(response.raw)); test.done(); }).on('error', function(err) { - test.ok(err instanceof Error, 'should be instanceof Error, got: ' + p(err)); + test.ok(err instanceof Error, 'should be instanceof Error, got: ' + util.inspect(err)); }).on('success', function() { test.ok(false, 'should not have got here'); }).on('fail', function() { @@ -621,7 +618,7 @@ module.exports['Redirect'] = { 'Should follow redirects': function(test) { rest.get(host).on('complete', function(data) { - test.equal(data, 'redirected', 'returned: ' + p(data)); + test.equal(data, 'redirected', 'returned: ' + util.inspect(data)); test.done(); }); }, @@ -630,7 +627,7 @@ module.exports['Redirect'] = { rest.get(host, { headers: { 'x-redirects': '5' } }).on('complete', function(data) { - test.equal(data, '5', 'returned: ' + p(data)); + test.equal(data, '5', 'returned: ' + util.inspect(data)); test.done(); }); } From 12dcbdc7fb726627edb6a423afe44cf1b9f5874f Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Fri, 6 Dec 2013 16:42:51 +0000 Subject: [PATCH 13/49] Update README.md Updated instructions for running the tests. Added install instructions. --- README.md | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index a98b844..bff61f5 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,20 @@ Ths change will inevitably affect those using older < 0.2.x versions of restler. See [Version History](https://github.com/danwrong/restler/wiki/Version-History) for changes +Installing +---------- + +``` +npm install restler +``` + +Running the tests +----------------- + +``` +npm test +``` + Features -------- @@ -185,26 +199,6 @@ rest.postJson('http://example.com/action', jsonData).on('complete', function(dat ``` -Running the tests ------------------ -install **[nodeunit](https://github.com/caolan/nodeunit)** - -```bash -npm install nodeunit -``` - -then - -```bash -node test/all.js -``` - -or - -```bash -nodeunit test/restler.js -``` - TODO ---- * What do you need? Let me know or fork. From ead274ea20af0cb1a0a1b9cad4c3679e56dada8e Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Fri, 6 Dec 2013 17:02:18 +0000 Subject: [PATCH 14/49] Adding repository to the package.json. --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 027d538..3498773 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,10 @@ } ], "homepage": "https://github.com/danwrong/restler", + "repository": { + "type": "git", + "url": "https://github.com/danwrong/restler.git" + }, "directories": { "lib": "./lib" }, From 731faa15a15de5514d50f32e2b77d6d7168912ed Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Mon, 9 Dec 2013 14:05:20 +0000 Subject: [PATCH 15/49] Set Content-Length for empty data response. --- lib/restler.js | 5 ++++- test/restler.js | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/restler.js b/lib/restler.js index 466107a..f8e9649 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -70,11 +70,14 @@ function Request(uri, options) { this.headers['Content-Type'] = 'application/x-www-form-urlencoded'; this.headers['Content-Length'] = this.options.data.length; } - if(typeof this.options.data == 'string') { + if (typeof this.options.data == 'string') { var buffer = new Buffer(this.options.data, this.options.encoding || 'utf8'); this.options.data = buffer; this.headers['Content-Length'] = buffer.length; } + if (!this.options.data) { + this.headers['Content-Length'] = 0; + } } var proto = (this.url.protocol == 'https:') ? https : http; diff --git a/test/restler.js b/test/restler.js index c56759d..60de000 100644 --- a/test/restler.js +++ b/test/restler.js @@ -666,6 +666,13 @@ module.exports['Content-Length'] = { test.equal(36, data, 'should byte-size content-length'); test.done(); }); + }, + + 'None data request content length': function (test) { + rest.post(host).on('complete', function(data) { + test.equal(0, data, 'should set content-length') + test.done(); + }) } }; From c0baab5e3b9153ca3a29805a522f686a7931ef06 Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Mon, 9 Dec 2013 14:17:17 +0000 Subject: [PATCH 16/49] Allow empty password auth header with test. --- test/restler.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/restler.js b/test/restler.js index 60de000..de2cddd 100644 --- a/test/restler.js +++ b/test/restler.js @@ -176,6 +176,13 @@ module.exports['Basic'] = { }); }, + 'Should send basic auth with blank password': function(test) { + rest.post(host, { username: 'danwrong', password: '' }).on('complete', function(data) { + test.re(data, /authorization\: Basic ZGFud3Jvbmc6/, 'should have "authorization "header'); + test.done(); + }); + }, + 'Should send basic auth if in url': function(test) { rest.post('http://danwrong:flange@' + hostname + ':' + port).on('complete', function(data) { test.re(data, /authorization\: Basic ZGFud3Jvbmc6Zmxhbmdl/, 'should have "authorization" header'); From 41854b128582aab12268fb7603c97db36d49a674 Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Mon, 9 Dec 2013 14:45:31 +0000 Subject: [PATCH 17/49] Adding node-querystring due to incomplete qs in node code. --- lib/restler.js | 2 +- package.json | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/restler.js b/lib/restler.js index afaae07..93e1562 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -3,7 +3,7 @@ var events = require("events"); var http = require('http'); var https = require('https'); var url = require('url'); -var qs = require('querystring'); +var qs = require('qs'); var multipart = require('./multipartform'); var zlib = null; var Iconv = null; diff --git a/package.json b/package.json index 3498773..a074bfa 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,9 @@ "scripts": { "test": "node test/all.js" }, + "dependencies": { + "qs": "0.6.6" + }, "devDependencies": { "nodeunit": "0.8.2", "xml2js": "0.4.0", From e7a424a78b8f91d6acba0bc70cdb8cb8e77dacfc Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Mon, 9 Dec 2013 14:53:41 +0000 Subject: [PATCH 18/49] Version bump in accoradance with semvar. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a074bfa..841de77 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "restler", - "version": "2.0.1", + "version": "3.0.0", "description": "An HTTP client library for node.js", "contributors": [ { From 051151e1dfeb3cc3437bedf5b4283a16e78f6aad Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Tue, 10 Dec 2013 11:02:13 +0000 Subject: [PATCH 19/49] Updates to documentation and supported node engines. --- README.md | 6 +----- package.json | 6 +++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4fb4ad3..9581659 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,7 @@ Restler (C) Dan Webb (dan@danwebb.net/@danwrong) 2011, Licensed under the MIT-LICENSE -An HTTP client library for node.js (0.6.x and up). Hides most of the complexity of creating and using http.Client. - -**Release 2.x.x** is dedicated to modifying how errors are handled and emitted. Currently errors are being fired as an on 'error' event but as [@ctavan](https://github.com/ctavan) pointed out on [issue #36](https://github.com/danwrong/restler/pull/36) a better approach (and more commonly in vogue now) would be to pass the error obj to the callback. - -Ths change will inevitably affect those using older < 0.2.x versions of restler. Those not ready to upgrade yet are encouraged to stay on the 0.2.x version. +An HTTP client library for node.js (0.10.x and up). Hides most of the complexity of creating and using http.Client. See [Version History](https://github.com/danwrong/restler/wiki/Version-History) for changes diff --git a/package.json b/package.json index 841de77..0622e74 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,10 @@ { "name": "Dan Webb", "email": "dan@danwebb.net" + }, + { + "name": "Ben Marvell", + "email": "ben@marvell-consulting.com" } ], "homepage": "https://github.com/danwrong/restler", @@ -18,7 +22,7 @@ }, "main": "./lib/restler", "engines": { - "node": ">= 0.6.x" + "node": ">= 0.10.x" }, "scripts": { "test": "node test/all.js" From 05c646562c67d3fd6929807e2b8c7b0f817bb34b Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Tue, 10 Dec 2013 11:33:37 +0000 Subject: [PATCH 20/49] Minor updates to readme --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9581659..f37db48 100644 --- a/README.md +++ b/README.md @@ -133,24 +133,23 @@ Example usage ------------- ```javascript -var sys = require('util'), - rest = require('./restler'); +var rest = require('./restler'); rest.get('http://google.com').on('complete', function(result) { if (result instanceof Error) { - sys.puts('Error: ' + result.message); + console.log('Error:', result.message); this.retry(5000); // try again after 5 sec } else { - sys.puts(result); + console.log(result); } }); rest.get('http://twaud.io/api/v1/users/danwrong.json').on('complete', function(data) { - sys.puts(data[0].message); // auto convert to object + console.log(data[0].message); // auto convert to object }); rest.get('http://twaud.io/api/v1/users/danwrong.xml').on('complete', function(data) { - sys.puts(data[0].sounds[0].sound[0].message); // auto convert to object + console.log(data[0].sounds[0].sound[0].message); // auto convert to object }); rest.post('http://user:pass@service.com/action', { @@ -171,7 +170,7 @@ rest.post('https://twaud.io/api/v1/upload.json', { 'sound[file]': rest.file('doug-e-fresh_the-show.mp3', null, 321567, null, 'audio/mpeg') } }).on('complete', function(data) { - sys.puts(data.audio_url); + console.log(data.audio_url); }); // create a service constructor for very easy API wrappers a la HTTParty... @@ -188,7 +187,7 @@ Twitter = rest.service(function(u, p) { var client = new Twitter('danwrong', 'password'); client.update('Tweeting using a Restler service thingy').on('complete', function(data) { - sys.p(data); + console.log(data); }); // post JSON From d3deca9566f379c1bb5315e628cb6bd527346213 Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Tue, 10 Dec 2013 11:52:01 +0000 Subject: [PATCH 21/49] As we now support node 0.10.x upwards we just require zlib instead of checking. We also know Iconv is there so we just require that. Removed trailing spaces. Fixed package.json to include dependencies in the correct locations. --- README.md | 4 +-- lib/restler.js | 98 ++++++++++++++++++++++---------------------------- package.json | 8 ++--- 3 files changed, 49 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index f37db48..7657000 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,8 @@ Features * Transparently handle SSL (just specify https in the URL) * Deals with basic auth for you, just provide username and password options * Simple service wrapper that allows you to easily put together REST API libraries -* Transparently handle content-encoded responses (gzip, deflate) (requires node 0.6+) -* Transparently handle different content charsets via [iconv](https://github.com/bnoordhuis/node-iconv) (if available) +* Transparently handle content-encoded responses (gzip, deflate) +* Transparently handle different content charsets via [iconv](https://github.com/bnoordhuis/node-iconv) API diff --git a/lib/restler.js b/lib/restler.js index 93e1562..8995627 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -1,27 +1,19 @@ -var util = require('util'); -var events = require("events"); -var http = require('http'); -var https = require('https'); -var url = require('url'); -var qs = require('qs'); -var multipart = require('./multipartform'); -var zlib = null; -var Iconv = null; - -try { - zlib = require('zlib'); -} catch (err) {} - -try { - Iconv = require('iconv').Iconv; -} catch (err) {} +var util = require('util'), + events = require("events"), + http = require('http'), + https = require('https'), + url = require('url'), + qs = require('qs'), + multipart = require('./multipartform'), + zlib = require('zlib'), + Iconv = require('iconv').Iconv; function mixin(target, source) { source = source || {}; Object.keys(source).forEach(function(key) { target[key] = source[key]; }); - + return target; } @@ -35,26 +27,24 @@ function Request(uri, options) { 'Host': this.url.host }; - if (zlib) { - this.headers['Accept-Encoding'] = 'gzip, deflate'; - } - + this.headers['Accept-Encoding'] = 'gzip, deflate'; + mixin(this.headers, options.headers || {}); - + // set port and method defaults if (!this.url.port) this.url.port = (this.url.protocol == 'https:') ? '443' : '80'; if (!this.options.method) this.options.method = (this.options.data) ? 'POST' : 'GET'; if (typeof this.options.followRedirects == 'undefined') this.options.followRedirects = true; - + // stringify query given in options of not given in URL if (this.options.query && !this.url.query) { - if (typeof this.options.query == 'object') + if (typeof this.options.query == 'object') this.url.query = qs.stringify(this.options.query); else this.url.query = this.options.query; } - + this._applyBasicAuth(); - + if (this.options.multipart) { this.headers['Content-Type'] = 'multipart/form-data; boundary=' + multipart.defaultBoundary; var multipart_size = multipart.sizeOf(this.options.data, multipart.defaultBoundary); @@ -79,9 +69,9 @@ function Request(uri, options) { this.headers['Content-Length'] = 0; } } - + var proto = (this.url.protocol == 'https:') ? https : http; - + this.request = proto.request({ host: this.url.hostname, port: this.url.port, @@ -90,7 +80,7 @@ function Request(uri, options) { headers: this.headers, rejectUnauthorized: this.options.rejectUnauthorized }); - + this._makeRequest(); } @@ -108,13 +98,13 @@ mixin(Request.prototype, { }, _applyBasicAuth: function() { var authParts; - + if (this.url.auth) { authParts = this.url.auth.split(':'); this.options.username = authParts[0]; this.options.password = authParts[1]; } - + if (this.options.username && this.options.password !== undefined) { var b = new Buffer([this.options.username, this.options.password].join(':')); this.headers['Authorization'] = "Basic " + b.toString('base64'); @@ -122,7 +112,7 @@ mixin(Request.prototype, { }, _responseHandler: function(response) { var self = this; - + if (self._isRedirect(response) && self.options.followRedirects) { try { // 303 should redirect and retrieve content with the GET method @@ -143,13 +133,13 @@ mixin(Request.prototype, { } } else { var body = ''; - + response.setEncoding('binary'); - + response.on('data', function(chunk) { body += chunk; }); - + response.on('end', function() { response.rawEncoded = body; self._decode(new Buffer(body, 'binary'), response, function(err, body) { @@ -179,18 +169,16 @@ mixin(Request.prototype, { } }, _iconv: function(body, response) { - if (Iconv) { - var charset = response.headers['content-type']; + var charset = response.headers['content-type']; + if (charset) { + charset = /\bcharset=(.+)(?:;|$)/i.exec(charset); if (charset) { - charset = /\bcharset=(.+)(?:;|$)/i.exec(charset); - if (charset) { - charset = charset[1].trim().toUpperCase(); - if (charset != 'UTF-8') { - try { - var iconv = new Iconv(charset, 'UTF-8//TRANSLIT//IGNORE'); - return iconv.convert(body); - } catch (err) {} - } + charset = charset[1].trim().toUpperCase(); + if (charset != 'UTF-8') { + try { + var iconv = new Iconv(charset, 'UTF-8//TRANSLIT//IGNORE'); + return iconv.convert(body); + } catch (err) {} } } } @@ -254,7 +242,7 @@ mixin(Request.prototype, { } this.request.end(); } - + return this; }, abort: function(err) { @@ -303,8 +291,8 @@ function shortcutOptions(options, method) { options.parser = (typeof options.parser !== "undefined") ? options.parser : parsers.auto; return options; } - -function request(url, options) { + +function request(url, options) { var request = new Request(url, options); request.on('error', function() {}); process.nextTick(request.run.bind(request)); @@ -400,7 +388,7 @@ parsers.auto.matchers = { try { var yaml = require('yaml'); - + parsers.yaml = function(data, callback) { if (data) { try { @@ -413,7 +401,7 @@ try { callback(null, null); } }; - + parsers.auto.matchers['application/yaml'] = parsers.yaml; } catch(e) {} @@ -433,7 +421,7 @@ try { callback(null, null); } }; - + parsers.auto.matchers['application/xml'] = parsers.xml; } catch(e) { } @@ -450,9 +438,9 @@ var decoders = { function Service(defaults) { if (defaults.baseURL) { this.baseURL = defaults.baseURL; - delete defaults.baseURL; + delete defaults.baseURL; } - + this.defaults = defaults; } diff --git a/package.json b/package.json index 0622e74..d5b57ed 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,12 @@ "test": "node test/all.js" }, "dependencies": { - "qs": "0.6.6" - }, - "devDependencies": { - "nodeunit": "0.8.2", + "qs": "0.6.6", "xml2js": "0.4.0", "yaml": "0.2.3", "iconv": "2.0.7" + }, + "devDependencies": { + "nodeunit": "0.8.2" } } From 56bf99718cce6abd336af8db3a2b99e93ce5998a Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Wed, 11 Dec 2013 14:31:10 +0000 Subject: [PATCH 22/49] Fixed a few jshint issues. Made the parse tests clearer. --- test/restler.js | 108 ++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 58 deletions(-) diff --git a/test/restler.js b/test/restler.js index de2cddd..8fc94fa 100644 --- a/test/restler.js +++ b/test/restler.js @@ -1,19 +1,11 @@ -var rest = require('../lib/restler'); -var http = require('http'); -var util = require('util'); -var path = require('path'); -var fs = require('fs'); -var crypto = require('crypto'); -var zlib = null; -var Iconv = null; - -try { - zlib = require('zlib'); -} catch (err) {} - -try { - Iconv = require('iconv').Iconv; -} catch (err) {} +var rest = require('../lib/restler'), + http = require('http'), + util = require('util'), + path = require('path'), + fs = require('fs'), + crypto = require('crypto'), + zlib = require('zlib'), + Iconv = require('iconv').Iconv; var port = 9000; var hostname = 'localhost'; @@ -21,7 +13,9 @@ var host = 'http://' + hostname + ':' + port; var nodeunit = require('nodeunit'); nodeunit.assert.re = function(actual, expected, message) { - new RegExp(expected).test(actual) || nodeunit.assert.fail(actual, expected, message, '~=', nodeunit.assert.re); + if (!new RegExp(expected).test(actual)) { + nodeunit.assert.fail(actual, expected, message, '~=', nodeunit.assert.re); + } }; @@ -34,7 +28,9 @@ function setup(response) { function teardown() { return function (next) { - this.server._handle && this.server.close(); + if (this.server._handle) { + this.server.close(); + } process.nextTick(next); }; } @@ -255,10 +251,12 @@ module.exports['Basic'] = { function command() { var args = [].slice.call(arguments); var method = args.shift(); - method && setTimeout(function() { - request[method](); - command.apply(null, args); - }, 50); + if (method) { + setTimeout(function() { + request[method](); + command.apply(null, args); + }, 50); + } } request = rest.get(host, { headers: { 'x-delay': '1000' } }).on('complete', function() { @@ -284,7 +282,7 @@ module.exports['Multipart'] = { data: { a: 10, b: 'thing' }, multipart: true }).on('complete', function(data) { - test.re(data, /content-type\: multipart\/form-data/, 'should set "content-type" header') + test.re(data, /content-type\: multipart\/form-data/, 'should set "content-type" header'); test.re(data, /name="a"(\s)+10/, 'should send a=10'); test.re(data, /name="b"(\s)+thing/, 'should send b=thing'); test.re(data, /content-length: 200/, 'should send content-length header'); @@ -404,43 +402,35 @@ module.exports['Deserialization'] = { }, 'Should gunzip': function(test) { - if (zlib) { - rest.get(host + '/gzip').on('complete', function(data) { - test.re(data, /^(compressed data){10}$/, 'returned: ' + util.inspect(data)); - test.done(); - }); - } else { + rest.get(host + '/gzip').on('complete', function(data) { + test.re(data, /^(compressed data){10}$/, 'returned: ' + util.inspect(data)); test.done(); - } + }); }, 'Should inflate': function(test) { - if (zlib) { - rest.get(host + '/deflate').on('complete', function(data) { - test.re(data, /^(compressed data){10}$/, 'returned: ' + util.inspect(data)); - test.done(); - }) - } else { + rest.get(host + '/deflate').on('complete', function(data) { + test.re(data, /^(compressed data){10}$/, 'returned: ' + util.inspect(data)); test.done(); - } + }); }, 'Should decode and parse': function(test) { - if (zlib) { - rest.get(host + '/truth').on('complete', function(data) { - try { - with (data) { - var result = what + (is + the + answer + to + life + the + universe + and + everything).length; - } - test.equal(result, 42, 'returned: ' + util.inspect(data)); - } catch (err) { - test.ok(false, 'returned: ' + util.inspect(data)); - } - test.done(); - }) - } else { + rest.get(host + '/truth').on('complete', function(data) { + var expected = { + what: -6, + is: {}, + the: [ 0, 0, 0 ], + answer: 'answer', + to: 2, + life: 'life', + universe: null, + and: 3.14, + everything: true + }; + test.deepEqual(data, expected, 'returned: ' + util.inspect(data)); test.done(); - } + }); }, 'Should decode as buffer': function(test) { @@ -448,7 +438,7 @@ module.exports['Deserialization'] = { test.ok(data instanceof Buffer, 'should be buffer'); test.equal(data.toString('base64'), 'CR5Ah8g=', 'returned: ' + util.inspect(data)); test.done(); - }) + }); }, 'Should decode as binary': function(test) { @@ -456,7 +446,7 @@ module.exports['Deserialization'] = { test.ok(typeof data == 'string', 'should be string: ' + util.inspect(data)); test.equal(data, '\t\u001e@‡È', 'returned: ' + util.inspect(data)); test.done(); - }) + }); }, 'Should decode as base64': function(test) { @@ -464,7 +454,7 @@ module.exports['Deserialization'] = { test.ok(typeof data == 'string', 'should be string: ' + util.inspect(data)); test.equal(data, 'CR5Ah8g=', 'returned: ' + util.inspect(data)); test.done(); - }) + }); }, 'Should post and parse JSON': function(test) { @@ -477,7 +467,7 @@ module.exports['Deserialization'] = { }).on('complete', function(data) { test.equal(obj.secret, data.secret, 'returned: ' + util.inspect(data)); test.done(); - }) + }); }, 'Should post and parse JSON via shortcut method': function(test) { @@ -491,7 +481,9 @@ module.exports['Deserialization'] = { 'Should understand custom mime-type': function(test) { rest.parsers.auto.matchers['application/vnd.github+json'] = function(data, callback) { rest.parsers.json.call(this, data, function(err, data) { - err || (data.__parsedBy__ = 'github'); + if (!err) { + data.__parsedBy__ = 'github'; + } callback(err, data); }); }; @@ -609,8 +601,8 @@ function redirectResponse(request, response) { }); response.end('redirect'); } else { - var count = parseInt(request.url.substr(1)); - var max = parseInt(request.headers['x-redirects']); + var count = parseInt(request.url.substr(1), 10); + var max = parseInt(request.headers['x-redirects'], 10); response.writeHead(count < max ? 301 : 200, { 'location': host + '/' + (count + 1) }); From 5409273db5c4f33492ff52ec67c456c8ef2c05f5 Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Wed, 11 Dec 2013 14:31:38 +0000 Subject: [PATCH 23/49] Added a simple test for timeouts --- test/restler.js | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/test/restler.js b/test/restler.js index 8fc94fa..c2b29fd 100644 --- a/test/restler.js +++ b/test/restler.js @@ -369,6 +369,12 @@ function dataResponse(request, response) { }); response.end(Buffer('e0e1e2e3e4e5b8e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', 'hex')); break; + case '/timeout': + setTimeout(function() { + response.writeHead(200); + response.end('that took a while'); + }, 100); + break; default: response.writeHead(404); response.end(); @@ -669,9 +675,25 @@ module.exports['Content-Length'] = { 'None data request content length': function (test) { rest.post(host).on('complete', function(data) { - test.equal(0, data, 'should set content-length') + test.equal(0, data, 'should set content-length'); test.done(); - }) + }); } }; + +module.exports['Timeout'] = { + setUp: setup(dataResponse), + tearDown: teardown(), + + 'will timeout within given time': function(test) { + rest.get(host + '/timeout', {timeout: 50}) + .on('timeout', function () { + test.ok(true, 'timeout endpoint is 100ms and timeout was 50ms'); + test.done(); + }) + .on('complete', function () { + test.ok(false, 'should not emit complete event'); + }); + } +}; \ No newline at end of file From 2af60e1be04dbe986ff34ad72324f7c9f763f608 Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Wed, 11 Dec 2013 16:31:07 +0000 Subject: [PATCH 24/49] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fed6358..db177fe 100644 --- a/README.md +++ b/README.md @@ -155,9 +155,9 @@ rest.get('http://twaud.io/api/v1/users/danwrong.xml').on('complete', function(da }); rest.get('http://tianji.com',{timeout: 10000}).on('timeout' function(ms){ - sys.puts('did not return within '+ms+' ms'); + console.log('did not return within '+ms+' ms'); }).on('complete',function(data,response){ - sys.puts('did not time out'); + console.log('did not time out'); }); rest.post('http://user:pass@service.com/action', { From 5b07d142aed5e137cad26007e1018c26f30d61b3 Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Wed, 11 Dec 2013 16:32:10 +0000 Subject: [PATCH 25/49] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db177fe..ed434df 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ rest.get('http://twaud.io/api/v1/users/danwrong.xml').on('complete', function(da console.log(data[0].sounds[0].sound[0].message); // auto convert to object }); -rest.get('http://tianji.com',{timeout: 10000}).on('timeout' function(ms){ +rest.get('http://someslowdomain.com',{timeout: 10000}).on('timeout' function(ms){ console.log('did not return within '+ms+' ms'); }).on('complete',function(data,response){ console.log('did not time out'); From f17b670ee07ceeb964f37857c3a4961e8e953db6 Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Wed, 11 Dec 2013 17:55:51 +0000 Subject: [PATCH 26/49] Move to a purejs implementation of iconv --- lib/restler.js | 5 ++--- package.json | 2 +- test/restler.js | 19 ++++++++----------- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/lib/restler.js b/lib/restler.js index 3c1df7d..6bdb1ea 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -6,7 +6,7 @@ var util = require('util'), qs = require('qs'), multipart = require('./multipartform'), zlib = require('zlib'), - Iconv = require('iconv').Iconv; + iconv = require('iconv-lite'); function mixin(target, source) { source = source || {}; @@ -176,8 +176,7 @@ mixin(Request.prototype, { charset = charset[1].trim().toUpperCase(); if (charset != 'UTF-8') { try { - var iconv = new Iconv(charset, 'UTF-8//TRANSLIT//IGNORE'); - return iconv.convert(body); + return iconv.decode(body, charset); } catch (err) {} } } diff --git a/package.json b/package.json index d5b57ed..6f45f77 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "qs": "0.6.6", "xml2js": "0.4.0", "yaml": "0.2.3", - "iconv": "2.0.7" + "iconv-lite": "0.2.11" }, "devDependencies": { "nodeunit": "0.8.2" diff --git a/test/restler.js b/test/restler.js index c2b29fd..8669bb7 100644 --- a/test/restler.js +++ b/test/restler.js @@ -3,9 +3,7 @@ var rest = require('../lib/restler'), util = require('util'), path = require('path'), fs = require('fs'), - crypto = require('crypto'), - zlib = require('zlib'), - Iconv = require('iconv').Iconv; + crypto = require('crypto'); var port = 9000; var hostname = 'localhost'; @@ -587,14 +585,13 @@ module.exports['Deserialization'] = { }; -if (Iconv) { - module.exports['Deserialization']['Should correctly convert charsets '] = function(test) { - rest.get(host + '/charset').on('complete', function(data) { - test.equal(data, 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'); - test.done(); - }); - }; -} + +module.exports['Deserialization']['Should correctly convert charsets '] = function(test) { + rest.get(host + '/charset').on('complete', function(data) { + test.equal(data, 'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'); + test.done(); + }); +}; function redirectResponse(request, response) { From 2c658f1ccab6b7dffc719b30d6e637a56c09842f Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Thu, 12 Dec 2013 11:21:48 +0000 Subject: [PATCH 27/49] Version bump 3.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6f45f77..752be68 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "restler", - "version": "3.0.0", + "version": "3.1.0", "description": "An HTTP client library for node.js", "contributors": [ { From e122f9d078eb5cdcfa64a5ef317c77b4ffeec228 Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Thu, 12 Dec 2013 11:26:06 +0000 Subject: [PATCH 28/49] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ed434df..2208651 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Features * Deals with basic auth for you, just provide username and password options * Simple service wrapper that allows you to easily put together REST API libraries * Transparently handle content-encoded responses (gzip, deflate) -* Transparently handle different content charsets via [iconv](https://github.com/bnoordhuis/node-iconv) +* Transparently handle different content charsets via [iconv-lite](https://github.com/ashtuchkin/iconv-lite) API From c295a6bef2e28c1a52689bc81ba45eff69cb0107 Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Thu, 12 Dec 2013 12:45:57 +0000 Subject: [PATCH 29/49] Added an npm badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 2208651..6fb7ce5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ Restler ======= +[![NPM](https://nodei.co/npm/restler.png?downloads=true&stars=true)](https://nodei.co/npm/restler/) + (C) Dan Webb (dan@danwebb.net/@danwrong) 2011, Licensed under the MIT-LICENSE An HTTP client library for node.js (0.10.x and up). Hides most of the complexity of creating and using http.Client. From 394cc0df92a7f94e5e3964f16baa9a745cfbf207 Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Fri, 13 Dec 2013 10:18:06 +0000 Subject: [PATCH 30/49] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6fb7ce5..0566fd2 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Features * Easy interface for common operations via http.request * Automatic serialization of post data * Automatic serialization of query string data -* Automatic deserialization of XML, JSON and YAML responses to JavaScript objects (if you have js-yaml and/or xml2js in the require path) +* Automatic deserialization of XML, JSON and YAML responses to JavaScript objects * Provide your own deserialization functions for other datatypes * Automatic following of redirects * Send files with multipart requests From a264c333e659c534c9de58b874be2e948813f550 Mon Sep 17 00:00:00 2001 From: pmaccart Date: Fri, 13 Dec 2013 14:25:21 -0600 Subject: [PATCH 31/49] don't perform callback in a try/catch block after parsing JSON --- lib/restler.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/restler.js b/lib/restler.js index 6bdb1ea..72175c7 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -390,12 +390,14 @@ var parsers = { }, json: function(data, callback) { if (data && data.length) { + var parsedData; try { - callback(null, JSON.parse(data)); + parsedData = JSON.parse(data); } catch (err) { err.message = 'Failed to parse JSON body: ' + err.message; callback(err, null); } + callback(null, parsedData); } else { callback(null, null); } From f1d0a95c3ffcc1bb9a7894c771d7ba7a67530a4c Mon Sep 17 00:00:00 2001 From: pmaccart Date: Fri, 13 Dec 2013 14:31:08 -0600 Subject: [PATCH 32/49] squash! don't perform callback in a try/catch block after parsing JSON --- lib/restler.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/restler.js b/lib/restler.js index 72175c7..61aa528 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -397,7 +397,9 @@ var parsers = { err.message = 'Failed to parse JSON body: ' + err.message; callback(err, null); } - callback(null, parsedData); + if (parsedData !== undefined) { + callback(null, parsedData); + } } else { callback(null, null); } From e24f086a91cb0f10121ad27dc6670ee45c9db53a Mon Sep 17 00:00:00 2001 From: mcameron Date: Sun, 16 Feb 2014 14:48:41 +0000 Subject: [PATCH 33/49] Adding json handing to put requests --- lib/restler.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/restler.js b/lib/restler.js index 61aa528..895b005 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -357,6 +357,10 @@ function postJson(url, data, options) { return json(url, data, options, 'POST'); } +function putJson(url, data, options) { + return json(url, data, options, 'PUT'); +} + var parsers = { auto: function(data, callback) { var contentType = this.headers['content-type']; @@ -519,6 +523,7 @@ mixin(exports, { head: head, json: json, postJson: postJson, + putJson: putJson, parsers: parsers, file: multipart.file, data: multipart.data From a0228f1ef62edff08b82f20951605c024251590c Mon Sep 17 00:00:00 2001 From: mcameron Date: Sun, 16 Feb 2014 14:52:35 +0000 Subject: [PATCH 34/49] Updating docs --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 0566fd2..ab0d9e4 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,12 @@ rest.postJson('http://example.com/action', jsonData).on('complete', function(dat // handle response }); +// put JSON +var jsonData = { id: 334 }; +rest.putJson('http://example.com/action', jsonData).on('complete', function(data, response) { + // handle response +}); + ``` TODO From 7a696b1869e5438b075457e9d48dcf7546a7b277 Mon Sep 17 00:00:00 2001 From: mcameron Date: Sun, 16 Feb 2014 14:53:28 +0000 Subject: [PATCH 35/49] Updating docs --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index ab0d9e4..a4e25f8 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,9 @@ Send json `data` via GET method. Send json `data` via POST method. +### putJson(url, data, options) + +Send json `data` via PUT method. ### Parsers From 2b5aa08037c9a13d116db07b94a062913a1504b5 Mon Sep 17 00:00:00 2001 From: mcameron Date: Sun, 16 Feb 2014 14:57:50 +0000 Subject: [PATCH 36/49] Adding tests --- test/restler.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/restler.js b/test/restler.js index 8669bb7..ae1a061 100644 --- a/test/restler.js +++ b/test/restler.js @@ -482,6 +482,14 @@ module.exports['Deserialization'] = { }); }, + 'Should put and parse JSON via shortcut method': function(test) { + var obj = { secret : 'very secret string' }; + rest.putJson(host + '/push-json', obj).on('complete', function(data) { + test.equal(obj.secret, data.secret, 'returned: ' + util.inspect(data)); + test.done(); + }); + }, + 'Should understand custom mime-type': function(test) { rest.parsers.auto.matchers['application/vnd.github+json'] = function(data, callback) { rest.parsers.json.call(this, data, function(err, data) { @@ -693,4 +701,4 @@ module.exports['Timeout'] = { test.ok(false, 'should not emit complete event'); }); } -}; \ No newline at end of file +}; From cd99af2c97b16ccb780f3b85546cd5e18c8dc217 Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Mon, 17 Feb 2014 14:50:07 +0000 Subject: [PATCH 37/49] Version bump for latest release. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 752be68..21059f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "restler", - "version": "3.1.0", + "version": "3.2.0", "description": "An HTTP client library for node.js", "contributors": [ { From 09111fca444c7390d30e8b1a8b83f8825213f7b4 Mon Sep 17 00:00:00 2001 From: Curtis Allen Date: Thu, 20 Feb 2014 13:14:56 -0700 Subject: [PATCH 38/49] Add missing doc for rejectUnauthorized option --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a4e25f8..db8df4f 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ Also you can use `json()` and `postJson()` methods. * `client` A http.Client instance if you want to reuse or implement some kind of connection pooling. Defaults to empty. * `followRedirects` If set will recursively follow redirects. Defaults to `true`. * `timeout` If set, will emit the timeout event when the response does not return within the said value (in ms) +* `rejectUnauthorized` If true, the server certificate is verified against the list of supplied CAs. An 'error' event is emitted if verification fails. Verification happens at the connection level, before the HTTP request is sent. Default true. Example usage From a2dd9d83a1702ed47ac7125c152e33e15718e905 Mon Sep 17 00:00:00 2001 From: Gustavo Henke Date: Sat, 8 Mar 2014 23:51:19 -0300 Subject: [PATCH 39/49] Fix link to Node Buffer API --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a4e25f8..4120538 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Note that if you want your request body to be JSON with the `Content-Type: appli Also you can use `json()` and `postJson()` methods. * `parser` A function that will be called on the returned data. Use any of predefined `restler.parsers`. See parsers section below. Defaults to `restler.parsers.auto`. * `encoding` The encoding of the request body. Defaults to `"utf8"`. -* `decoding` The encoding of the response body. For a list of supported values see [Buffers](http://nodejs.org/docs/latest/api/buffers.html#buffers). Additionally accepts `"buffer"` - returns response as `Buffer`. Defaults to `"utf8"`. +* `decoding` The encoding of the response body. For a list of supported values see [Buffers](http://nodejs.org/api/buffer.html#buffer_buffer). Additionally accepts `"buffer"` - returns response as `Buffer`. Defaults to `"utf8"`. * `headers` A hash of HTTP headers to be sent. Defaults to `{ 'Accept': '*/*', 'User-Agent': 'Restler for node.js' }`. * `username` Basic auth username. Defaults to empty. * `password` Basic auth password. Defaults to empty. From c0091b4a8b574aa7ab49d9a3eecd6d4d8a6abd86 Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Wed, 9 Apr 2014 09:58:10 +0100 Subject: [PATCH 40/49] Update README.md Fixes #169 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a58318..c9a6b37 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ rest.get('http://twaud.io/api/v1/users/danwrong.xml').on('complete', function(da console.log(data[0].sounds[0].sound[0].message); // auto convert to object }); -rest.get('http://someslowdomain.com',{timeout: 10000}).on('timeout' function(ms){ +rest.get('http://someslowdomain.com',{timeout: 10000}).on('timeout', function(ms){ console.log('did not return within '+ms+' ms'); }).on('complete',function(data,response){ console.log('did not time out'); From d5fc4905c23aa3ab081bb785442dc686592f4f44 Mon Sep 17 00:00:00 2001 From: Artem Vitiuk Date: Mon, 14 Apr 2014 18:37:17 +0300 Subject: [PATCH 41/49] Add OAuth support Fixes #100 --- README.md | 1 + lib/restler.js | 6 ++++-- package.json | 2 +- test/restler.js | 7 +++++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c9a6b37..ea57eec 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,7 @@ Also you can use `json()` and `postJson()` methods. * `headers` A hash of HTTP headers to be sent. Defaults to `{ 'Accept': '*/*', 'User-Agent': 'Restler for node.js' }`. * `username` Basic auth username. Defaults to empty. * `password` Basic auth password. Defaults to empty. +* `accessToken` OAuth Bearer Token. Defaults to empty. * `multipart` If set the data passed will be formated as `multipart/form-encoded`. See multipart example below. Defaults to `false`. * `client` A http.Client instance if you want to reuse or implement some kind of connection pooling. Defaults to empty. * `followRedirects` If set will recursively follow redirects. Defaults to `true`. diff --git a/lib/restler.js b/lib/restler.js index 895b005..715845a 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -43,7 +43,7 @@ function Request(uri, options) { else this.url.query = this.options.query; } - this._applyBasicAuth(); + this._applyAuth(); if (this.options.multipart) { this.headers['Content-Type'] = 'multipart/form-data; boundary=' + multipart.defaultBoundary; @@ -96,7 +96,7 @@ mixin(Request.prototype, { if (this.url.query) path += '?' + this.url.query; return path; }, - _applyBasicAuth: function() { + _applyAuth: function() { var authParts; if (this.url.auth) { @@ -108,6 +108,8 @@ mixin(Request.prototype, { if (this.options.username && this.options.password !== undefined) { var b = new Buffer([this.options.username, this.options.password].join(':')); this.headers['Authorization'] = "Basic " + b.toString('base64'); + } else if (this.options.accessToken) { + this.headers['Authorization'] = "Bearer " + this.options.accessToken; } }, _responseHandler: function(response) { diff --git a/package.json b/package.json index 21059f4..9e931dd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "restler", - "version": "3.2.0", + "version": "3.2.1", "description": "An HTTP client library for node.js", "contributors": [ { diff --git a/test/restler.js b/test/restler.js index ae1a061..d2c64c0 100644 --- a/test/restler.js +++ b/test/restler.js @@ -163,6 +163,13 @@ module.exports['Basic'] = { }); }, + 'Should send Bearer auth': function(test) { + rest.post(host, { accessToken: 't0k3n' }).on('complete', function(data) { + test.re(data, /authorization\: Bearer t0k3n/, 'should have "authorization "header'); + test.done(); + }); + }, + 'Should send basic auth': function(test) { rest.post(host, { username: 'danwrong', password: 'flange' }).on('complete', function(data) { test.re(data, /authorization\: Basic ZGFud3Jvbmc6Zmxhbmdl/, 'should have "authorization "header'); From be34cbc428f33a91b03b0997eb7a68e1830e612b Mon Sep 17 00:00:00 2001 From: Lapo Luchini Date: Wed, 23 Apr 2014 17:18:08 +0200 Subject: [PATCH 42/49] Add test case for mloar's PR danwrong/restler#119. --- test/restler.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/test/restler.js b/test/restler.js index d2c64c0..43b5320 100644 --- a/test/restler.js +++ b/test/restler.js @@ -294,7 +294,26 @@ module.exports['Multipart'] = { test.done(); }); - } + }, + + 'Test multipart request with Data vars': function(test) { + rest.post(host, { + data: { + a: 10, + b: rest.data('b.txt', 'text/plain', 'thing'), + c: rest.data('c.txt', 'text/plain', new Buffer('thing')) + }, + multipart: true + }).on('complete', function(data) { + test.re(data, /content-type\: multipart\/form-data/, 'should set "content-type" header'); + test.re(data, /name="a"(\s)+10/, 'should send a=10'); + test.re(data, /name="b"; filename="b.txt"\s+Content-Length: 5\s+Content-Type: text\/plain\s+thing\s/, 'should send b=thing'); + test.re(data, /name="c"; filename="c.txt"\s+Content-Length: 5\s+Content-Type: text\/plain\s+thing\s/, 'should send c=thing'); + test.re(data, /content-length: 410/, 'should send content-length header'); + + test.done(); + }); + }, }; From 017710a1e4c257f452d530ebb5a2b7c25ea6465a Mon Sep 17 00:00:00 2001 From: Ben Marvell Date: Thu, 24 Apr 2014 15:11:17 +0100 Subject: [PATCH 43/49] Version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9e931dd..d7bad79 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "restler", - "version": "3.2.1", + "version": "3.2.2", "description": "An HTTP client library for node.js", "contributors": [ { From a5901e611060a2abb8fc38788cccaef3752c6ab6 Mon Sep 17 00:00:00 2001 From: Justas Brazauskas Date: Tue, 17 Jun 2014 17:03:37 +0300 Subject: [PATCH 44/49] Allow writing buffer directly to req body --- lib/restler.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/restler.js b/lib/restler.js index 715845a..3d7945b 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -55,7 +55,7 @@ function Request(uri, options) { console.log("Building multipart request without Content-Length header, please specify all file sizes"); } } else { - if (typeof this.options.data == 'object') { + if (typeof this.options.data == 'object' && !Buffer.isBuffer(this.options.data)) { this.options.data = qs.stringify(this.options.data); this.headers['Content-Type'] = 'application/x-www-form-urlencoded'; this.headers['Content-Length'] = this.options.data.length; @@ -260,7 +260,7 @@ mixin(Request.prototype, { }); } else { if (this.options.data) { - this.request.write(this.options.data.toString(), this.options.encoding || 'utf8'); + this.request.write(this.options.data, this.options.encoding || 'utf8'); } this.request.end(); } From 6ef99d987cfb96caaef74aee275063ca55b77b44 Mon Sep 17 00:00:00 2001 From: Peter deHaan Date: Fri, 8 Aug 2014 18:07:41 -0700 Subject: [PATCH 45/49] Updating to qs@1.2.0 Fixes #186 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d7bad79..83143d7 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "test": "node test/all.js" }, "dependencies": { - "qs": "0.6.6", + "qs": "1.2.0", "xml2js": "0.4.0", "yaml": "0.2.3", "iconv-lite": "0.2.11" From 47e1b63044630db37ebaa6c2f0ed8e67b2f38994 Mon Sep 17 00:00:00 2001 From: Justas Brazauskas Date: Thu, 14 Aug 2014 17:08:55 +0300 Subject: [PATCH 46/49] Added test to send buffer --- test/restler.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/restler.js b/test/restler.js index 43b5320..ec7d926 100644 --- a/test/restler.js +++ b/test/restler.js @@ -145,6 +145,13 @@ module.exports['Basic'] = { }); }, + 'Should POST buffer body': function(test) { + rest.post(host, { data: new Buffer('balls') }).on('complete', function(data) { + test.re(data, /\r\n\r\nballs/, 'should have balls in the body'); + test.done(); + }); + }, + 'Should serialize POST body': function(test) { rest.post(host, { data: { q: 'balls' } }).on('complete', function(data) { test.re(data, /content-type\: application\/x-www-form-urlencoded/, 'should set content-type'); From 0cf5fbefe3093dcd57e1fa9caf35bbda5568181d Mon Sep 17 00:00:00 2001 From: Jonathan Bender Date: Thu, 22 Jan 2015 12:00:20 -0500 Subject: [PATCH 47/49] Cleaner at-a-glace stats/info Retina-ready svg icons indicating current version and Node.js dependency rather than as text, which was harder to find --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ea57eec..7e1b3bb 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,8 @@ -Restler -======= - -[![NPM](https://nodei.co/npm/restler.png?downloads=true&stars=true)](https://nodei.co/npm/restler/) +# Restler [![NPM Version](https://img.shields.io/npm/v/restler.svg?style=flat)](https://www.npmjs.com/package/restler) ![Node Version](https://img.shields.io/node/v/restler.svg?style=flat) ![Downloads](https://img.shields.io/npm/dm/restler.svg?style=flat) (C) Dan Webb (dan@danwebb.net/@danwrong) 2011, Licensed under the MIT-LICENSE -An HTTP client library for node.js (0.10.x and up). Hides most of the complexity of creating and using http.Client. +An HTTP client library for node.js. Hides most of the complexity of creating and using http.Client. See [Version History](https://github.com/danwrong/restler/wiki/Version-History) for changes From 79a08d90ff96821cef345c408dff55bbc747fbda Mon Sep 17 00:00:00 2001 From: Jonathan Bender Date: Thu, 22 Jan 2015 12:03:25 -0500 Subject: [PATCH 48/49] Keep old style for headers --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e1b3bb..79595aa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# Restler [![NPM Version](https://img.shields.io/npm/v/restler.svg?style=flat)](https://www.npmjs.com/package/restler) ![Node Version](https://img.shields.io/node/v/restler.svg?style=flat) ![Downloads](https://img.shields.io/npm/dm/restler.svg?style=flat) +Restler [![NPM Version](https://img.shields.io/npm/v/restler.svg?style=flat)](https://www.npmjs.com/package/restler) ![Node Version](https://img.shields.io/node/v/restler.svg?style=flat) ![Downloads](https://img.shields.io/npm/dm/restler.svg?style=flat) +======= (C) Dan Webb (dan@danwebb.net/@danwrong) 2011, Licensed under the MIT-LICENSE From 9a4d5a6304f42492512abc2d7204acf2f870dfeb Mon Sep 17 00:00:00 2001 From: Zack Birkenbuel Date: Mon, 30 Mar 2015 12:43:45 -0700 Subject: [PATCH 49/49] missing one change in merge --- lib/restler.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/restler.js b/lib/restler.js index 29c8b3e..8a378b0 100644 --- a/lib/restler.js +++ b/lib/restler.js @@ -263,8 +263,8 @@ mixin(Request.prototype, { self.request.end(); }); } else { - if (this.options.data) { - this.request.write(this.options.data, this.options.encoding || 'utf8'); + if (this.data) { + this.request.write(this.data, this.options.encoding || 'utf8'); } this.request.end(); }