Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into gh-pages
Browse files Browse the repository at this point in the history
* origin/master:
  Normalize spelling of SuperAgent in docs
  Remove superagent-promise-plugin from plugin list
  Fixes #857
  Test trailing junk
  Fixed test
  Formatting
  Drop workaround for ancient Node
  No slacking when constructing JSON.
  Added authentication with client certificates.
  Update Readme.md
  Add .catch for more Promise-like interface
  Include the root file, so that patched agent works
  Correct event.direction in uploads
  Return this when overwriting the response object's on() method
  Changelog
  v2.2.0
  add 'timedout' property to node Request instance
  Add tests to reproduce error when used only .catch without .then
  Unify null querystring values in node and browser environments.
  v2.1.0
  • Loading branch information
kornelski committed Sep 4, 2016
2 parents fa4d65d + 61b000d commit cff1d4d
Show file tree
Hide file tree
Showing 24 changed files with 588 additions and 240 deletions.
12 changes: 8 additions & 4 deletions History.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# 2.1.0-beta
# 2.2.0

* Wait for async parsers to avoid double callback (Kornel Lesiński)
* DRY parser selection and response creation code (Kornel Lesiński)
* Treat multipart like other parsers (Kornel Lesiński)
* Added `timedout` property to node Request instance (Alexander Pope)
* Unified `null` querystring values in node and browser environments. (George Chung)

# 2.1.0

* Refactored async parsers. Now the `end` callback waits for async parsers to finish (Kornel Lesiński)
* Errors thrown in `.end()` callback don't cause the callback to be called twice (Kornel Lesiński)
* Added `headers` to `toJSON()` (Tao)

# 2.0.0

Expand Down
13 changes: 6 additions & 7 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ component:
$ component install visionmedia/superagent
```

Works with [browserify](https://github.com/substack/node-browserify) and should work with [webpack](https://github.com/visionmedia/superagent/wiki/Superagent-for-Webpack)
Works with [browserify](https://github.com/substack/node-browserify) and should work with [webpack](https://github.com/visionmedia/superagent/wiki/SuperAgent-for-Webpack)

```js
request
Expand Down Expand Up @@ -46,7 +46,7 @@ Even though IE9 is supported, a polyfill for `window.FormData` is required for `

# Plugins

Superagent is easily extended via plugins.
SuperAgent is easily extended via plugins.

```js
var nocache = require('superagent-no-cache');
Expand All @@ -68,18 +68,17 @@ Existing plugins:
* [superagent-suffix](https://github.com/timneutkens1/superagent-suffix) - suffix URLs with a given path
* [superagent-mock](https://github.com/M6Web/superagent-mock) - simulate HTTP calls by returning data fixtures based on the requested URL
* [superagent-mocker](https://github.com/shuvalov-anton/superagent-mocker) — simulate REST API
* [superagent-cache](https://github.com/jpodwys/superagent-cache) - superagent with built-in, flexible caching
* [superagent-cache](https://github.com/jpodwys/superagent-cache) - SuperAgent with built-in, flexible caching (compatible with SuperAgent `1.x`)
* [superagent-jsonapify](https://github.com/alex94puchades/superagent-jsonapify) - A lightweight [json-api](http://jsonapi.org/format/) client addon for superagent
* [superagent-serializer](https://github.com/zzarcon/superagent-serializer) - Converts server payload into different cases
* [superagent-promise-plugin](https://github.com/jomaxx/superagent-promise-plugin) - Shims req.end to return a promise when executed with no callback.
* [superagent-use](https://github.com/koenpunt/superagent-use) - A client addon to apply plugins to all requests.
* [superagent-httpbackend](https://www.npmjs.com/package/superagent-httpbackend) - stub out requests using AngularJS' $httpBackend syntax
* [superagent-throttle](https://github.com/leviwheatcroft/superagent-throttle) - queues and intelligently throttles requests
* [superagent-charset](https://github.com/magicdawn/superagent-charset) - add charset support for node's superagent
* [superagent-charset](https://github.com/magicdawn/superagent-charset) - add charset support for node's SuperAgent

Please prefix your plugin with `superagent-*` so that it can easily be found by others.

For superagent extensions such as couchdb and oauth visit the [wiki](https://github.com/visionmedia/superagent/wiki).
For SuperAgent extensions such as couchdb and oauth visit the [wiki](https://github.com/visionmedia/superagent/wiki).

## Running node tests

Expand Down Expand Up @@ -119,7 +118,7 @@ Edit tests and refresh your browser. You do not have to restart the test runner.

**npm (for browser standalone)** When we publish versions to npm, we run `make superagent.js` which generates the standalone `superagent.js` file via `browserify`, and this file is included in the package published to npm (but this file is never checked into the git repository). If users want to install via npm but serve a single `.js` file directly to the browser, the `node_modules/superagent/superagent.js` is a standalone browserified file ready to go for that purpose. It is not minified.

**npm (for browserify)** is handled via the `package.json` `browser` field which allows users to install superagent via npm, reference it from their browser code with `require('superagent')`, and then build their own application bundle via `browserify`, which will use `lib/client.js` as the superagent entrypoint.
**npm (for browserify)** is handled via the `package.json` `browser` field which allows users to install SuperAgent via npm, reference it from their browser code with `require('superagent')`, and then build their own application bundle via `browserify`, which will use `lib/client.js` as the SuperAgent entrypoint.

**bower** is configured via the `bower.json` file. Bower installs files directly from git/github without any transformation.

Expand Down
18 changes: 9 additions & 9 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# SuperAgent

Super Agent is light-weight progressive ajax API crafted for flexibility, readability, and a low learning curve after being frustrated with many of the existing request APIs. It also works with Node.js!
SuperAgent is light-weight progressive ajax API crafted for flexibility, readability, and a low learning curve after being frustrated with many of the existing request APIs. It also works with Node.js!

request
.post('/api/pet')
Expand Down Expand Up @@ -199,7 +199,7 @@ You can also use the `.query()` method for HEAD requests. The following will pro

## Serializing request body

Superagent will automatically serialize JSON and forms. If you want to send the payload in a custom format, you can replace the built-in serialization with `.serialize()` method.
SuperAgent will automatically serialize JSON and forms. If you want to send the payload in a custom format, you can replace the built-in serialization with `.serialize()` method.

## Setting Accept

Expand Down Expand Up @@ -227,7 +227,7 @@ In a similar fashion to the `.type()` method it is also possible to set the Acce

## Parsing response bodies

Super Agent will parse known response-body data for you, currently supporting `application/x-www-form-urlencoded`, `application/json`, and `multipart/form-data`.
SuperAgent will parse known response-body data for you, currently supporting `application/x-www-form-urlencoded`, `application/json`, and `multipart/form-data`.

You can set a custom parser (that takes precedence over built-in parsers) with the `.buffer(true).parse(fn)` method. If response buffering is not enabled (`.buffer(false)`) then the `response` event will be emitted without waiting for the body parser to finish, so `response.body` won't be available.

Expand Down Expand Up @@ -365,7 +365,7 @@ In a similar fashion to the `.type()` method it is also possible to set the Acce

## Multipart requests

Super Agent is also great for _building_ multipart requests for which it provides methods `.attach()` and `.field()`.
SuperAgent is also great for _building_ multipart requests for which it provides methods `.attach()` and `.field()`.

### Attaching files

Expand Down Expand Up @@ -454,23 +454,23 @@ Your callback function will always be passed two arguments: error and response.

## Promise and Generator support

Superagent's request is a "thenable" object that's compatible with JavaScript promises and `async`/`await` syntax.
SuperAgent's request is a "thenable" object that's compatible with JavaScript promises and `async`/`await` syntax.

Libraries like [co](https://github.com/tj/co) or a web framework like [koa](https://github.com/koajs/koa) can `yield` on any superagent method:
Libraries like [co](https://github.com/tj/co) or a web framework like [koa](https://github.com/koajs/koa) can `yield` on any SuperAgent method:

var res = yield request
.get('http://local')
.auth('tobi', 'learnboost')

Note that superagent expects the global `Promise` object to be present. You'll need a polyfill to use promises in Internet Explorer or Node.js 0.10.
Note that SuperAgent expects the global `Promise` object to be present. You'll need a polyfill to use promises in Internet Explorer or Node.js 0.10.


## Browser and node versions

Superagent has two implementations: one for web browsers (using XHR) and one for Node.JS (using core http module). By default Browserify and WebPack will pick the browser version.
SuperAgent has two implementations: one for web browsers (using XHR) and one for Node.JS (using core http module). By default Browserify and WebPack will pick the browser version.

If want to use WebPack to compile code for Node.JS, you *must* specify [node target](webpack.github.io/docs/configuration.html#target) in its configuration.

### Using browser version in electron

[Electron](http://electron.atom.io/) developers report if you would prefer to use the browser version of superagent instead of the Node version, you can `require('superagent/superagent')`. Your requests will now show up in the Chrome developer tools Network tab. Note this environment is not covered by automated test suite and not officially supported.
[Electron](http://electron.atom.io/) developers report if you would prefer to use the browser version of SuperAgent instead of the Node version, you can `require('superagent/superagent')`. Your requests will now show up in the Chrome developer tools Network tab. Note this environment is not covered by automated test suite and not officially supported.
18 changes: 9 additions & 9 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<ul id="menu"></ul>
<div id="content">
<h1 id="superagent">SuperAgent</h1>
<p> Super Agent is light-weight progressive ajax API crafted for flexibility, readability, and a low learning curve after being frustrated with many of the existing request APIs. It also works with Node.js!</p>
<p> SuperAgent is light-weight progressive ajax API crafted for flexibility, readability, and a low learning curve after being frustrated with many of the existing request APIs. It also works with Node.js!</p>
<pre><code> request
.post(&#39;/api/pet&#39;)
.send({ name: &#39;Manny&#39;, species: &#39;cat&#39; })
Expand Down Expand Up @@ -153,7 +153,7 @@ <h2 id="setting-the-content-type">Setting the Content-Type</h2>
request.post(&#39;/user&#39;)
.type(&#39;png&#39;)
</code></pre><h2 id="serializing-request-body">Serializing request body</h2>
<p>Superagent will automatically serialize JSON and forms. If you want to send the payload in a custom format, you can replace the built-in serialization with <code>.serialize()</code> method.</p>
<p>SuperAgent will automatically serialize JSON and forms. If you want to send the payload in a custom format, you can replace the built-in serialization with <code>.serialize()</code> method.</p>
<h2 id="setting-accept">Setting Accept</h2>
<p>In a similar fashion to the <code>.type()</code> method it is also possible to set the Accept header via the short hand method <code>.accept()</code>. Which references <code>request.types</code> as well allowing you to specify either the full canonicalized MIME type name as type/subtype, or the extension suffix form as &quot;xml&quot;, &quot;json&quot;, &quot;png&quot;, etc for convenience:</p>
<pre><code> request.get(&#39;/user&#39;)
Expand All @@ -173,7 +173,7 @@ <h2 id="setting-accept">Setting Accept</h2>
.send({ post: &#39;data&#39;, here: &#39;wahoo&#39; })
.end(callback);
</code></pre><h2 id="parsing-response-bodies">Parsing response bodies</h2>
<p> Super Agent will parse known response-body data for you, currently supporting <code>application/x-www-form-urlencoded</code>, <code>application/json</code>, and <code>multipart/form-data</code>.</p>
<p> SuperAgent will parse known response-body data for you, currently supporting <code>application/x-www-form-urlencoded</code>, <code>application/json</code>, and <code>multipart/form-data</code>.</p>
<p> You can set a custom parser (that takes precedence over built-in parsers) with the <code>.buffer(true).parse(fn)</code> method. If response buffering is not enabled (<code>.buffer(false)</code>) then the <code>response</code> event will be emitted without waiting for the body parser to finish, so <code>response.body</code> won&#39;t be available.</p>
<h3 id="json-urlencoded">JSON / Urlencoded</h3>
<p> The property <code>res.body</code> is the parsed object, for example if a request responded with the JSON string &#39;{&quot;user&quot;:{&quot;name&quot;:&quot;tobi&quot;}}&#39;, <code>res.body.user.name</code> would be &quot;tobi&quot;. Likewise the x-www-form-urlencoded value of &quot;user[name]=tobi&quot; would yield the same result.</p>
Expand Down Expand Up @@ -268,7 +268,7 @@ <h2 id="authentication">Authentication</h2>
var req = request.get(&#39;/some.json&#39;);
req.pipe(stream);
</code></pre><h2 id="multipart-requests">Multipart requests</h2>
<p> Super Agent is also great for <em>building</em> multipart requests for which it provides methods <code>.attach()</code> and <code>.field()</code>.</p>
<p> SuperAgent is also great for <em>building</em> multipart requests for which it provides methods <code>.attach()</code> and <code>.field()</code>.</p>
<h3 id="attaching-files">Attaching files</h3>
<p> As mentioned a higher-level API is also provided, in the form of <code>.attach(name, [path], [filename])</code> and <code>.field(name, value)</code>. Attaching several files is simple, you can also provide a custom filename for the attachment, otherwise the basename of the attached file is used.</p>
<pre><code>request
Expand Down Expand Up @@ -334,17 +334,17 @@ <h2 id="cors">CORS</h2>
// all other error types we handle generically
}
</code></pre><h2 id="promise-and-generator-support">Promise and Generator support</h2>
<p>Superagent&#39;s request is a &quot;thenable&quot; object that&#39;s compatible with JavaScript promises and <code>async</code>/<code>await</code> syntax.</p>
<p>Libraries like <a href="https://github.com/tj/co">co</a> or a web framework like <a href="https://github.com/koajs/koa">koa</a> can <code>yield</code> on any superagent method:</p>
<p>SuperAgent&#39;s request is a &quot;thenable&quot; object that&#39;s compatible with JavaScript promises and <code>async</code>/<code>await</code> syntax.</p>
<p>Libraries like <a href="https://github.com/tj/co">co</a> or a web framework like <a href="https://github.com/koajs/koa">koa</a> can <code>yield</code> on any SuperAgent method:</p>
<pre><code>var res = yield request
.get(&#39;http://local&#39;)
.auth(&#39;tobi&#39;, &#39;learnboost&#39;)
</code></pre><p>Note that superagent expects the global <code>Promise</code> object to be present. You&#39;ll need a polyfill to use promises in Internet Explorer or Node.js 0.10.</p>
</code></pre><p>Note that SuperAgent expects the global <code>Promise</code> object to be present. You&#39;ll need a polyfill to use promises in Internet Explorer or Node.js 0.10.</p>
<h2 id="browser-and-node-versions">Browser and node versions</h2>
<p>Superagent has two implementations: one for web browsers (using XHR) and one for Node.JS (using core http module). By default Browserify and WebPack will pick the browser version.</p>
<p>SuperAgent has two implementations: one for web browsers (using XHR) and one for Node.JS (using core http module). By default Browserify and WebPack will pick the browser version.</p>
<p>If want to use WebPack to compile code for Node.JS, you <em>must</em> specify <a href="webpack.github.io/docs/configuration.html#target">node target</a> in its configuration.</p>
<h3 id="using-browser-version-in-electron">Using browser version in electron</h3>
<p><a href="http://electron.atom.io/">Electron</a> developers report if you would prefer to use the browser version of superagent instead of the Node version, you can <code>require(&#39;superagent/superagent&#39;)</code>. Your requests will now show up in the Chrome developer tools Network tab. Note this environment is not covered by automated test suite and not officially supported.</p>
<p><a href="http://electron.atom.io/">Electron</a> developers report if you would prefer to use the browser version of SuperAgent instead of the Node version, you can <code>require(&#39;superagent/superagent&#39;)</code>. Your requests will now show up in the Chrome developer tools Network tab. Note this environment is not covered by automated test suite and not officially supported.</p>

</div>
<a href="http://github.com/visionmedia/superagent"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_white_ffffff.png" alt="Fork me on GitHub"></a>
Expand Down
52 changes: 27 additions & 25 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ function serialize(obj) {
if (!isObject(obj)) return obj;
var pairs = [];
for (var key in obj) {
if (null != obj[key]) {
pushEncodedKeyValuePair(pairs, key, obj[key]);
}
pushEncodedKeyValuePair(pairs, key, obj[key]);
}
return pairs.join('&');
}
Expand All @@ -87,18 +85,22 @@ function serialize(obj) {
*/

function pushEncodedKeyValuePair(pairs, key, val) {
if (Array.isArray(val)) {
return val.forEach(function(v) {
pushEncodedKeyValuePair(pairs, key, v);
});
} else if (isObject(val)) {
for(var subkey in val) {
pushEncodedKeyValuePair(pairs, key + '[' + subkey + ']', val[subkey]);
if (val != null) {
if (Array.isArray(val)) {
val.forEach(function(v) {
pushEncodedKeyValuePair(pairs, key, v);
});
} else if (isObject(val)) {
for(var subkey in val) {
pushEncodedKeyValuePair(pairs, key + '[' + subkey + ']', val[subkey]);
}
} else {
pairs.push(encodeURIComponent(key)
+ '=' + encodeURIComponent(val));
}
return;
} else if (val === null) {
pairs.push(encodeURIComponent(key));
}
pairs.push(encodeURIComponent(key)
+ '=' + encodeURIComponent(val));
}

/**
Expand Down Expand Up @@ -782,24 +784,24 @@ Request.prototype.end = function(fn){
};

// progress
var handleProgress = function(e){
var handleProgress = function(direction, e) {
if (e.total > 0) {
e.percent = e.loaded / e.total * 100;
}
e.direction = 'download';
e.direction = direction;
self.emit('progress', e);
};
if (this.hasListeners('progress')) {
xhr.onprogress = handleProgress;
}
try {
if (xhr.upload && this.hasListeners('progress')) {
xhr.upload.onprogress = handleProgress;
if (this.hasListeners('progress')) {
try {
xhr.onprogress = handleProgress.bind(null, 'download');
if (xhr.upload) {
xhr.upload.onprogress = handleProgress.bind(null, 'upload');
}
} catch(e) {
// Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.
// Reported here:
// https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context
}
} catch(e) {
// Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist.
// Reported here:
// https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context
}

// timeout
Expand Down
10 changes: 8 additions & 2 deletions lib/node/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
var CookieJar = require('cookiejar').CookieJar;
var CookieAccess = require('cookiejar').CookieAccessInfo;
var parse = require('url').parse;
var request = require('./index');
var request = require('../..');
var methods = require('methods');

/**
Expand All @@ -23,7 +23,11 @@ module.exports = Agent;

function Agent(options) {
if (!(this instanceof Agent)) return new Agent(options);
if (options) this._ca = options.ca;
if (options) {
this._ca = options.ca;
this._key = options.key;
this._cert = options.cert;
}
this.jar = new CookieJar;
}

Expand Down Expand Up @@ -70,6 +74,8 @@ methods.forEach(function(method){
Agent.prototype[name] = function(url, fn){
var req = request(method, url);
req.ca(this._ca);
req.key(this._key);
req.cert(this._cert);

req.on('response', this._saveCookies.bind(this));
req.on('redirect', this._saveCookies.bind(this));
Expand Down

0 comments on commit cff1d4d

Please sign in to comment.