purescript-installer
Version:
Installs the PureScript compiler
207 lines (164 loc) • 5.3 kB
JavaScript
// 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.
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