UNPKG

purescript-installer

Version:
207 lines (164 loc) 5.3 kB
// Copyright 2010-2012 Mikeal Rogers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // This is a heavily lobotomized version of request@2.88.2, with no // external dependencies and keeping only the functionality we use. 'use strict' var http = require('http') var https = require('https') var stream = require('stream') var url = require('url') var util = require('util') function Request ({ uri, headers }) { var self = this stream.Stream.call(self) self.uri = uri self.headers = headers self.readable = true self.maxRedirects = 10 self.redirectsFollowed = 0 self.init() } util.inherits(Request, stream.Stream) Request.prototype.init = function () { // init() contains all the code to setup the request object. // the actual outgoing request is not started until start() is called // this function is called from both the constructor and on redirect. var self = this self.headers = Object.assign({}, self.headers) if (self.uri.path) { self.path = self.uri.path } else { self.path = self.uri.pathname + (self.uri.search || '') } var protocol = self.uri.protocol var defaultModules = {'http:': http, 'https:': https} self.httpModule = defaultModules[protocol] if (!self.httpModule) { return self.emit('error', new Error('Invalid protocol: ' + protocol)) } setImmediate(function () { self.start() }) } Request.prototype.start = function () { // start() is called once we are ready to send the outgoing HTTP request. // this is usually called on the first write(), end() or on nextTick() var self = this if (self._started) { return } self._started = true var reqOptions = { headers: self.headers, host: self.uri.hostname, port: self.uri.port, path: self.path, } try { self.req = self.httpModule.request(reqOptions) } catch (err) { self.emit('error', err) return } self.req.on('response', self.onRequestResponse.bind(self)) self.req.on('error', function (error) { self.emit('error', error) }) self.req.on('drain', function () { self.emit('drain') }) self.req.on('socket', function (socket) { self.emit('socket', socket) }) self.req.end() } Request.prototype.onRequestResponse = function (response) { var self = this self.response = response response.request = self if (self.tryRedirect(response)) { return // Ignore the rest of the response } else { // Be a good stream and emit end when the response is finished. // Hack to emit end on close because of a core bug that never fires end response.on('close', function () { if (!self._ended) { self.response.emit('end') } }) response.once('end', function () { self._ended = true }) var responseContent = response if (self._paused) { responseContent.pause() } self.responseContent = responseContent self.emit('response', response) responseContent.on('data', function (chunk) { self.emit('data', chunk) }) responseContent.once('end', function (chunk) { self.emit('end', chunk) }) responseContent.on('error', function (error) { self.emit('error', error) }) responseContent.on('close', function () { self.emit('close') }) } } Request.prototype.tryRedirect = function (response) { var self = this if (response.statusCode < 300 || response.statusCode >= 400 || !('location' in response.headers)) { return false } var redirectTo = response.headers.location // ignore any potential response body. it cannot possibly be useful // to us at this point. // response.resume should be defined, but check anyway before calling. Workaround for browserify. if (response.resume) { response.resume() } if (self.redirectsFollowed >= self.maxRedirects) { self.emit('error', new Error('Exceeded maxRedirects. Probably stuck in a redirect loop ' + self.uri.href)) return false } self.redirectsFollowed += 1 if (!isUrl.test(redirectTo)) { redirectTo = url.resolve(self.uri.href, redirectTo) } self.headers.referer = self.uri.href self.uri = url.parse(redirectTo) delete self.req delete self._started self.init() return true } // Stream API Request.prototype.pause = function () { var self = this if (!self.responseContent) { self._paused = true } else { self.responseContent.pause() } } Request.prototype.resume = function () { var self = this if (!self.responseContent) { self._paused = false } else { self.responseContent.resume() } } Request.prototype.destroy = function () { var self = this if (self.response) { self.response.destroy() } } var isUrl = /^https?:/ function request (params) { return new Request(params) } // Exports module.exports = request