Created
April 24, 2013 03:17
-
-
Save ForbesLindesay/5449331 to your computer and use it in GitHub Desktop.
First stab at a plugable request library with promises and v0.10 streams
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var url = require('url'); | |
| var http = require('http'); | |
| var https = require('https'); | |
| var Promise = require('promise'); | |
| var sprom = require('sprom'); | |
| var Duplex = require('./lib/duplex'); | |
| var wrap = require('./lib/wrap'); | |
| var through = require('./lib/through'); | |
| //https://github.com/substack/hyperquest/archive/master.zip | |
| function Request(method, uri) { | |
| if (typeof uri === 'object') { | |
| uri = url.format(uri); | |
| } | |
| this.uri = uri; | |
| this.middleware = []; | |
| this._headers = {}; | |
| this._ws = through(); | |
| this._rs = through(); | |
| var self = this; | |
| Duplex.call(this, this._ws, this._rs); | |
| Promise.call(this, function (resolve, reject) { | |
| process.nextTick(function () { | |
| resolve(self._hook('preRequest').then(function () { | |
| return self._doRequest() | |
| }).then(function (res) { | |
| return self._hook('postResponse', res); | |
| })); | |
| }); | |
| }); | |
| this.on('pipe', function () { | |
| self._piped = true; | |
| }); | |
| } | |
| Request.prototype = Object.create(Promise.prototype); | |
| Request.prototype.constructor = Request; | |
| for (var key in Duplex.prototype) { | |
| if (key != 'constructor') { | |
| Request.prototype[key] = Duplex.prototype[key]; | |
| } | |
| } | |
| Request.prototype._doRequest = function () { | |
| var self = this; | |
| var u = url.parse(self.uri); | |
| var interface = (u.protocol === 'https:') ? https : http; | |
| var req = interface.request({ | |
| method: self.method, | |
| host: u.hostname, | |
| port: Number(u.port), | |
| path: u.path, | |
| agent: false, | |
| headers: self._headers | |
| }); | |
| var res = self._getResponse(req); | |
| return self._hook('postRequest', req) | |
| .then(function () { | |
| if (!self._piped) { | |
| req.end(); | |
| } else { | |
| self._ws.pipe(req); | |
| } | |
| return res; | |
| }); | |
| }; | |
| Request.prototype._getResponse = function (req) { | |
| var self = this; | |
| return promise(function (resolve, reject) { | |
| req.on('response', function (res) { | |
| res.body = wrap(res); | |
| var buf = null; | |
| res.buffer = function () { | |
| if (buf) return buf; | |
| return buf = sprom(res.body); | |
| } | |
| resolve(res); | |
| }) | |
| }) | |
| .then(function (res) { | |
| return self._hook('preResponse', res) | |
| }); | |
| }; | |
| /** | |
| * Registers middlware and returns this | |
| * | |
| * @param {Object} middleware | |
| * @api public | |
| */ | |
| Request.prototype.use = function (middleware) { | |
| for (var i = 0; i < arguments.length; i++) { | |
| this.middleware.push(arguments[i]); | |
| } | |
| return this; | |
| }; | |
| /** | |
| * Calls all the hooks of a given name | |
| * | |
| * @param {String} name | |
| * @param {Any} arg | |
| * @api private | |
| */ | |
| Request.prototype._hook = function (name, arg) { | |
| var self = this; | |
| var middleware = self.middleware; | |
| next(0, arg); | |
| function next(i, arg) { | |
| if (i >= middleware.length) return new Promise(function (resolve) { resolve(arg); }); | |
| if (typeof middleware[i][name] !== 'function') return next(i + 1, arg); | |
| return new Promise(function (resolve) { resolve(middleware[i][name].apply(self, arg)); }) | |
| .then(function (arg) { | |
| return next(i + 1, arg); | |
| }); | |
| } | |
| }; | |
| function bufferResponse() { | |
| return { | |
| preResponse: function (res) { | |
| return res.buffer() | |
| .then(function (buf) { | |
| res.body = buf; | |
| return res; | |
| }); | |
| } | |
| } | |
| } | |
| function handleRedirects() { | |
| return { | |
| preResponse: function (res) { | |
| if (res.statusCode === 303 || res.statusCode === 302 || res.statusCode === 301) { | |
| if (this.method !== 'HEAD') this.method = 'GET'; | |
| this.uri = res.headers.location; | |
| //redo the request with the new location | |
| this._piped = false;//don't redo the body | |
| return this._doRequest(); | |
| } else if (res.statusCode === 307 || res.statusCode === 308) { | |
| this.uri = res.headers.location; | |
| this._piped = false;//don't redo the body | |
| return this._doRequest(); | |
| } else { | |
| return res; | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment