Created
February 17, 2016 15:12
-
-
Save darkyen/c29f07771d763602f5c6 to your computer and use it in GitHub Desktop.
cannot parse
This file contains 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
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
(function (process){ | |
'use strict'; | |
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | |
var _plivo = require('plivo'); | |
var _plivo2 = _interopRequireDefault(_plivo); | |
var _express = require('express'); | |
var _express2 = _interopRequireDefault(_express); | |
var _bodyParser = require('body-parser'); | |
var _bodyParser2 = _interopRequireDefault(_bodyParser); | |
var _webtaskTools = require('webtask-tools'); | |
var _webtaskTools2 = _interopRequireDefault(_webtaskTools); | |
var app = (0, _express2['default'])(); | |
app.use(_bodyParser2['default'].urlencoded({ extended: true })); | |
app.set('port', process.env.PORT || 5000); | |
// This file will be played when a caller presses 2. | |
var PLIVO_SONG = "https://s3.amazonaws.com/plivocloud/music.mp3"; | |
// This is the message that Plivo reads when the caller dials in | |
var IVR_MESSAGE1 = "Welcome to the Plivo IVR Demo App. Press 1 to listen to a pre recorded text in different languages. Press 2 to listen to a song."; | |
var IVR_MESSAGE2 = "Press 1 for English. Press 2 for French. Press 3 for Russian"; | |
// This is the message that Plivo reads when the caller does nothing at all | |
var NO_INPUT_MESSAGE = "Sorry, I didn't catch that. Please hangup and try again later."; | |
// This is the message that Plivo reads when the caller inputs a wrong number. | |
var WRONG_INPUT_MESSAGE = "Sorry, you've entered an invalid input."; | |
app.get('/response/ivr/', function (request, response) { | |
var r = _plivo2['default'].Response(); | |
var getdigits_action_url, params, getDigits; | |
getdigits_action_url = request.protocol + '://' + request.headers.host + '/response/ivr/'; | |
params = { | |
'action': getdigits_action_url, | |
'method': 'POST', | |
'timeout': '7', | |
'numDigits': '1', | |
'retries': '1' | |
}; | |
getDigits = r.addGetDigits(params); | |
getDigits.addSpeak(IVR_MESSAGE1); | |
r.addSpeak(NO_INPUT_MESSAGE); | |
console.log(r.toXML()); | |
response.set({ 'Content-Type': 'text/xml' }); | |
response.send(r.toXML()); | |
}); | |
app.post('/response/ivr/', function (request, response) { | |
var r = _plivo2['default'].Response(); | |
var getdigits_action_url, params, getDigits; | |
var digit = request.body.Digits; | |
console.log(digit); | |
if (digit === '1') { | |
getdigits_action_url = request.protocol + '://' + request.headers.host + '/response/tree/'; | |
params = { | |
'action': getdigits_action_url, | |
'method': 'POST', | |
'timeout': '7', | |
'numDigits': '1', | |
'retries': '1' | |
}; | |
getDigits = r.addGetDigits(params); | |
getDigits.addSpeak(IVR_MESSAGE2); | |
r.addSpeak(NO_INPUT_MESSAGE); | |
} else if (digit === '2') { | |
r.addPlay(PLIVO_SONG); | |
} else { | |
r.addSpeak(WRONG_INPUT_MESSAGE); | |
} | |
console.log(r.toXML()); | |
response.set({ 'Content-Type': 'text/xml' }); | |
response.send(r.toXML()); | |
}); | |
app.all('/response/tree/', function (request, response) { | |
var r = _plivo2['default'].Response(); | |
var text, params; | |
var digit = request.body.Digits || request.query.Digits; | |
if (digit === "1") { | |
text = "This message is being read out in English"; | |
params = { 'language': 'en-US' }; | |
r.addSpeak(text, params); | |
} else if (digit === "2") { | |
text = "Ce message est lu en français"; | |
params = { 'language': 'fr-FR' }; | |
r.addSpeak(text, params); | |
} else if (digit === "3") { | |
text = "Это сообщение было прочитано в России"; | |
params = { 'language': 'ru-RU' }; | |
r.addSpeak(text, params); | |
} else { | |
r.addSpeak(WRONG_INPUT_MESSAGE); | |
} | |
console.log(r.toXML()); | |
response.set({ 'Content-Type': 'text/xml' }); | |
response.send(r.toXML()); | |
}); | |
module.exports = _webtaskTools2['default'].fromExpress(app); | |
}).call(this,require('_process')) | |
},{"_process":undefined,"body-parser":undefined,"express":undefined,"plivo":2,"webtask-tools":undefined}],2:[function(require,module,exports){ | |
(function (process,Buffer){ | |
//Get required modules | |
var util = require('util'); | |
var crypto = require('crypto'); | |
var Request = require('request'); | |
var qs = require('querystring'); | |
var xmlBuilder = require('xmlbuilder'); | |
var doc = xmlBuilder.create(); | |
var plivo = {}; | |
plivo.options = {}; | |
plivo.options.host = 'api.plivo.com'; | |
plivo.options.version = 'v1'; | |
plivo.options.authId = ''; | |
plivo.options.authToken = ''; | |
var UserAgent = 'NodePlivo'; | |
// Generic Plivo Error | |
function PlivoError(msg) { | |
Error.call(this); | |
Error.captureStackTrace(this, arguments.callee); | |
this.message = (msg || '') + '\n'; | |
this.name = 'PlivoError'; | |
} | |
PlivoError.prototype = Error.prototype; | |
// Main request function | |
var request = function (action, method, params, callback, optional) { | |
if (optional) { | |
if (typeof params != 'object') { | |
if (typeof params == 'function') { | |
var callback = params; | |
} | |
var params = {}; | |
} | |
} | |
if (!callback) { | |
var callback = function() {}; | |
} | |
var err = null; | |
var path = 'https://' + plivo.options.host + '/' + plivo.options.version + '/Account/' + plivo.options.authId + '/' + action; | |
var auth = 'Basic ' + new Buffer(plivo.options.authId + ':' + plivo.options.authToken) | |
.toString('base64'); | |
var headers = { | |
'Authorization': auth, | |
'User-Agent': UserAgent, | |
'Content-Type': 'application/json' | |
}; | |
var request_options = { | |
uri: path, | |
headers: headers, | |
json: true, | |
}; | |
if (method == 'POST') { | |
var body = JSON.stringify(params); | |
request_options.json = true; | |
request_options.body = body; | |
Request.post(request_options, function (error, response, body) { | |
if (error || !response) { | |
return callback(500, body) | |
} | |
if (response.statusCode != 201) { | |
err = new PlivoError(error); | |
} | |
callback(response.statusCode, body); | |
}); | |
} else if (method == 'GET') { | |
request_options.qs = params; | |
Request.get(request_options, function (error, response, body) { | |
callback(response.statusCode, body); | |
}); | |
} else if (method == 'DELETE') { | |
Request.del(request_options, function (error, response, body) { | |
callback(response.statusCode, body); | |
}); | |
} else if (method == 'PUT') { | |
var body = JSON.stringify(params); | |
request_options.json = true; | |
request_options.body = body, | |
Request.put(request_options, function (error, response, body) { | |
callback(response.statusCode, body); | |
}); | |
} | |
}; | |
// Exposing generic request functionality as well. | |
plivo.request = request; | |
// For verifying the plivo server signature | |
plivo.create_signature = function (url, params) { | |
var toSign = url; | |
Object.keys(params).sort().forEach(function(key) { | |
toSign += key + params[key]; | |
}); | |
var signature = crypto | |
.createHmac('sha1', plivo.options.authToken) | |
.update(new Buffer(toSign, 'utf-8')) | |
.digest('base64'); | |
return signature; | |
}; | |
// Express middleware for verifying signature | |
plivo.middleware = function(options) { | |
return function (req, res, next) { | |
if (process.env.NODE_ENV === 'test') return next() | |
var toSign; | |
if (options && options.host) { | |
toSign = options.host; | |
} else { | |
toSign = req.protocol + '://' + req.host; | |
} | |
toSign += req.originalUrl; | |
var expectedSignature = plivo.create_signature(toSign, req.body); | |
if (expectedSignature === req.header('X-Plivo-Signature')) { | |
next(); | |
} else { | |
var msg = 'Invalid Plivo Signature toSign=' + toSign + ', ' + | |
'expected=' + expectedSignature + ', ' + | |
'actual=' + req.header('X-Plivo-Signature'); | |
next(new Error(msg)); | |
} | |
}; | |
}; | |
// Calls | |
plivo.make_call = function (params, callback) { | |
var action = 'Call/'; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_cdrs = function (params, callback) { | |
var action = 'Call/'; | |
var method = 'GET'; | |
request(action, method, params, callback, true); | |
}; | |
plivo.get_cdr = function (params, callback) { | |
var action = 'Call/' + params['call_uuid'] + '/'; | |
delete params.call_uuid; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_live_calls = function (params, callback) { | |
var action = 'Call/'; | |
var method = 'GET'; | |
params.status = 'live'; | |
request(action, method, params, callback, true); | |
}; | |
plivo.get_live_call = function (params, callback) { | |
var action = 'Call/' + params['call_uuid'] + '/'; | |
delete params.call_uuid; | |
var method = 'GET'; | |
params.status = 'live'; | |
request(action, method, params, callback); | |
}; | |
plivo.transfer_call = function (params, callback) { | |
var action = 'Call/' + params['call_uuid'] + '/'; | |
delete params.call_uuid; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.hangup_all_calls = function (callback) { | |
var action = 'Call/'; | |
var method = 'DELETE'; | |
var params = {}; | |
request(action, method, params, callback); | |
}; | |
plivo.hangup_call = function (params, callback) { | |
var action = 'Call/' + params['call_uuid'] + '/'; | |
delete params.call_uuid; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
plivo.record = function (params, callback) { | |
var action = 'Call/' + params['call_uuid'] + '/Record/'; | |
delete params.call_uuid; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.record_stop = function (params, callback) { | |
var action = 'Call/' + params['call_uuid'] + '/Record/'; | |
delete params.call_uuid; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
plivo.play = function (params, callback) { | |
var action = 'Call/' + params['call_uuid'] + '/Play/'; | |
delete params.call_uuid; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.play_stop = function (params, callback) { | |
var action = 'Call/' + params['call_uuid'] + '/Play/'; | |
delete params.call_uuid; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
plivo.speak = function (params, callback) { | |
var action = 'Call/' + params['call_uuid'] + '/Speak/'; | |
delete params.call_uuid; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.speak_stop = function (params, callback) { | |
var action = 'Call/' + params['call_uuid'] + '/Speak/'; | |
delete params.call_uuid; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
plivo.send_digits = function (params, callback) { | |
var action = 'Call/' + params['call_uuid'] + '/DTMF/'; | |
delete params.call_uuid; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
// Request | |
plivo.hangup_request = function (params, callback) { | |
var action = 'Request/' + params['request_uuid'] + '/'; | |
delete params.request_uuid; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
// Conferences | |
plivo.get_live_conferences = function (params, callback) { | |
var action = 'Conference/'; | |
var method = 'GET'; | |
request(action, method, params, callback, true); | |
}; | |
plivo.get_live_conference = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/'; | |
delete params.conference_id; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.hangup_all_conferences = function (callback) { | |
var action = 'Conference/'; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
plivo.hangup_conference = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/'; | |
delete params.conference_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
plivo.hangup_conference_member = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/Member/' + params['member_id'] + '/'; | |
delete params.conference_id; | |
delete params.member_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
plivo.play_conference_member = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/Member/' + params['member_id'] + '/Play/'; | |
delete params.conference_id; | |
delete params.member_id; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.stop_play_conference_member = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/Member/' + params['member_id'] + '/Play/'; | |
delete params.conference_id; | |
delete params.member_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
plivo.speak_conference_member = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/Member/' + params['member_id'] + '/Speak/'; | |
console.log(action); | |
delete params.conference_id; | |
delete params.member_id; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.stop_speak_conference_member = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/Member/' + params['member_id'] + '/Speak/'; | |
delete params.conference_id; | |
delete params.member_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
plivo.deaf_conference_member = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/Member/' + params['member_id'] + '/Deaf/'; | |
delete params.conference_id; | |
delete params.member_id; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.undeaf_conference_member = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/Member/' + params['member_id'] + '/Deaf/'; | |
delete params.conference_id; | |
delete params.member_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
plivo.mute_conference_member = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/Member/' + params['member_id'] + '/Mute/'; | |
delete params.conference_id; | |
delete params.member_id; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.unmute_conference_member = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/Member/' + params['member_id'] + '/Mute/'; | |
delete params.conference_id; | |
delete params.member_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
plivo.kick_conference_member = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/Member/' + params['member_id'] + '/Kick/'; | |
delete params.conference_id; | |
delete params.member_id; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.record_conference = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/Record/'; | |
delete params.conference_id; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.stop_record_conference = function (params, callback) { | |
var action = 'Conference/' + params['conference_id'] + '/Record/'; | |
delete params.conference_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
// Accounts | |
plivo.get_account = function (params, callback) { | |
var action = ''; | |
var method = 'GET'; | |
request(action, method, params, callback, true); | |
}; | |
plivo.modify_account = function (params, callback) { | |
var action = ''; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_subaccounts = function (params, callback) { | |
var action = 'Subaccount/'; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_subaccount = function (params, callback) { | |
var action = 'Subaccount/' + params['subauth_id'] + '/'; | |
delete params.subauth_id; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.create_subaccount = function (params, callback) { | |
var action = 'Subaccount/'; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.modify_subaccount = function (params, callback) { | |
var action = 'Subaccount/' + params['subauth_id'] + '/'; | |
delete params.subauth_id; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.delete_subaccount = function (params, callback) { | |
var action = 'Subaccount/' + params['subauth_id'] + '/'; | |
delete params.subauth_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
// Applications | |
plivo.get_applications = function (params, callback) { | |
var action = 'Application/'; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_application = function (params, callback) { | |
var action = 'Application/' + params['app_id'] + '/'; | |
delete params.app_id; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.create_application = function (params, callback) { | |
var action = 'Application/'; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.modify_application = function (params, callback) { | |
var action = 'Application/' + params['app_id'] + '/'; | |
delete params.app_id; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.delete_application = function (params, callback) { | |
var action = 'Application/' + params['app_id'] + '/'; | |
delete params.app_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
// Recordings | |
plivo.get_recordings = function (params, callback) { | |
var action = 'Recording/'; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_recording = function (params, callback) { | |
var action = 'Recording/' + params['recording_id'] + '/'; | |
delete params.recording_id; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.delete_recording = function (params, callback) { | |
var action = 'Recording/' + params['recording_id'] + '/'; | |
delete params.recording_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
// Endpoints | |
plivo.get_endpoints = function (params, callback) { | |
var action = 'Endpoint/'; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_endpoint = function (params, callback) { | |
var action = 'Endpoint/' + params['endpoint_id'] + '/'; | |
delete params.endpoint_id; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.create_endpoint = function (params, callback) { | |
var action = 'Endpoint/'; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.modify_endpoint = function (params, callback) { | |
var action = 'Endpoint/' + params['endpoint_id'] + '/'; | |
delete params.endpoint_id; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.delete_endpoint = function (params, callback) { | |
var action = 'Endpoint/' + params['endpoint_id'] + '/'; | |
delete params.endpoint_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
// Numbers | |
plivo.get_numbers = function (params, callback) { | |
var action = 'Number/'; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_number_details = function (params, callback) { | |
var action = 'Number/' + params['number'] + '/'; | |
delete params.number; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.unrent_number = function (params, callback) { | |
var action = 'Number/' + params['number'] + '/'; | |
delete params.number; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_number_group = function (params, callback) { | |
var action = 'AvailableNumberGroup/'; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_number_group_details = function (params, callback) { | |
var action = 'AvailableNumberGroup/' + params['group_id'] + '/'; | |
delete params.group_id; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.rent_from_number_group = function (params, callback) { | |
var action = 'AvailableNumberGroup/' + params['group_id'] + '/'; | |
delete params.group_id; | |
var method = 'POST'; | |
request(action, method, params, callback, true); | |
}; | |
plivo.edit_number = function (params, callback) { | |
var action = 'Number/' + params['number'] + '/'; | |
delete params.number; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.link_application_number = function (params, callback) { | |
this.edit_number(params, callback); | |
}; | |
plivo.unlink_application_number = function (params, callback) { | |
params.app_id = null; | |
this.edit_number(params, callback); | |
}; | |
plivo.search_phone_numbers = function (params, callback) { | |
var action = 'PhoneNumber/'; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.buy_phone_number = function (params, callback) { | |
var action = 'PhoneNumber/' + params['number'] + '/'; | |
delete params.number; | |
var method = 'POST'; | |
request(action, method, params, callback, true); | |
}; | |
// Message | |
plivo.send_message = function (params, callback) { | |
var action = 'Message/'; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_messages = function (params, callback) { | |
var action = 'Message/'; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_message = function (params, callback) { | |
var action = 'Message/' + params['record_id'] + '/'; | |
delete params.record_id; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
// Incoming Carriers | |
plivo.get_incoming_carriers = function (params, callback) { | |
var action = 'IncomingCarrier/'; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_incoming_carrier = function (params, callback) { | |
var action = 'IncomingCarrier/' + params['carrier_id'] + '/'; | |
delete params.carrier_id; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.create_incoming_carrier = function (params, callback) { | |
var action = 'IncomingCarrier/'; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.modify_incoming_carrier = function (params, callback) { | |
var action = 'IncomingCarrier/' + params['carrier_id'] + '/'; | |
delete params.carrier_id; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.delete_incoming_carrier = function (params, callback) { | |
var action = 'IncomingCarrier/' + params['carrier_id'] + '/'; | |
delete params.carrier_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
// Outgoing Carriers | |
plivo.get_outgoing_carriers = function (params, callback) { | |
var action = 'OutgoingCarrier/'; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_outgoing_carrier = function (params, callback) { | |
var action = 'OutgoingCarrier/' + params['carrier_id'] + '/'; | |
delete params.carrier_id; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.create_outgoing_carrier = function (params, callback) { | |
var action = 'OutgoingCarrier/'; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.modify_outgoing_carrier = function (params, callback) { | |
var action = 'OutgoingCarrier/' + params['carrier_id'] + '/'; | |
delete params.carrier_id; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.delete_outgoing_carrier = function (params, callback) { | |
var action = 'OutgoingCarrier/' + params['carrier_id'] + '/'; | |
delete params.carrier_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
// Outgoing Carrier Routings | |
plivo.get_outgoing_carrier_routings = function (params, callback) { | |
var action = 'OutgoingCarrierRouting/'; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.get_outgoing_carrier_routing = function (params, callback) { | |
var action = 'OutgoingCarrierRouting/' + params['routing_id'] + '/'; | |
delete params.routing_id; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
plivo.create_outgoing_carrier_routing = function (params, callback) { | |
var action = 'OutgoingCarrierRouting/'; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.modify_outgoing_carrier_routing = function (params, callback) { | |
var action = 'OutgoingCarrierRouting/' + params['routing_id'] + '/'; | |
delete params.routing_id; | |
var method = 'POST'; | |
request(action, method, params, callback); | |
}; | |
plivo.delete_outgoing_carrier_routing = function (params, callback) { | |
var action = 'OutgoingCarrierRouting/' + params['routing_id'] + '/'; | |
delete params.routing_id; | |
var method = 'DELETE'; | |
request(action, method, params, callback); | |
}; | |
// Pricing | |
plivo.get_pricing = function (params, callback) { | |
var action = 'Pricing/'; | |
var method = 'GET'; | |
request(action, method, params, callback); | |
}; | |
/** | |
* XML Response Generation | |
*/ | |
// Decalaring a class Response | |
function Response() { | |
this.element = 'Response'; | |
this.nestables = ['Speak', 'Play', 'GetDigits', 'Record', 'Dial', 'Message', | |
'Redirect', 'Wait', 'Hangup', 'PreAnswer', 'Conference', 'DTMF']; | |
this.valid_attributes = []; | |
this.elem = doc.begin(this.element); | |
}; | |
Response.prototype = { | |
init: function (name, body, attributes, parent) { | |
this.name = name; | |
this.body = body; | |
this.elem = ''; | |
if (this.element != 'Response') { | |
this.elem.parent = parent; | |
this.elem = parent.ele(this.name); | |
} else { | |
this.elem = this.elem.ele(this.name); | |
} | |
if (!attributes) { | |
var attributes = {}; | |
} | |
var keys = Object.keys(attributes); | |
for (var i = 0; i < keys.length; i++) { | |
if (this.valid_attributes.indexOf(keys[i]) == -1) { | |
throw new PlivoError('Not a valid attribute : "' + keys[i] + '" for "' + this.name + '" Element'); | |
} | |
this.elem.att(keys[i], attributes[keys[i]]) | |
} | |
if (body) { | |
this.elem.text(body) | |
} | |
}, | |
add: function (new_element, body, attributes) { | |
if (body === undefined) { | |
throw new PlivoError('No text set for ' + new_element.element + '.'); | |
} | |
if (this.nestables.indexOf(new_element.element) > -1) { | |
var parent = this.elem; | |
} else { | |
throw new PlivoError(new_element.element + ' cannot be nested in ' + this.element + '.'); | |
} | |
new_element.init(new_element.element, body, attributes, parent); | |
return new_element; | |
}, | |
addConference: function (body, attributes) { | |
return this.add(new Conference(Response), body, attributes); | |
}, | |
addNumber: function (body, attributes) { | |
return this.add(new Number(Response), body, attributes); | |
}, | |
addUser: function (body) { | |
return this.add(new User(Response), body, {}); | |
}, | |
addDial: function (attributes) { | |
return this.add(new Dial(Response), '', attributes); | |
}, | |
addGetDigits: function (attributes) { | |
return this.add(new GetDigits(Response), '', attributes); | |
}, | |
addHangup: function (attributes) { | |
return this.add(new Hangup(Response), '', attributes); | |
}, | |
addMessage: function (body, attributes) { | |
return this.add(new Message(Response), body, attributes); | |
}, | |
addPlay: function (body, attributes) { | |
return this.add(new Play(Response), body, attributes); | |
}, | |
addPreAnswer: function () { | |
return this.add(new PreAnswer(Response), '', {}); | |
}, | |
addRecord: function (attributes) { | |
return this.add(new Record(Response),'', attributes); | |
}, | |
addRedirect: function (body, attributes) { | |
return this.add(new Redirect(Response), body, attributes); | |
}, | |
addSpeak: function (body, attributes) { | |
return this.add(new Speak(Response), body, attributes); | |
}, | |
addWait: function (attributes) { | |
return this.add(new Wait(Response), '', attributes); | |
}, | |
addDTMF: function (body, attributes) { | |
return this.add(new DTMF(Response), body, attributes); | |
}, | |
toXML: function () { | |
return this.elem.toString(); | |
} | |
} | |
function Conference(Response) { | |
this.element = 'Conference'; | |
this.valid_attributes = ['muted', 'beep', 'startConferenceOnEnter', | |
'endConferenceOnExit', 'waitSound', 'enterSound', 'exitSound', | |
'timeLimit', 'hangupOnStar', 'maxMembers', 'record','recordWhenAlone', | |
'recordFileFormat', 'action', 'method', 'redirect', | |
'digitsMatch', 'callbackUrl', 'callbackMethod', 'stayAlone', | |
'floorEvent', 'transcriptionType', 'transcriptionUrl', | |
'transcriptionMethod', 'relayDTMF']; | |
this.nestables = []; | |
} | |
util.inherits(Conference, Response); | |
function Number(Response) { | |
this.element = 'Number'; | |
this.valid_attributes = ['sendDigits', 'sendOnPreanswer', 'sendDigitsMode']; | |
this.nestables = []; | |
} | |
util.inherits(Number, Response); | |
function User(Response) { | |
this.element = 'User'; | |
this.nestables = []; | |
this.valid_attributes = ['sendDigits', 'sendOnPreanswer', 'sipHeaders']; | |
} | |
util.inherits(User, Response); | |
function Dial(Response) { | |
this.element = 'Dial'; | |
this.valid_attributes = ['action', 'method', 'timeout', 'hangupOnStar', | |
'timeLimit', 'callerId', 'callerName', 'confirmSound', | |
'dialMusic', 'confirmKey', 'redirect', 'callbackUrl', | |
'callbackMethod', 'digitsMatch', 'digitsMatchBLeg', 'sipHeaders']; | |
this.nestables = ['Number', 'User']; | |
} | |
util.inherits(Dial, Response); | |
function GetDigits(Response) { | |
this.element = 'GetDigits'; | |
this.valid_attributes = ['action', 'method', 'timeout', 'digitTimeout', | |
'finishOnKey', 'numDigits', 'retries', 'invalidDigitsSound', | |
'validDigits', 'playBeep', 'redirect', 'log']; | |
this.nestables = ['Speak', 'Play', 'Wait']; | |
} | |
util.inherits(GetDigits, Response); | |
function Hangup(Response) { | |
this.element = 'Hangup'; | |
this.valid_attributes = ['schedule', 'reason']; | |
this.nestables = []; | |
} | |
util.inherits(Hangup, Response); | |
function Message(Response) { | |
this.element = 'Message'; | |
this.nestables = []; | |
this.valid_attributes = ['src', 'dst', 'type', 'callbackUrl', | |
'callbackMethod']; | |
} | |
util.inherits(Message, Response); | |
function Play(Response) { | |
this.element = 'Play'; | |
this.valid_attributes = ['loop']; | |
this.nestables = []; | |
} | |
util.inherits(Play, Response); | |
function PreAnswer(Response) { | |
this.element = 'PreAnswer'; | |
this.valid_attributes = []; | |
this.nestables = ['Play', 'Speak', 'GetDigits', 'Wait', 'Redirect', | |
'Message', 'DTMF']; | |
} | |
util.inherits(PreAnswer, Response); | |
function Record(Response) { | |
this.element = 'Record'; | |
this.nestables = []; | |
this.valid_attributes = ['action', 'method', 'timeout', 'finishOnKey', | |
'maxLength', 'playBeep', 'recordSession', | |
'startOnDialAnswer', 'redirect', 'fileFormat', | |
'callbackUrl', 'callbackMethod', 'transcriptionType', | |
'transcriptionUrl', 'transcriptionMethod']; | |
} | |
util.inherits(Record, Response); | |
function Redirect(Response) { | |
this.element = 'Redirect'; | |
this.valid_attributes = ['method']; | |
this.nestables = []; | |
} | |
util.inherits(Redirect, Response); | |
function Speak(Response) { | |
this.element = 'Speak'; | |
this.valid_attributes = ['voice', 'language', 'loop']; | |
this.nestables = []; | |
} | |
util.inherits(Speak, Response); | |
function Wait(Response) { | |
this.element = 'Wait'; | |
this.valid_attributes = ['length', 'silence', 'min_silence', 'minSilence', 'beep']; | |
this.nestables = []; | |
} | |
util.inherits(Wait, Response); | |
function DTMF(Response) { | |
this.element = 'DTMF'; | |
this.nestables = []; | |
this.valid_attributes = ['digits', 'async']; | |
} | |
util.inherits(DTMF, Response); | |
/** | |
* Module Exports | |
*/ | |
exports.Response = function () { | |
return new Response(); | |
} | |
exports.RestAPI = function (config) { | |
if (!config) { | |
throw new PlivoError('Auth ID and Auth Token must be provided.'); | |
} | |
if (typeof config != 'object') { | |
throw new PlivoError('Config for RestAPI must be provided as an object.'); | |
} | |
if (!config.authId || !config.authToken) { | |
throw new PlivoError('Auth ID and Auth Token must be provided.'); | |
} | |
// override default config according to the config provided. | |
for (key in config) { | |
plivo.options[key] = config[key]; | |
} | |
return plivo; | |
} | |
}).call(this,require('_process'),require("buffer").Buffer) | |
},{"_process":undefined,"buffer":undefined,"crypto":undefined,"querystring":undefined,"request":5,"util":undefined,"xmlbuilder":19}],3:[function(require,module,exports){ | |
/*! | |
* knox - auth | |
* Copyright(c) 2010 LearnBoost <[email protected]> | |
* MIT Licensed | |
*/ | |
/** | |
* Module dependencies. | |
*/ | |
var crypto = require('crypto') | |
, parse = require('url').parse | |
; | |
/** | |
* Valid keys. | |
*/ | |
var keys = | |
[ 'acl' | |
, 'location' | |
, 'logging' | |
, 'notification' | |
, 'partNumber' | |
, 'policy' | |
, 'requestPayment' | |
, 'torrent' | |
, 'uploadId' | |
, 'uploads' | |
, 'versionId' | |
, 'versioning' | |
, 'versions' | |
, 'website' | |
] | |
/** | |
* Return an "Authorization" header value with the given `options` | |
* in the form of "AWS <key>:<signature>" | |
* | |
* @param {Object} options | |
* @return {String} | |
* @api private | |
*/ | |
exports.authorization = function(options){ | |
return 'AWS ' + options.key + ':' + exports.sign(options) | |
} | |
/** | |
* Simple HMAC-SHA1 Wrapper | |
* | |
* @param {Object} options | |
* @return {String} | |
* @api private | |
*/ | |
exports.hmacSha1 = function(options){ | |
return crypto.createHmac('sha1', options.secret).update(options.message).digest('base64') | |
} | |
/** | |
* Create a base64 sha1 HMAC for `options`. | |
* | |
* @param {Object} options | |
* @return {String} | |
* @api private | |
*/ | |
exports.sign = function(options){ | |
options.message = exports.stringToSign(options) | |
return exports.hmacSha1(options) | |
} | |
/** | |
* Create a base64 sha1 HMAC for `options`. | |
* | |
* Specifically to be used with S3 presigned URLs | |
* | |
* @param {Object} options | |
* @return {String} | |
* @api private | |
*/ | |
exports.signQuery = function(options){ | |
options.message = exports.queryStringToSign(options) | |
return exports.hmacSha1(options) | |
} | |
/** | |
* Return a string for sign() with the given `options`. | |
* | |
* Spec: | |
* | |
* <verb>\n | |
* <md5>\n | |
* <content-type>\n | |
* <date>\n | |
* [headers\n] | |
* <resource> | |
* | |
* @param {Object} options | |
* @return {String} | |
* @api private | |
*/ | |
exports.stringToSign = function(options){ | |
var headers = options.amazonHeaders || '' | |
if (headers) headers += '\n' | |
var r = | |
[ options.verb | |
, options.md5 | |
, options.contentType | |
, options.date.toUTCString() | |
, headers + options.resource | |
] | |
return r.join('\n') | |
} | |
/** | |
* Return a string for sign() with the given `options`, but is meant exclusively | |
* for S3 presigned URLs | |
* | |
* Spec: | |
* | |
* <date>\n | |
* <resource> | |
* | |
* @param {Object} options | |
* @return {String} | |
* @api private | |
*/ | |
exports.queryStringToSign = function(options){ | |
return 'GET\n\n\n' + options.date + '\n' + options.resource | |
}; | |
/** | |
* Perform the following: | |
* | |
* - ignore non-amazon headers | |
* - lowercase fields | |
* - sort lexicographically | |
* - trim whitespace between ":" | |
* - join with newline | |
* | |
* @param {Object} headers | |
* @return {String} | |
* @api private | |
*/ | |
exports.canonicalizeHeaders = function(headers){ | |
var buf = [] | |
, fields = Object.keys(headers) | |
; | |
for (var i = 0, len = fields.length; i < len; ++i) { | |
var field = fields[i] | |
, val = headers[field] | |
, field = field.toLowerCase() | |
; | |
if (0 !== field.indexOf('x-amz')) continue | |
buf.push(field + ':' + val) | |
} | |
return buf.sort().join('\n') | |
}; | |
/** | |
* Perform the following: | |
* | |
* - ignore non sub-resources | |
* - sort lexicographically | |
* | |
* @param {String} resource | |
* @return {String} | |
* @api private | |
*/ | |
exports.canonicalizeResource = function(resource){ | |
var url = parse(resource, true) | |
, path = url.pathname | |
, buf = [] | |
; | |
Object.keys(url.query).forEach(function(key){ | |
if (!~keys.indexOf(key)) return | |
var val = '' == url.query[key] ? '' : '=' + encodeURIComponent(url.query[key]) | |
buf.push(key + val) | |
}) | |
return path + (buf.length ? '?' + buf.sort().join('&') : '') | |
}; | |
},{"crypto":undefined,"url":undefined}],4:[function(require,module,exports){ | |
module.exports = ForeverAgent | |
ForeverAgent.SSL = ForeverAgentSSL | |
var util = require('util') | |
, Agent = require('http').Agent | |
, net = require('net') | |
, tls = require('tls') | |
, AgentSSL = require('https').Agent | |
function ForeverAgent(options) { | |
var self = this | |
self.options = options || {} | |
self.requests = {} | |
self.sockets = {} | |
self.freeSockets = {} | |
self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets | |
self.minSockets = self.options.minSockets || ForeverAgent.defaultMinSockets | |
self.on('free', function(socket, host, port) { | |
var name = host + ':' + port | |
if (self.requests[name] && self.requests[name].length) { | |
self.requests[name].shift().onSocket(socket) | |
} else if (self.sockets[name].length < self.minSockets) { | |
if (!self.freeSockets[name]) self.freeSockets[name] = [] | |
self.freeSockets[name].push(socket) | |
// if an error happens while we don't use the socket anyway, meh, throw the socket away | |
function onIdleError() { | |
socket.destroy() | |
} | |
socket._onIdleError = onIdleError | |
socket.on('error', onIdleError) | |
} else { | |
// If there are no pending requests just destroy the | |
// socket and it will get removed from the pool. This | |
// gets us out of timeout issues and allows us to | |
// default to Connection:keep-alive. | |
socket.destroy() | |
} | |
}) | |
} | |
util.inherits(ForeverAgent, Agent) | |
ForeverAgent.defaultMinSockets = 5 | |
ForeverAgent.prototype.createConnection = net.createConnection | |
ForeverAgent.prototype.addRequestNoreuse = Agent.prototype.addRequest | |
ForeverAgent.prototype.addRequest = function(req, host, port) { | |
var name = host + ':' + port | |
if (this.freeSockets[name] && this.freeSockets[name].length > 0 && !req.useChunkedEncodingByDefault) { | |
var idleSocket = this.freeSockets[name].pop() | |
idleSocket.removeListener('error', idleSocket._onIdleError) | |
delete idleSocket._onIdleError | |
req._reusedSocket = true | |
req.onSocket(idleSocket) | |
} else { | |
this.addRequestNoreuse(req, host, port) | |
} | |
} | |
ForeverAgent.prototype.removeSocket = function(s, name, host, port) { | |
if (this.sockets[name]) { | |
var index = this.sockets[name].indexOf(s) | |
if (index !== -1) { | |
this.sockets[name].splice(index, 1) | |
} | |
} else if (this.sockets[name] && this.sockets[name].length === 0) { | |
// don't leak | |
delete this.sockets[name] | |
delete this.requests[name] | |
} | |
if (this.freeSockets[name]) { | |
var index = this.freeSockets[name].indexOf(s) | |
if (index !== -1) { | |
this.freeSockets[name].splice(index, 1) | |
if (this.freeSockets[name].length === 0) { | |
delete this.freeSockets[name] | |
} | |
} | |
} | |
if (this.requests[name] && this.requests[name].length) { | |
// If we have pending requests and a socket gets closed a new one | |
// needs to be created to take over in the pool for the one that closed. | |
this.createSocket(name, host, port).emit('free') | |
} | |
} | |
function ForeverAgentSSL (options) { | |
ForeverAgent.call(this, options) | |
} | |
util.inherits(ForeverAgentSSL, ForeverAgent) | |
ForeverAgentSSL.prototype.createConnection = createConnectionSSL | |
ForeverAgentSSL.prototype.addRequestNoreuse = AgentSSL.prototype.addRequest | |
function createConnectionSSL (port, host, options) { | |
options.port = port | |
options.host = host | |
return tls.connect(options) | |
} | |
},{"http":undefined,"https":undefined,"net":undefined,"tls":undefined,"util":undefined}],5:[function(require,module,exports){ | |
(function (process,Buffer){ | |
// 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. | |
var http = require('http') | |
, https = false | |
, tls = false | |
, url = require('url') | |
, util = require('util') | |
, stream = require('stream') | |
, qs = require('querystring') | |
, oauth = require('./oauth') | |
, uuid = require('./uuid') | |
, ForeverAgent = require('./forever') | |
, Cookie = require('./vendor/cookie') | |
, CookieJar = require('./vendor/cookie/jar') | |
, cookieJar = new CookieJar | |
, tunnel = require('./tunnel') | |
, aws = require('./aws') | |
, mime = require('mime') | |
, FormData = require('form-data') | |
; | |
if (process.logging) { | |
var log = process.logging('request') | |
} | |
try { | |
https = require('https') | |
} catch (e) {} | |
try { | |
tls = require('tls') | |
} catch (e) {} | |
function toBase64 (str) { | |
return (new Buffer(str || "", "ascii")).toString("base64") | |
} | |
// Hacky fix for pre-0.4.4 https | |
if (https && !https.Agent) { | |
https.Agent = function (options) { | |
http.Agent.call(this, options) | |
} | |
util.inherits(https.Agent, http.Agent) | |
https.Agent.prototype._getConnection = function (host, port, cb) { | |
var s = tls.connect(port, host, this.options, function () { | |
// do other checks here? | |
if (cb) cb() | |
}) | |
return s | |
} | |
} | |
function isReadStream (rs) { | |
if (rs.readable && rs.path && rs.mode) { | |
return true | |
} | |
} | |
function copy (obj) { | |
var o = {} | |
Object.keys(obj).forEach(function (i) { | |
o[i] = obj[i] | |
}) | |
return o | |
} | |
var isUrl = /^https?:/ | |
var globalPool = {} | |
function Request (options) { | |
stream.Stream.call(this) | |
this.readable = true | |
this.writable = true | |
if (typeof options === 'string') { | |
options = {uri:options} | |
} | |
var reserved = Object.keys(Request.prototype) | |
for (var i in options) { | |
if (reserved.indexOf(i) === -1) { | |
this[i] = options[i] | |
} else { | |
if (typeof options[i] === 'function') { | |
delete options[i] | |
} | |
} | |
} | |
options = copy(options) | |
this.init(options) | |
} | |
util.inherits(Request, stream.Stream) | |
Request.prototype.init = function (options) { | |
var self = this | |
if (!options) options = {} | |
if (process.env.NODE_DEBUG && /request/.test(process.env.NODE_DEBUG)) console.error('REQUEST', options) | |
if (!self.pool && self.pool !== false) self.pool = globalPool | |
self.dests = [] | |
self.__isRequestRequest = true | |
// Protect against double callback | |
if (!self._callback && self.callback) { | |
self._callback = self.callback | |
self.callback = function () { | |
if (self._callbackCalled) return // Print a warning maybe? | |
self._callback.apply(self, arguments) | |
self._callbackCalled = true | |
} | |
self.on('error', self.callback.bind()) | |
self.on('complete', self.callback.bind(self, null)) | |
} | |
if (self.url) { | |
// People use this property instead all the time so why not just support it. | |
self.uri = self.url | |
delete self.url | |
} | |
if (!self.uri) { | |
// this will throw if unhandled but is handleable when in a redirect | |
return self.emit('error', new Error("options.uri is a required argument")) | |
} else { | |
if (typeof self.uri == "string") self.uri = url.parse(self.uri) | |
} | |
if (self.proxy) { | |
if (typeof self.proxy == 'string') self.proxy = url.parse(self.proxy) | |
// do the HTTP CONNECT dance using koichik/node-tunnel | |
if (http.globalAgent && self.uri.protocol === "https:") { | |
var tunnelFn = self.proxy.protocol === "http:" | |
? tunnel.httpsOverHttp : tunnel.httpsOverHttps | |
var tunnelOptions = { proxy: { host: self.proxy.hostname | |
, port: +self.proxy.port | |
, proxyAuth: self.proxy.auth } | |
, ca: this.ca } | |
self.agent = tunnelFn(tunnelOptions) | |
self.tunnel = true | |
} | |
} | |
if (!self.uri.host || !self.uri.pathname) { | |
// Invalid URI: it may generate lot of bad errors, like "TypeError: Cannot call method 'indexOf' of undefined" in CookieJar | |
// Detect and reject it as soon as possible | |
var faultyUri = url.format(self.uri) | |
var message = 'Invalid URI "' + faultyUri + '"' | |
if (Object.keys(options).length === 0) { | |
// No option ? This can be the sign of a redirect | |
// As this is a case where the user cannot do anything (he didn't call request directly with this URL) | |
// he should be warned that it can be caused by a redirection (can save some hair) | |
message += '. This can be caused by a crappy redirection.' | |
} | |
self.emit('error', new Error(message)) | |
return // This error was fatal | |
} | |
self._redirectsFollowed = self._redirectsFollowed || 0 | |
self.maxRedirects = (self.maxRedirects !== undefined) ? self.maxRedirects : 10 | |
self.followRedirect = (self.followRedirect !== undefined) ? self.followRedirect : true | |
self.followAllRedirects = (self.followAllRedirects !== undefined) ? self.followAllRedirects : false | |
if (self.followRedirect || self.followAllRedirects) | |
self.redirects = self.redirects || [] | |
self.headers = self.headers ? copy(self.headers) : {} | |
self.setHost = false | |
if (!self.headers.host) { | |
self.headers.host = self.uri.hostname | |
if (self.uri.port) { | |
if ( !(self.uri.port === 80 && self.uri.protocol === 'http:') && | |
!(self.uri.port === 443 && self.uri.protocol === 'https:') ) | |
self.headers.host += (':'+self.uri.port) | |
} | |
self.setHost = true | |
} | |
self.jar(self._jar || options.jar) | |
if (!self.uri.pathname) {self.uri.pathname = '/'} | |
if (!self.uri.port) { | |
if (self.uri.protocol == 'http:') {self.uri.port = 80} | |
else if (self.uri.protocol == 'https:') {self.uri.port = 443} | |
} | |
if (self.proxy && !self.tunnel) { | |
self.port = self.proxy.port | |
self.host = self.proxy.hostname | |
} else { | |
self.port = self.uri.port | |
self.host = self.uri.hostname | |
} | |
self.clientErrorHandler = function (error) { | |
if (self._aborted) return | |
if (self.setHost) delete self.headers.host | |
if (self.req._reusedSocket && error.code === 'ECONNRESET' | |
&& self.agent.addRequestNoreuse) { | |
self.agent = { addRequest: self.agent.addRequestNoreuse.bind(self.agent) } | |
self.start() | |
self.req.end() | |
return | |
} | |
if (self.timeout && self.timeoutTimer) { | |
clearTimeout(self.timeoutTimer) | |
self.timeoutTimer = null | |
} | |
self.emit('error', error) | |
} | |
self._parserErrorHandler = function (error) { | |
if (this.res) { | |
if (this.res.request) { | |
this.res.request.emit('error', error) | |
} else { | |
this.res.emit('error', error) | |
} | |
} else { | |
this._httpMessage.emit('error', error) | |
} | |
} | |
if (options.form) { | |
self.form(options.form) | |
} | |
if (options.oauth) { | |
self.oauth(options.oauth) | |
} | |
if (options.aws) { | |
self.aws(options.aws) | |
} | |
if (self.uri.auth && !self.headers.authorization) { | |
self.headers.authorization = "Basic " + toBase64(self.uri.auth.split(':').map(function(item){ return qs.unescape(item)}).join(':')) | |
} | |
if (self.proxy && self.proxy.auth && !self.headers['proxy-authorization'] && !self.tunnel) { | |
self.headers['proxy-authorization'] = "Basic " + toBase64(self.proxy.auth.split(':').map(function(item){ return qs.unescape(item)}).join(':')) | |
} | |
if (options.qs) self.qs(options.qs) | |
if (self.uri.path) { | |
self.path = self.uri.path | |
} else { | |
self.path = self.uri.pathname + (self.uri.search || "") | |
} | |
if (self.path.length === 0) self.path = '/' | |
if (self.proxy && !self.tunnel) self.path = (self.uri.protocol + '//' + self.uri.host + self.path) | |
if (options.json) { | |
self.json(options.json) | |
} else if (options.multipart) { | |
self.boundary = uuid() | |
self.multipart(options.multipart) | |
} | |
if (self.body) { | |
var length = 0 | |
if (!Buffer.isBuffer(self.body)) { | |
if (Array.isArray(self.body)) { | |
for (var i = 0; i < self.body.length; i++) { | |
length += self.body[i].length | |
} | |
} else { | |
self.body = new Buffer(self.body) | |
length = self.body.length | |
} | |
} else { | |
length = self.body.length | |
} | |
if (length) { | |
if(!self.headers['content-length'] && !self.headers['Content-Length']) | |
self.headers['content-length'] = length | |
} else { | |
throw new Error('Argument error, options.body.') | |
} | |
} | |
var protocol = self.proxy && !self.tunnel ? self.proxy.protocol : self.uri.protocol | |
, defaultModules = {'http:':http, 'https:':https} | |
, httpModules = self.httpModules || {} | |
; | |
self.httpModule = httpModules[protocol] || defaultModules[protocol] | |
if (!self.httpModule) return this.emit('error', new Error("Invalid protocol")) | |
if (options.ca) self.ca = options.ca | |
if (!self.agent) { | |
if (options.agentOptions) self.agentOptions = options.agentOptions | |
if (options.agentClass) { | |
self.agentClass = options.agentClass | |
} else if (options.forever) { | |
self.agentClass = protocol === 'http:' ? ForeverAgent : ForeverAgent.SSL | |
} else { | |
self.agentClass = self.httpModule.Agent | |
} | |
} | |
if (self.pool === false) { | |
self.agent = false | |
} else { | |
self.agent = self.agent || self.getAgent() | |
if (self.maxSockets) { | |
// Don't use our pooling if node has the refactored client | |
self.agent.maxSockets = self.maxSockets | |
} | |
if (self.pool.maxSockets) { | |
// Don't use our pooling if node has the refactored client | |
self.agent.maxSockets = self.pool.maxSockets | |
} | |
} | |
self.once('pipe', function (src) { | |
if (self.ntick && self._started) throw new Error("You cannot pipe to this stream after the outbound request has started.") | |
self.src = src | |
if (isReadStream(src)) { | |
if (!self.headers['content-type'] && !self.headers['Content-Type']) | |
self.headers['content-type'] = mime.lookup(src.path) | |
} else { | |
if (src.headers) { | |
for (var i in src.headers) { | |
if (!self.headers[i]) { | |
self.headers[i] = src.headers[i] | |
} | |
} | |
} | |
if (self._json && !self.headers['content-type'] && !self.headers['Content-Type']) | |
self.headers['content-type'] = 'application/json' | |
if (src.method && !self.method) { | |
self.method = src.method | |
} | |
} | |
self.on('pipe', function () { | |
console.error("You have already piped to this stream. Pipeing twice is likely to break the request.") | |
}) | |
}) | |
process.nextTick(function () { | |
if (self._aborted) return | |
if (self._form) { | |
self.setHeaders(self._form.getHeaders()) | |
self._form.pipe(self) | |
} | |
if (self.body) { | |
if (Array.isArray(self.body)) { | |
self.body.forEach(function (part) { | |
self.write(part) | |
}) | |
} else { | |
self.write(self.body) | |
} | |
self.end() | |
} else if (self.requestBodyStream) { | |
console.warn("options.requestBodyStream is deprecated, please pass the request object to stream.pipe.") | |
self.requestBodyStream.pipe(self) | |
} else if (!self.src) { | |
if (self.method !== 'GET' && typeof self.method !== 'undefined') { | |
self.headers['content-length'] = 0 | |
} | |
self.end() | |
} | |
self.ntick = true | |
}) | |
} | |
// Must call this when following a redirect from https to http or vice versa | |
// Attempts to keep everything as identical as possible, but update the | |
// httpModule, Tunneling agent, and/or Forever Agent in use. | |
Request.prototype._updateProtocol = function () { | |
var self = this | |
var protocol = self.uri.protocol | |
if (protocol === 'https:') { | |
// previously was doing http, now doing https | |
// if it's https, then we might need to tunnel now. | |
if (self.proxy) { | |
self.tunnel = true | |
var tunnelFn = self.proxy.protocol === 'http:' | |
? tunnel.httpsOverHttp : tunnel.httpsOverHttps | |
var tunnelOptions = { proxy: { host: self.proxy.hostname | |
, post: +self.proxy.port | |
, proxyAuth: self.proxy.auth } | |
, ca: self.ca } | |
self.agent = tunnelFn(tunnelOptions) | |
return | |
} | |
self.httpModule = https | |
switch (self.agentClass) { | |
case ForeverAgent: | |
self.agentClass = ForeverAgent.SSL | |
break | |
case http.Agent: | |
self.agentClass = https.Agent | |
break | |
default: | |
// nothing we can do. Just hope for the best. | |
return | |
} | |
// if there's an agent, we need to get a new one. | |
if (self.agent) self.agent = self.getAgent() | |
} else { | |
if (log) log('previously https, now http') | |
// previously was doing https, now doing http | |
// stop any tunneling. | |
if (self.tunnel) self.tunnel = false | |
self.httpModule = http | |
switch (self.agentClass) { | |
case ForeverAgent.SSL: | |
self.agentClass = ForeverAgent | |
break | |
case https.Agent: | |
self.agentClass = http.Agent | |
break | |
default: | |
// nothing we can do. just hope for the best | |
return | |
} | |
// if there's an agent, then get a new one. | |
if (self.agent) { | |
self.agent = null | |
self.agent = self.getAgent() | |
} | |
} | |
} | |
Request.prototype.getAgent = function () { | |
var Agent = this.agentClass | |
var options = {} | |
if (this.agentOptions) { | |
for (var i in this.agentOptions) { | |
options[i] = this.agentOptions[i] | |
} | |
} | |
if (this.ca) options.ca = this.ca | |
var poolKey = '' | |
// different types of agents are in different pools | |
if (Agent !== this.httpModule.Agent) { | |
poolKey += Agent.name | |
} | |
if (!this.httpModule.globalAgent) { | |
// node 0.4.x | |
options.host = this.host | |
options.port = this.port | |
if (poolKey) poolKey += ':' | |
poolKey += this.host + ':' + this.port | |
} | |
// ca option is only relevant if proxy or destination are https | |
var proxy = this.proxy | |
if (typeof proxy === 'string') proxy = url.parse(proxy) | |
var caRelevant = (proxy && proxy.protocol === 'https:') || this.uri.protocol === 'https:' | |
if (options.ca && caRelevant) { | |
if (poolKey) poolKey += ':' | |
poolKey += options.ca | |
} | |
if (!poolKey && Agent === this.httpModule.Agent && this.httpModule.globalAgent) { | |
// not doing anything special. Use the globalAgent | |
return this.httpModule.globalAgent | |
} | |
// we're using a stored agent. Make sure it's protocol-specific | |
poolKey = this.uri.protocol + poolKey | |
// already generated an agent for this setting | |
if (this.pool[poolKey]) return this.pool[poolKey] | |
return this.pool[poolKey] = new Agent(options) | |
} | |
Request.prototype.start = function () { | |
var self = this | |
if (self._aborted) return | |
self._started = true | |
self.method = self.method || 'GET' | |
self.href = self.uri.href | |
if (log) log('%method %href', self) | |
if (self.src && self.src.stat && self.src.stat.size && !self.headers['content-length'] && !self.headers['Content-Length']) { | |
self.headers['content-length'] = self.src.stat.size | |
} | |
if (self._aws) { | |
self.aws(self._aws, true) | |
} | |
self.req = self.httpModule.request(self, function (response) { | |
if (response.connection.listeners('error').indexOf(self._parserErrorHandler) === -1) { | |
response.connection.once('error', self._parserErrorHandler) | |
} | |
if (self._aborted) return | |
if (self._paused) response.pause() | |
self.response = response | |
response.request = self | |
response.toJSON = toJSON | |
if (self.httpModule === https && | |
self.strictSSL && | |
!response.client.authorized) { | |
var sslErr = response.client.authorizationError | |
self.emit('error', new Error('SSL Error: '+ sslErr)) | |
return | |
} | |
if (self.setHost) delete self.headers.host | |
if (self.timeout && self.timeoutTimer) { | |
clearTimeout(self.timeoutTimer) | |
self.timeoutTimer = null | |
} | |
var addCookie = function (cookie) { | |
if (self._jar) self._jar.add(new Cookie(cookie)) | |
else cookieJar.add(new Cookie(cookie)) | |
} | |
if (response.headers['set-cookie'] && (!self._disableCookies)) { | |
if (Array.isArray(response.headers['set-cookie'])) response.headers['set-cookie'].forEach(addCookie) | |
else addCookie(response.headers['set-cookie']) | |
} | |
if (response.statusCode >= 300 && response.statusCode < 400 && | |
(self.followAllRedirects || | |
(self.followRedirect && (self.method !== 'PUT' && self.method !== 'POST' && self.method !== 'DELETE'))) && | |
response.headers.location) { | |
if (self._redirectsFollowed >= self.maxRedirects) { | |
self.emit('error', new Error("Exceeded maxRedirects. Probably stuck in a redirect loop "+self.uri.href)) | |
return | |
} | |
self._redirectsFollowed += 1 | |
if (!isUrl.test(response.headers.location)) { | |
response.headers.location = url.resolve(self.uri.href, response.headers.location) | |
} | |
var uriPrev = self.uri | |
self.uri = url.parse(response.headers.location) | |
// handle the case where we change protocol from https to http or vice versa | |
if (self.uri.protocol !== uriPrev.protocol) { | |
self._updateProtocol() | |
} | |
self.redirects.push( | |
{ statusCode : response.statusCode | |
, redirectUri: response.headers.location | |
} | |
) | |
if (self.followAllRedirects) self.method = 'GET' | |
// self.method = 'GET' // Force all redirects to use GET || commented out fixes #215 | |
delete self.src | |
delete self.req | |
delete self.agent | |
delete self._started | |
delete self.body | |
delete self._form | |
if (self.headers) { | |
delete self.headers.host | |
delete self.headers['content-type'] | |
delete self.headers['content-length'] | |
} | |
if (log) log('Redirect to %uri', self) | |
self.init() | |
return // Ignore the rest of the response | |
} else { | |
self._redirectsFollowed = self._redirectsFollowed || 0 | |
// 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') | |
}) | |
if (self.encoding) { | |
if (self.dests.length !== 0) { | |
console.error("Ingoring encoding parameter as this stream is being piped to another stream which makes the encoding option invalid.") | |
} else { | |
response.setEncoding(self.encoding) | |
} | |
} | |
self.dests.forEach(function (dest) { | |
self.pipeDest(dest) | |
}) | |
response.on("data", function (chunk) { | |
self._destdata = true | |
self.emit("data", chunk) | |
}) | |
response.on("end", function (chunk) { | |
self._ended = true | |
self.emit("end", chunk) | |
}) | |
response.on("close", function () {self.emit("close")}) | |
self.emit('response', response) | |
if (self.callback) { | |
var buffer = [] | |
var bodyLen = 0 | |
self.on("data", function (chunk) { | |
buffer.push(chunk) | |
bodyLen += chunk.length | |
}) | |
self.on("end", function () { | |
if (self._aborted) return | |
if (buffer.length && Buffer.isBuffer(buffer[0])) { | |
var body = new Buffer(bodyLen) | |
var i = 0 | |
buffer.forEach(function (chunk) { | |
chunk.copy(body, i, 0, chunk.length) | |
i += chunk.length | |
}) | |
if (self.encoding === null) { | |
response.body = body | |
} else { | |
response.body = body.toString(self.encoding) | |
} | |
} else if (buffer.length) { | |
response.body = buffer.join('') | |
} | |
if (self._json) { | |
try { | |
response.body = JSON.parse(response.body) | |
} catch (e) {} | |
} | |
self.emit('complete', response, response.body) | |
}) | |
} | |
} | |
}) | |
if (self.timeout && !self.timeoutTimer) { | |
self.timeoutTimer = setTimeout(function () { | |
self.req.abort() | |
var e = new Error("ETIMEDOUT") | |
e.code = "ETIMEDOUT" | |
self.emit("error", e) | |
}, self.timeout) | |
// Set additional timeout on socket - in case if remote | |
// server freeze after sending headers | |
if (self.req.setTimeout) { // only works on node 0.6+ | |
self.req.setTimeout(self.timeout, function () { | |
if (self.req) { | |
self.req.abort() | |
var e = new Error("ESOCKETTIMEDOUT") | |
e.code = "ESOCKETTIMEDOUT" | |
self.emit("error", e) | |
} | |
}) | |
} | |
} | |
self.req.on('error', self.clientErrorHandler) | |
self.req.on('drain', function() { | |
self.emit('drain') | |
}) | |
self.on('end', function() { | |
if ( self.req.connection ) self.req.connection.removeListener('error', self._parserErrorHandler) | |
}) | |
self.emit('request', self.req) | |
} | |
Request.prototype.abort = function () { | |
this._aborted = true | |
if (this.req) { | |
this.req.abort() | |
} | |
else if (this.response) { | |
this.response.abort() | |
} | |
this.emit("abort") | |
} | |
Request.prototype.pipeDest = function (dest) { | |
var response = this.response | |
// Called after the response is received | |
if (dest.headers) { | |
dest.headers['content-type'] = response.headers['content-type'] | |
if (response.headers['content-length']) { | |
dest.headers['content-length'] = response.headers['content-length'] | |
} | |
} | |
if (dest.setHeader) { | |
for (var i in response.headers) { | |
dest.setHeader(i, response.headers[i]) | |
} | |
dest.statusCode = response.statusCode | |
} | |
if (this.pipefilter) this.pipefilter(response, dest) | |
} | |
// Composable API | |
Request.prototype.setHeader = function (name, value, clobber) { | |
if (clobber === undefined) clobber = true | |
if (clobber || !this.headers.hasOwnProperty(name)) this.headers[name] = value | |
else this.headers[name] += ',' + value | |
return this | |
} | |
Request.prototype.setHeaders = function (headers) { | |
for (var i in headers) {this.setHeader(i, headers[i])} | |
return this | |
} | |
Request.prototype.qs = function (q, clobber) { | |
var base | |
if (!clobber && this.uri.query) base = qs.parse(this.uri.query) | |
else base = {} | |
for (var i in q) { | |
base[i] = q[i] | |
} | |
this.uri = url.parse(this.uri.href.split('?')[0] + '?' + qs.stringify(base)) | |
this.url = this.uri | |
return this | |
} | |
Request.prototype.form = function (form) { | |
if (form) { | |
this.headers['content-type'] = 'application/x-www-form-urlencoded; charset=utf-8' | |
this.body = qs.stringify(form).toString('utf8') | |
return this | |
} | |
// create form-data object | |
this._form = new FormData() | |
return this._form | |
} | |
Request.prototype.multipart = function (multipart) { | |
var self = this | |
self.body = [] | |
if (!self.headers['content-type']) { | |
self.headers['content-type'] = 'multipart/related; boundary=' + self.boundary | |
} else { | |
self.headers['content-type'] = self.headers['content-type'].split(';')[0] + '; boundary=' + self.boundary | |
} | |
if (!multipart.forEach) throw new Error('Argument error, options.multipart.') | |
if (self.preambleCRLF) { | |
self.body.push(new Buffer('\r\n')) | |
} | |
multipart.forEach(function (part) { | |
var body = part.body | |
if(body == null) throw Error('Body attribute missing in multipart.') | |
delete part.body | |
var preamble = '--' + self.boundary + '\r\n' | |
Object.keys(part).forEach(function (key) { | |
preamble += key + ': ' + part[key] + '\r\n' | |
}) | |
preamble += '\r\n' | |
self.body.push(new Buffer(preamble)) | |
self.body.push(new Buffer(body)) | |
self.body.push(new Buffer('\r\n')) | |
}) | |
self.body.push(new Buffer('--' + self.boundary + '--')) | |
return self | |
} | |
Request.prototype.json = function (val) { | |
this.setHeader('accept', 'application/json') | |
this._json = true | |
if (typeof val === 'boolean') { | |
if (typeof this.body === 'object') { | |
this.setHeader('content-type', 'application/json') | |
this.body = JSON.stringify(this.body) | |
} | |
} else { | |
this.setHeader('content-type', 'application/json') | |
this.body = JSON.stringify(val) | |
} | |
return this | |
} | |
function getHeader(name, headers) { | |
var result, re, match | |
Object.keys(headers).forEach(function (key) { | |
re = new RegExp(name, 'i') | |
match = key.match(re) | |
if (match) result = headers[key] | |
}) | |
return result | |
} | |
Request.prototype.aws = function (opts, now) { | |
if (!now) { | |
this._aws = opts | |
return this | |
} | |
var date = new Date() | |
this.setHeader('date', date.toUTCString()) | |
var auth = | |
{ key: opts.key | |
, secret: opts.secret | |
, verb: this.method.toUpperCase() | |
, date: date | |
, contentType: getHeader('content-type', this.headers) || '' | |
, md5: getHeader('content-md5', this.headers) || '' | |
, amazonHeaders: aws.canonicalizeHeaders(this.headers) | |
} | |
if (opts.bucket && this.path) { | |
auth.resource = '/' + opts.bucket + this.path | |
} else if (opts.bucket && !this.path) { | |
auth.resource = '/' + opts.bucket | |
} else if (!opts.bucket && this.path) { | |
auth.resource = this.path | |
} else if (!opts.bucket && !this.path) { | |
auth.resource = '/' | |
} | |
auth.resource = aws.canonicalizeResource(auth.resource) | |
this.setHeader('authorization', aws.authorization(auth)) | |
return this | |
} | |
Request.prototype.oauth = function (_oauth) { | |
var form | |
if (this.headers['content-type'] && | |
this.headers['content-type'].slice(0, 'application/x-www-form-urlencoded'.length) === | |
'application/x-www-form-urlencoded' | |
) { | |
form = qs.parse(this.body) | |
} | |
if (this.uri.query) { | |
form = qs.parse(this.uri.query) | |
} | |
if (!form) form = {} | |
var oa = {} | |
for (var i in form) oa[i] = form[i] | |
for (var i in _oauth) oa['oauth_'+i] = _oauth[i] | |
if (!oa.oauth_version) oa.oauth_version = '1.0' | |
if (!oa.oauth_timestamp) oa.oauth_timestamp = Math.floor( (new Date()).getTime() / 1000 ).toString() | |
if (!oa.oauth_nonce) oa.oauth_nonce = uuid().replace(/-/g, '') | |
oa.oauth_signature_method = 'HMAC-SHA1' | |
var consumer_secret = oa.oauth_consumer_secret | |
delete oa.oauth_consumer_secret | |
var token_secret = oa.oauth_token_secret | |
delete oa.oauth_token_secret | |
var baseurl = this.uri.protocol + '//' + this.uri.host + this.uri.pathname | |
var signature = oauth.hmacsign(this.method, baseurl, oa, consumer_secret, token_secret) | |
// oa.oauth_signature = signature | |
for (var i in form) { | |
if ( i.slice(0, 'oauth_') in _oauth) { | |
// skip | |
} else { | |
delete oa['oauth_'+i] | |
if (i !== 'x_auth_mode') delete oa[i] | |
} | |
} | |
this.headers.Authorization = | |
'OAuth '+Object.keys(oa).sort().map(function (i) {return i+'="'+oauth.rfc3986(oa[i])+'"'}).join(',') | |
this.headers.Authorization += ',oauth_signature="' + oauth.rfc3986(signature) + '"' | |
return this | |
} | |
Request.prototype.jar = function (jar) { | |
var cookies | |
if (this._redirectsFollowed === 0) { | |
this.originalCookieHeader = this.headers.cookie | |
} | |
if (jar === false) { | |
// disable cookies | |
cookies = false | |
this._disableCookies = true | |
} else if (jar) { | |
// fetch cookie from the user defined cookie jar | |
cookies = jar.get({ url: this.uri.href }) | |
} else { | |
// fetch cookie from the global cookie jar | |
cookies = cookieJar.get({ url: this.uri.href }) | |
} | |
if (cookies && cookies.length) { | |
var cookieString = cookies.map(function (c) { | |
return c.name + "=" + c.value | |
}).join("; ") | |
if (this.originalCookieHeader) { | |
// Don't overwrite existing Cookie header | |
this.headers.cookie = this.originalCookieHeader + '; ' + cookieString | |
} else { | |
this.headers.cookie = cookieString | |
} | |
} | |
this._jar = jar | |
return this | |
} | |
// Stream API | |
Request.prototype.pipe = function (dest, opts) { | |
if (this.response) { | |
if (this._destdata) { | |
throw new Error("You cannot pipe after data has been emitted from the response.") | |
} else if (this._ended) { | |
throw new Error("You cannot pipe after the response has been ended.") | |
} else { | |
stream.Stream.prototype.pipe.call(this, dest, opts) | |
this.pipeDest(dest) | |
return dest | |
} | |
} else { | |
this.dests.push(dest) | |
stream.Stream.prototype.pipe.call(this, dest, opts) | |
return dest | |
} | |
} | |
Request.prototype.write = function () { | |
if (!this._started) this.start() | |
return this.req.write.apply(this.req, arguments) | |
} | |
Request.prototype.end = function (chunk) { | |
if (chunk) this.write(chunk) | |
if (!this._started) this.start() | |
this.req.end() | |
} | |
Request.prototype.pause = function () { | |
if (!this.response) this._paused = true | |
else this.response.pause.apply(this.response, arguments) | |
} | |
Request.prototype.resume = function () { | |
if (!this.response) this._paused = false | |
else this.response.resume.apply(this.response, arguments) | |
} | |
Request.prototype.destroy = function () { | |
if (!this._ended) this.end() | |
} | |
// organize params for post, put, head, del | |
function initParams(uri, options, callback) { | |
if ((typeof options === 'function') && !callback) callback = options | |
if (options && typeof options === 'object') { | |
options.uri = uri | |
} else if (typeof uri === 'string') { | |
options = {uri:uri} | |
} else { | |
options = uri | |
uri = options.uri | |
} | |
return { uri: uri, options: options, callback: callback } | |
} | |
function request (uri, options, callback) { | |
if (typeof uri === 'undefined') throw new Error('undefined is not a valid uri or options object.') | |
if ((typeof options === 'function') && !callback) callback = options | |
if (options && typeof options === 'object') { | |
options.uri = uri | |
} else if (typeof uri === 'string') { | |
options = {uri:uri} | |
} else { | |
options = uri | |
} | |
if (callback) options.callback = callback | |
var r = new Request(options) | |
return r | |
} | |
module.exports = request | |
request.initParams = initParams | |
request.defaults = function (options, requester) { | |
var def = function (method) { | |
var d = function (uri, opts, callback) { | |
var params = initParams(uri, opts, callback) | |
for (var i in options) { | |
if (params.options[i] === undefined) params.options[i] = options[i] | |
} | |
if(typeof requester === 'function') { | |
if(method === request) { | |
method = requester | |
} else { | |
params.options._requester = requester | |
} | |
} | |
return method(params.options, params.callback) | |
} | |
return d | |
} | |
var de = def(request) | |
de.get = def(request.get) | |
de.post = def(request.post) | |
de.put = def(request.put) | |
de.head = def(request.head) | |
de.del = def(request.del) | |
de.cookie = def(request.cookie) | |
de.jar = request.jar | |
return de | |
} | |
request.forever = function (agentOptions, optionsArg) { | |
var options = {} | |
if (optionsArg) { | |
for (option in optionsArg) { | |
options[option] = optionsArg[option] | |
} | |
} | |
if (agentOptions) options.agentOptions = agentOptions | |
options.forever = true | |
return request.defaults(options) | |
} | |
request.get = request | |
request.post = function (uri, options, callback) { | |
var params = initParams(uri, options, callback) | |
params.options.method = 'POST' | |
return request(params.uri || null, params.options, params.callback) | |
} | |
request.put = function (uri, options, callback) { | |
var params = initParams(uri, options, callback) | |
params.options.method = 'PUT' | |
return request(params.uri || null, params.options, params.callback) | |
} | |
request.head = function (uri, options, callback) { | |
var params = initParams(uri, options, callback) | |
params.options.method = 'HEAD' | |
if (params.options.body || | |
params.options.requestBodyStream || | |
(params.options.json && typeof params.options.json !== 'boolean') || | |
params.options.multipart) { | |
throw new Error("HTTP HEAD requests MUST NOT include a request body.") | |
} | |
return request(params.uri || null, params.options, params.callback) | |
} | |
request.del = function (uri, options, callback) { | |
var params = initParams(uri, options, callback) | |
params.options.method = 'DELETE' | |
if(typeof params.options._requester === 'function') { | |
request = params.options._requester | |
} | |
return request(params.uri || null, params.options, params.callback) | |
} | |
request.jar = function () { | |
return new CookieJar | |
} | |
request.cookie = function (str) { | |
if (str && str.uri) str = str.uri | |
if (typeof str !== 'string') throw new Error("The cookie function only accepts STRING as param") | |
return new Cookie(str) | |
} | |
// Safe toJSON | |
function getSafe (self, uuid) { | |
if (typeof self === 'object' || typeof self === 'function') var safe = {} | |
if (Array.isArray(self)) var safe = [] | |
var recurse = [] | |
Object.defineProperty(self, uuid, {}) | |
var attrs = Object.keys(self).filter(function (i) { | |
if (i === uuid) return false | |
if ( (typeof self[i] !== 'object' && typeof self[i] !== 'function') || self[i] === null) return true | |
return !(Object.getOwnPropertyDescriptor(self[i], uuid)) | |
}) | |
for (var i=0;i<attrs.length;i++) { | |
if ( (typeof self[attrs[i]] !== 'object' && typeof self[attrs[i]] !== 'function') || | |
self[attrs[i]] === null | |
) { | |
safe[attrs[i]] = self[attrs[i]] | |
} else { | |
recurse.push(attrs[i]) | |
Object.defineProperty(self[attrs[i]], uuid, {}) | |
} | |
} | |
for (var i=0;i<recurse.length;i++) { | |
safe[recurse[i]] = getSafe(self[recurse[i]], uuid) | |
} | |
return safe | |
} | |
function toJSON () { | |
return getSafe(this, (((1+Math.random())*0x10000)|0).toString(16)) | |
} | |
Request.prototype.toJSON = toJSON | |
}).call(this,require('_process'),require("buffer").Buffer) | |
},{"./aws":3,"./forever":4,"./oauth":12,"./tunnel":13,"./uuid":14,"./vendor/cookie":15,"./vendor/cookie/jar":16,"_process":undefined,"buffer":undefined,"form-data":6,"http":undefined,"https":undefined,"mime":11,"querystring":undefined,"stream":undefined,"tls":undefined,"url":undefined,"util":undefined}],6:[function(require,module,exports){ | |
(function (process,Buffer){ | |
var CombinedStream = require('combined-stream'); | |
var util = require('util'); | |
var path = require('path'); | |
var http = require('http'); | |
var https = require('https'); | |
var parseUrl = require('url').parse; | |
var fs = require('fs'); | |
var mime = require('mime'); | |
var async = require('async'); | |
module.exports = FormData; | |
function FormData() { | |
this._overheadLength = 0; | |
this._valueLength = 0; | |
this._lengthRetrievers = []; | |
CombinedStream.call(this); | |
} | |
util.inherits(FormData, CombinedStream); | |
FormData.LINE_BREAK = '\r\n'; | |
FormData.prototype.append = function(field, value) { | |
var append = CombinedStream.prototype.append.bind(this); | |
// all that streamy business can't handle numbers | |
if (typeof value == 'number') value = ''+value; | |
var header = this._multiPartHeader(field, value); | |
var footer = this._multiPartFooter(field, value); | |
append(header); | |
append(value); | |
append(footer); | |
this._trackLength(header, value) | |
}; | |
FormData.prototype._trackLength = function(header, value) { | |
var valueLength = 0; | |
if (Buffer.isBuffer(value)) { | |
valueLength = value.length; | |
} else if (typeof value === 'string') { | |
valueLength = Buffer.byteLength(value); | |
} | |
this._valueLength += valueLength; | |
this._overheadLength += | |
Buffer.byteLength(header) + | |
+ FormData.LINE_BREAK.length; | |
// empty or ethier doesn't have path or not an http response | |
if (!value || ( !value.path && !(value.readable && value.hasOwnProperty('httpVersion')) )) { | |
return; | |
} | |
this._lengthRetrievers.push(function(next) { | |
// check if it's local file | |
if (value.hasOwnProperty('fd')) { | |
fs.stat(value.path, function(err, stat) { | |
if (err) { | |
next(err); | |
return; | |
} | |
next(null, stat.size); | |
}); | |
// or http response | |
} else if (value.hasOwnProperty('httpVersion')) { | |
next(null, +value.headers['content-length']); | |
// or request stream http://github.com/mikeal/request | |
} else if (value.hasOwnProperty('httpModule')) { | |
// wait till response come back | |
value.on('response', function(response) { | |
value.pause(); | |
next(null, +response.headers['content-length']); | |
}); | |
value.resume(); | |
// something else | |
} else { | |
next('Unknown stream'); | |
} | |
}); | |
}; | |
FormData.prototype._multiPartHeader = function(field, value) { | |
var boundary = this.getBoundary(); | |
var header = | |
'--' + boundary + FormData.LINE_BREAK + | |
'Content-Disposition: form-data; name="' + field + '"'; | |
// fs- and request- streams have path property | |
// TODO: Use request's response mime-type | |
if (value.path) { | |
header += | |
'; filename="' + path.basename(value.path) + '"' + FormData.LINE_BREAK + | |
'Content-Type: ' + mime.lookup(value.path); | |
// http response has not | |
} else if (value.readable && value.hasOwnProperty('httpVersion')) { | |
header += | |
'; filename="' + path.basename(value.client._httpMessage.path) + '"' + FormData.LINE_BREAK + | |
'Content-Type: ' + value.headers['content-type']; | |
} | |
header += FormData.LINE_BREAK + FormData.LINE_BREAK; | |
return header; | |
}; | |
FormData.prototype._multiPartFooter = function(field, value) { | |
return function(next) { | |
var footer = FormData.LINE_BREAK; | |
var lastPart = (this._streams.length === 0); | |
if (lastPart) { | |
footer += this._lastBoundary(); | |
} | |
next(footer); | |
}.bind(this); | |
}; | |
FormData.prototype._lastBoundary = function() { | |
return '--' + this.getBoundary() + '--'; | |
}; | |
FormData.prototype.getHeaders = function(userHeaders) { | |
var formHeaders = { | |
'content-type': 'multipart/form-data; boundary=' + this.getBoundary() | |
}; | |
for (var header in userHeaders) { | |
formHeaders[header.toLowerCase()] = userHeaders[header]; | |
} | |
return formHeaders; | |
} | |
FormData.prototype.getCustomHeaders = function(contentType) { | |
contentType = contentType ? contentType : 'multipart/form-data'; | |
var formHeaders = { | |
'content-type': contentType + '; boundary=' + this.getBoundary(), | |
'content-length': this.getLengthSync() | |
}; | |
return formHeaders; | |
} | |
FormData.prototype.getBoundary = function() { | |
if (!this._boundary) { | |
this._generateBoundary(); | |
} | |
return this._boundary; | |
}; | |
FormData.prototype._generateBoundary = function() { | |
// This generates a 50 character boundary similar to those used by Firefox. | |
// They are optimized for boyer-moore parsing. | |
var boundary = '--------------------------'; | |
for (var i = 0; i < 24; i++) { | |
boundary += Math.floor(Math.random() * 10).toString(16); | |
} | |
this._boundary = boundary; | |
}; | |
FormData.prototype.getLengthSync = function() { | |
var knownLength = this._overheadLength + this._valueLength; | |
if (this._streams.length) { | |
knownLength += this._lastBoundary().length; | |
} | |
return knownLength; | |
}; | |
FormData.prototype.getLength = function(cb) { | |
var knownLength = this._overheadLength + this._valueLength; | |
if (this._streams.length) { | |
knownLength += this._lastBoundary().length; | |
} | |
if (!this._lengthRetrievers.length) { | |
process.nextTick(cb.bind(this, null, knownLength)); | |
return; | |
} | |
async.parallel(this._lengthRetrievers, function(err, values) { | |
if (err) { | |
cb(err); | |
return; | |
} | |
values.forEach(function(length) { | |
knownLength += length; | |
}); | |
cb(null, knownLength); | |
}); | |
}; | |
FormData.prototype.submit = function(url, cb) { | |
this.getLength(function(err, length) { | |
var request | |
, parsedUrl = parseUrl(url) | |
, options = { | |
method: 'post', | |
port: parsedUrl.port || 80, | |
path: parsedUrl.pathname, | |
headers: this.getHeaders({'Content-Length': length}), | |
host: parsedUrl.hostname | |
}; | |
if (parsedUrl.protocol == 'https:') { | |
// override default port | |
if (!parsedUrl.port) options.port = 443; | |
request = https.request(options); | |
} else { | |
request = http.request(options); | |
} | |
this.pipe(request); | |
if (cb) { | |
request.on('error', cb); | |
request.on('response', cb.bind(this, null)); | |
} | |
return request; | |
}.bind(this)); | |
}; | |
}).call(this,require('_process'),require("buffer").Buffer) | |
},{"_process":undefined,"async":7,"buffer":undefined,"combined-stream":9,"fs":undefined,"http":undefined,"https":undefined,"mime":11,"path":undefined,"url":undefined,"util":undefined}],7:[function(require,module,exports){ | |
// This file is just added for convenience so this repository can be | |
// directly checked out into a project's deps folder | |
module.exports = require('./lib/async'); | |
},{"./lib/async":8}],8:[function(require,module,exports){ | |
(function (process){ | |
/*global setTimeout: false, console: false */ | |
(function () { | |
var async = {}; | |
// global on the server, window in the browser | |
var root = this, | |
previous_async = root.async; | |
if (typeof module !== 'undefined' && module.exports) { | |
module.exports = async; | |
} | |
else { | |
root.async = async; | |
} | |
async.noConflict = function () { | |
root.async = previous_async; | |
return async; | |
}; | |
//// cross-browser compatiblity functions //// | |
var _forEach = function (arr, iterator) { | |
if (arr.forEach) { | |
return arr.forEach(iterator); | |
} | |
for (var i = 0; i < arr.length; i += 1) { | |
iterator(arr[i], i, arr); | |
} | |
}; | |
var _map = function (arr, iterator) { | |
if (arr.map) { | |
return arr.map(iterator); | |
} | |
var results = []; | |
_forEach(arr, function (x, i, a) { | |
results.push(iterator(x, i, a)); | |
}); | |
return results; | |
}; | |
var _reduce = function (arr, iterator, memo) { | |
if (arr.reduce) { | |
return arr.reduce(iterator, memo); | |
} | |
_forEach(arr, function (x, i, a) { | |
memo = iterator(memo, x, i, a); | |
}); | |
return memo; | |
}; | |
var _keys = function (obj) { | |
if (Object.keys) { | |
return Object.keys(obj); | |
} | |
var keys = []; | |
for (var k in obj) { | |
if (obj.hasOwnProperty(k)) { | |
keys.push(k); | |
} | |
} | |
return keys; | |
}; | |
var _indexOf = function (arr, item) { | |
if (arr.indexOf) { | |
return arr.indexOf(item); | |
} | |
for (var i = 0; i < arr.length; i += 1) { | |
if (arr[i] === item) { | |
return i; | |
} | |
} | |
return -1; | |
}; | |
//// exported async module functions //// | |
//// nextTick implementation with browser-compatible fallback //// | |
if (typeof process === 'undefined' || !(process.nextTick)) { | |
async.nextTick = function (fn) { | |
setTimeout(fn, 0); | |
}; | |
} | |
else { | |
async.nextTick = process.nextTick; | |
} | |
async.forEach = function (arr, iterator, callback) { | |
if (!arr.length) { | |
return callback(); | |
} | |
var completed = 0; | |
_forEach(arr, function (x) { | |
iterator(x, function (err) { | |
if (err) { | |
callback(err); | |
callback = function () {}; | |
} | |
else { | |
completed += 1; | |
if (completed === arr.length) { | |
callback(); | |
} | |
} | |
}); | |
}); | |
}; | |
async.forEachSeries = function (arr, iterator, callback) { | |
if (!arr.length) { | |
return callback(); | |
} | |
var completed = 0; | |
var iterate = function () { | |
iterator(arr[completed], function (err) { | |
if (err) { | |
callback(err); | |
callback = function () {}; | |
} | |
else { | |
completed += 1; | |
if (completed === arr.length) { | |
callback(); | |
} | |
else { | |
iterate(); | |
} | |
} | |
}); | |
}; | |
iterate(); | |
}; | |
var doParallel = function (fn) { | |
return function () { | |
var args = Array.prototype.slice.call(arguments); | |
return fn.apply(null, [async.forEach].concat(args)); | |
}; | |
}; | |
var doSeries = function (fn) { | |
return function () { | |
var args = Array.prototype.slice.call(arguments); | |
return fn.apply(null, [async.forEachSeries].concat(args)); | |
}; | |
}; | |
var _asyncMap = function (eachfn, arr, iterator, callback) { | |
var results = []; | |
arr = _map(arr, function (x, i) { | |
return {index: i, value: x}; | |
}); | |
eachfn(arr, function (x, callback) { | |
iterator(x.value, function (err, v) { | |
results[x.index] = v; | |
callback(err); | |
}); | |
}, function (err) { | |
callback(err, results); | |
}); | |
}; | |
async.map = doParallel(_asyncMap); | |
async.mapSeries = doSeries(_asyncMap); | |
// reduce only has a series version, as doing reduce in parallel won't | |
// work in many situations. | |
async.reduce = function (arr, memo, iterator, callback) { | |
async.forEachSeries(arr, function (x, callback) { | |
iterator(memo, x, function (err, v) { | |
memo = v; | |
callback(err); | |
}); | |
}, function (err) { | |
callback(err, memo); | |
}); | |
}; | |
// inject alias | |
async.inject = async.reduce; | |
// foldl alias | |
async.foldl = async.reduce; | |
async.reduceRight = function (arr, memo, iterator, callback) { | |
var reversed = _map(arr, function (x) { | |
return x; | |
}).reverse(); | |
async.reduce(reversed, memo, iterator, callback); | |
}; | |
// foldr alias | |
async.foldr = async.reduceRight; | |
var _filter = function (eachfn, arr, iterator, callback) { | |
var results = []; | |
arr = _map(arr, function (x, i) { | |
return {index: i, value: x}; | |
}); | |
eachfn(arr, function (x, callback) { | |
iterator(x.value, function (v) { | |
if (v) { | |
results.push(x); | |
} | |
callback(); | |
}); | |
}, function (err) { | |
callback(_map(results.sort(function (a, b) { | |
return a.index - b.index; | |
}), function (x) { | |
return x.value; | |
})); | |
}); | |
}; | |
async.filter = doParallel(_filter); | |
async.filterSeries = doSeries(_filter); | |
// select alias | |
async.select = async.filter; | |
async.selectSeries = async.filterSeries; | |
var _reject = function (eachfn, arr, iterator, callback) { | |
var results = []; | |
arr = _map(arr, function (x, i) { | |
return {index: i, value: x}; | |
}); | |
eachfn(arr, function (x, callback) { | |
iterator(x.value, function (v) { | |
if (!v) { | |
results.push(x); | |
} | |
callback(); | |
}); | |
}, function (err) { | |
callback(_map(results.sort(function (a, b) { | |
return a.index - b.index; | |
}), function (x) { | |
return x.value; | |
})); | |
}); | |
}; | |
async.reject = doParallel(_reject); | |
async.rejectSeries = doSeries(_reject); | |
var _detect = function (eachfn, arr, iterator, main_callback) { | |
eachfn(arr, function (x, callback) { | |
iterator(x, function (result) { | |
if (result) { | |
main_callback(x); | |
} | |
else { | |
callback(); | |
} | |
}); | |
}, function (err) { | |
main_callback(); | |
}); | |
}; | |
async.detect = doParallel(_detect); | |
async.detectSeries = doSeries(_detect); | |
async.some = function (arr, iterator, main_callback) { | |
async.forEach(arr, function (x, callback) { | |
iterator(x, function (v) { | |
if (v) { | |
main_callback(true); | |
main_callback = function () {}; | |
} | |
callback(); | |
}); | |
}, function (err) { | |
main_callback(false); | |
}); | |
}; | |
// any alias | |
async.any = async.some; | |
async.every = function (arr, iterator, main_callback) { | |
async.forEach(arr, function (x, callback) { | |
iterator(x, function (v) { | |
if (!v) { | |
main_callback(false); | |
main_callback = function () {}; | |
} | |
callback(); | |
}); | |
}, function (err) { | |
main_callback(true); | |
}); | |
}; | |
// all alias | |
async.all = async.every; | |
async.sortBy = function (arr, iterator, callback) { | |
async.map(arr, function (x, callback) { | |
iterator(x, function (err, criteria) { | |
if (err) { | |
callback(err); | |
} | |
else { | |
callback(null, {value: x, criteria: criteria}); | |
} | |
}); | |
}, function (err, results) { | |
if (err) { | |
return callback(err); | |
} | |
else { | |
var fn = function (left, right) { | |
var a = left.criteria, b = right.criteria; | |
return a < b ? -1 : a > b ? 1 : 0; | |
}; | |
callback(null, _map(results.sort(fn), function (x) { | |
return x.value; | |
})); | |
} | |
}); | |
}; | |
async.auto = function (tasks, callback) { | |
callback = callback || function () {}; | |
var keys = _keys(tasks); | |
if (!keys.length) { | |
return callback(null); | |
} | |
var completed = []; | |
var listeners = []; | |
var addListener = function (fn) { | |
listeners.unshift(fn); | |
}; | |
var removeListener = function (fn) { | |
for (var i = 0; i < listeners.length; i += 1) { | |
if (listeners[i] === fn) { | |
listeners.splice(i, 1); | |
return; | |
} | |
} | |
}; | |
var taskComplete = function () { | |
_forEach(listeners, function (fn) { | |
fn(); | |
}); | |
}; | |
addListener(function () { | |
if (completed.length === keys.length) { | |
callback(null); | |
} | |
}); | |
_forEach(keys, function (k) { | |
var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k]; | |
var taskCallback = function (err) { | |
if (err) { | |
callback(err); | |
// stop subsequent errors hitting callback multiple times | |
callback = function () {}; | |
} | |
else { | |
completed.push(k); | |
taskComplete(); | |
} | |
}; | |
var requires = task.slice(0, Math.abs(task.length - 1)) || []; | |
var ready = function () { | |
return _reduce(requires, function (a, x) { | |
return (a && _indexOf(completed, x) !== -1); | |
}, true); | |
}; | |
if (ready()) { | |
task[task.length - 1](taskCallback); | |
} | |
else { | |
var listener = function () { | |
if (ready()) { | |
removeListener(listener); | |
task[task.length - 1](taskCallback); | |
} | |
}; | |
addListener(listener); | |
} | |
}); | |
}; | |
async.waterfall = function (tasks, callback) { | |
if (!tasks.length) { | |
return callback(); | |
} | |
callback = callback || function () {}; | |
var wrapIterator = function (iterator) { | |
return function (err) { | |
if (err) { | |
callback(err); | |
callback = function () {}; | |
} | |
else { | |
var args = Array.prototype.slice.call(arguments, 1); | |
var next = iterator.next(); | |
if (next) { | |
args.push(wrapIterator(next)); | |
} | |
else { | |
args.push(callback); | |
} | |
async.nextTick(function () { | |
iterator.apply(null, args); | |
}); | |
} | |
}; | |
}; | |
wrapIterator(async.iterator(tasks))(); | |
}; | |
async.parallel = function (tasks, callback) { | |
callback = callback || function () {}; | |
if (tasks.constructor === Array) { | |
async.map(tasks, function (fn, callback) { | |
if (fn) { | |
fn(function (err) { | |
var args = Array.prototype.slice.call(arguments, 1); | |
if (args.length <= 1) { | |
args = args[0]; | |
} | |
callback.call(null, err, args); | |
}); | |
} | |
}, callback); | |
} | |
else { | |
var results = {}; | |
async.forEach(_keys(tasks), function (k, callback) { | |
tasks[k](function (err) { | |
var args = Array.prototype.slice.call(arguments, 1); | |
if (args.length <= 1) { | |
args = args[0]; | |
} | |
results[k] = args; | |
callback(err); | |
}); | |
}, function (err) { | |
callback(err, results); | |
}); | |
} | |
}; | |
async.series = function (tasks, callback) { | |
callback = callback || function () {}; | |
if (tasks.constructor === Array) { | |
async.mapSeries(tasks, function (fn, callback) { | |
if (fn) { | |
fn(function (err) { | |
var args = Array.prototype.slice.call(arguments, 1); | |
if (args.length <= 1) { | |
args = args[0]; | |
} | |
callback.call(null, err, args); | |
}); | |
} | |
}, callback); | |
} | |
else { | |
var results = {}; | |
async.forEachSeries(_keys(tasks), function (k, callback) { | |
tasks[k](function (err) { | |
var args = Array.prototype.slice.call(arguments, 1); | |
if (args.length <= 1) { | |
args = args[0]; | |
} | |
results[k] = args; | |
callback(err); | |
}); | |
}, function (err) { | |
callback(err, results); | |
}); | |
} | |
}; | |
async.iterator = function (tasks) { | |
var makeCallback = function (index) { | |
var fn = function () { | |
if (tasks.length) { | |
tasks[index].apply(null, arguments); | |
} | |
return fn.next(); | |
}; | |
fn.next = function () { | |
return (index < tasks.length - 1) ? makeCallback(index + 1): null; | |
}; | |
return fn; | |
}; | |
return makeCallback(0); | |
}; | |
async.apply = function (fn) { | |
var args = Array.prototype.slice.call(arguments, 1); | |
return function () { | |
return fn.apply( | |
null, args.concat(Array.prototype.slice.call(arguments)) | |
); | |
}; | |
}; | |
var _concat = function (eachfn, arr, fn, callback) { | |
var r = []; | |
eachfn(arr, function (x, cb) { | |
fn(x, function (err, y) { | |
r = r.concat(y || []); | |
cb(err); | |
}); | |
}, function (err) { | |
callback(err, r); | |
}); | |
}; | |
async.concat = doParallel(_concat); | |
async.concatSeries = doSeries(_concat); | |
async.whilst = function (test, iterator, callback) { | |
if (test()) { | |
iterator(function (err) { | |
if (err) { | |
return callback(err); | |
} | |
async.whilst(test, iterator, callback); | |
}); | |
} | |
else { | |
callback(); | |
} | |
}; | |
async.until = function (test, iterator, callback) { | |
if (!test()) { | |
iterator(function (err) { | |
if (err) { | |
return callback(err); | |
} | |
async.until(test, iterator, callback); | |
}); | |
} | |
else { | |
callback(); | |
} | |
}; | |
async.queue = function (worker, concurrency) { | |
var workers = 0; | |
var tasks = []; | |
var q = { | |
concurrency: concurrency, | |
saturated: null, | |
empty: null, | |
drain: null, | |
push: function (data, callback) { | |
tasks.push({data: data, callback: callback}); | |
if(q.saturated && tasks.length == concurrency) q.saturated(); | |
async.nextTick(q.process); | |
}, | |
process: function () { | |
if (workers < q.concurrency && tasks.length) { | |
var task = tasks.splice(0, 1)[0]; | |
if(q.empty && tasks.length == 0) q.empty(); | |
workers += 1; | |
worker(task.data, function () { | |
workers -= 1; | |
if (task.callback) { | |
task.callback.apply(task, arguments); | |
} | |
if(q.drain && tasks.length + workers == 0) q.drain(); | |
q.process(); | |
}); | |
} | |
}, | |
length: function () { | |
return tasks.length; | |
}, | |
running: function () { | |
return workers; | |
} | |
}; | |
return q; | |
}; | |
var _console_fn = function (name) { | |
return function (fn) { | |
var args = Array.prototype.slice.call(arguments, 1); | |
fn.apply(null, args.concat([function (err) { | |
var args = Array.prototype.slice.call(arguments, 1); | |
if (typeof console !== 'undefined') { | |
if (err) { | |
if (console.error) { | |
console.error(err); | |
} | |
} | |
else if (console[name]) { | |
_forEach(args, function (x) { | |
console[name](x); | |
}); | |
} | |
} | |
}])); | |
}; | |
}; | |
async.log = _console_fn('log'); | |
async.dir = _console_fn('dir'); | |
/*async.info = _console_fn('info'); | |
async.warn = _console_fn('warn'); | |
async.error = _console_fn('error');*/ | |
async.memoize = function (fn, hasher) { | |
var memo = {}; | |
hasher = hasher || function (x) { | |
return x; | |
}; | |
return function () { | |
var args = Array.prototype.slice.call(arguments); | |
var callback = args.pop(); | |
var key = hasher.apply(null, args); | |
if (key in memo) { | |
callback.apply(null, memo[key]); | |
} | |
else { | |
fn.apply(null, args.concat([function () { | |
memo[key] = arguments; | |
callback.apply(null, arguments); | |
}])); | |
} | |
}; | |
}; | |
}()); | |
}).call(this,require('_process')) | |
},{"_process":undefined}],9:[function(require,module,exports){ | |
(function (Buffer){ | |
var util = require('util'); | |
var Stream = require('stream').Stream; | |
var DelayedStream = require('delayed-stream'); | |
module.exports = CombinedStream; | |
function CombinedStream() { | |
this.writable = false; | |
this.readable = true; | |
this.dataSize = 0; | |
this.maxDataSize = 2 * 1024 * 1024; | |
this.pauseStreams = true; | |
this._released = false; | |
this._streams = []; | |
this._currentStream = null; | |
} | |
util.inherits(CombinedStream, Stream); | |
CombinedStream.create = function(options) { | |
var combinedStream = new this(); | |
options = options || {}; | |
for (var option in options) { | |
combinedStream[option] = options[option]; | |
} | |
return combinedStream; | |
}; | |
CombinedStream.isStreamLike = function(stream) { | |
return (typeof stream !== 'function') | |
&& (typeof stream !== 'string') | |
&& (!Buffer.isBuffer(stream)); | |
}; | |
CombinedStream.prototype.append = function(stream) { | |
var isStreamLike = CombinedStream.isStreamLike(stream); | |
if (isStreamLike) { | |
if (!(stream instanceof DelayedStream)) { | |
stream.on('data', this._checkDataSize.bind(this)); | |
stream = DelayedStream.create(stream, { | |
maxDataSize: Infinity, | |
pauseStream: this.pauseStreams, | |
}); | |
} | |
this._handleErrors(stream); | |
if (this.pauseStreams) { | |
stream.pause(); | |
} | |
} | |
this._streams.push(stream); | |
return this; | |
}; | |
CombinedStream.prototype.pipe = function(dest, options) { | |
Stream.prototype.pipe.call(this, dest, options); | |
this.resume(); | |
}; | |
CombinedStream.prototype._getNext = function() { | |
this._currentStream = null; | |
var stream = this._streams.shift(); | |
if (!stream) { | |
this.end(); | |
return; | |
} | |
if (typeof stream !== 'function') { | |
this._pipeNext(stream); | |
return; | |
} | |
var getStream = stream; | |
getStream(function(stream) { | |
var isStreamLike = CombinedStream.isStreamLike(stream); | |
if (isStreamLike) { | |
stream.on('data', this._checkDataSize.bind(this)); | |
this._handleErrors(stream); | |
} | |
this._pipeNext(stream); | |
}.bind(this)); | |
}; | |
CombinedStream.prototype._pipeNext = function(stream) { | |
this._currentStream = stream; | |
var isStreamLike = CombinedStream.isStreamLike(stream); | |
if (isStreamLike) { | |
stream.on('end', this._getNext.bind(this)) | |
stream.pipe(this, {end: false}); | |
return; | |
} | |
var value = stream; | |
this.write(value); | |
this._getNext(); | |
}; | |
CombinedStream.prototype._handleErrors = function(stream) { | |
var self = this; | |
stream.on('error', function(err) { | |
self._emitError(err); | |
}); | |
}; | |
CombinedStream.prototype.write = function(data) { | |
this.emit('data', data); | |
}; | |
CombinedStream.prototype.pause = function() { | |
if (!this.pauseStreams) { | |
return; | |
} | |
this.emit('pause'); | |
}; | |
CombinedStream.prototype.resume = function() { | |
if (!this._released) { | |
this._released = true; | |
this.writable = true; | |
this._getNext(); | |
} | |
this.emit('resume'); | |
}; | |
CombinedStream.prototype.end = function() { | |
this._reset(); | |
this.emit('end'); | |
}; | |
CombinedStream.prototype.destroy = function() { | |
this._reset(); | |
this.emit('close'); | |
}; | |
CombinedStream.prototype._reset = function() { | |
this.writable = false; | |
this._streams = []; | |
this._currentStream = null; | |
}; | |
CombinedStream.prototype._checkDataSize = function() { | |
this._updateDataSize(); | |
if (this.dataSize <= this.maxDataSize) { | |
return; | |
} | |
var message = | |
'DelayedStream#maxDataSize of ' + this.maxDataSize + ' bytes exceeded.' | |
this._emitError(new Error(message)); | |
}; | |
CombinedStream.prototype._updateDataSize = function() { | |
this.dataSize = 0; | |
var self = this; | |
this._streams.forEach(function(stream) { | |
if (!stream.dataSize) { | |
return; | |
} | |
self.dataSize += stream.dataSize; | |
}); | |
if (this._currentStream && this._currentStream.dataSize) { | |
this.dataSize += this._currentStream.dataSize; | |
} | |
}; | |
CombinedStream.prototype._emitError = function(err) { | |
this._reset(); | |
this.emit('error', err); | |
}; | |
}).call(this,{"isBuffer":require("../../../../../../../../../../../work/webtask-pen/node_modules/is-buffer/index.js")}) | |
},{"../../../../../../../../../../../work/webtask-pen/node_modules/is-buffer/index.js":20,"delayed-stream":10,"stream":undefined,"util":undefined}],10:[function(require,module,exports){ | |
var Stream = require('stream').Stream; | |
var util = require('util'); | |
module.exports = DelayedStream; | |
function DelayedStream() { | |
this.source = null; | |
this.dataSize = 0; | |
this.maxDataSize = 1024 * 1024; | |
this.pauseStream = true; | |
this._maxDataSizeExceeded = false; | |
this._released = false; | |
this._bufferedEvents = []; | |
} | |
util.inherits(DelayedStream, Stream); | |
DelayedStream.create = function(source, options) { | |
var delayedStream = new this(); | |
options = options || {}; | |
for (var option in options) { | |
delayedStream[option] = options[option]; | |
} | |
delayedStream.source = source; | |
var realEmit = source.emit; | |
source.emit = function() { | |
delayedStream._handleEmit(arguments); | |
return realEmit.apply(source, arguments); | |
}; | |
source.on('error', function() {}); | |
if (delayedStream.pauseStream) { | |
source.pause(); | |
} | |
return delayedStream; | |
}; | |
DelayedStream.prototype.__defineGetter__('readable', function() { | |
return this.source.readable; | |
}); | |
DelayedStream.prototype.resume = function() { | |
if (!this._released) { | |
this.release(); | |
} | |
this.source.resume(); | |
}; | |
DelayedStream.prototype.pause = function() { | |
this.source.pause(); | |
}; | |
DelayedStream.prototype.release = function() { | |
this._released = true; | |
this._bufferedEvents.forEach(function(args) { | |
this.emit.apply(this, args); | |
}.bind(this)); | |
this._bufferedEvents = []; | |
}; | |
DelayedStream.prototype.pipe = function() { | |
var r = Stream.prototype.pipe.apply(this, arguments); | |
this.resume(); | |
return r; | |
}; | |
DelayedStream.prototype._handleEmit = function(args) { | |
if (this._released) { | |
this.emit.apply(this, args); | |
return; | |
} | |
if (args[0] === 'data') { | |
this.dataSize += args[1].length; | |
this._checkIfMaxDataSizeExceeded(); | |
} | |
this._bufferedEvents.push(args); | |
}; | |
DelayedStream.prototype._checkIfMaxDataSizeExceeded = function() { | |
if (this._maxDataSizeExceeded) { | |
return; | |
} | |
if (this.dataSize <= this.maxDataSize) { | |
return; | |
} | |
this._maxDataSizeExceeded = true; | |
var message = | |
'DelayedStream#maxDataSize of ' + this.maxDataSize + ' bytes exceeded.' | |
this.emit('error', new Error(message)); | |
}; | |
},{"stream":undefined,"util":undefined}],11:[function(require,module,exports){ | |
(function (__dirname){ | |
var path = require('path'); | |
var fs = require('fs'); | |
function Mime() { | |
// Map of extension -> mime type | |
this.types = Object.create(null); | |
// Map of mime type -> extension | |
this.extensions = Object.create(null); | |
} | |
/** | |
* Define mimetype -> extension mappings. Each key is a mime-type that maps | |
* to an array of extensions associated with the type. The first extension is | |
* used as the default extension for the type. | |
* | |
* e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']}); | |
* | |
* @param map (Object) type definitions | |
*/ | |
Mime.prototype.define = function (map) { | |
for (var type in map) { | |
var exts = map[type]; | |
for (var i = 0; i < exts.length; i++) { | |
this.types[exts[i]] = type; | |
} | |
// Default extension is the first one we encounter | |
if (!this.extensions[type]) { | |
this.extensions[type] = exts[0]; | |
} | |
} | |
}; | |
/** | |
* Load an Apache2-style ".types" file | |
* | |
* This may be called multiple times (it's expected). Where files declare | |
* overlapping types/extensions, the last file wins. | |
* | |
* @param file (String) path of file to load. | |
*/ | |
Mime.prototype.load = function(file) { | |
// Read file and split into lines | |
var map = {}, | |
content = fs.readFileSync(file, 'ascii'), | |
lines = content.split(/[\r\n]+/); | |
lines.forEach(function(line) { | |
// Clean up whitespace/comments, and split into fields | |
var fields = line.replace(/\s*#.*|^\s*|\s*$/g, '').split(/\s+/); | |
map[fields.shift()] = fields; | |
}); | |
this.define(map); | |
}; | |
/** | |
* Lookup a mime type based on extension | |
*/ | |
Mime.prototype.lookup = function(path, fallback) { | |
var ext = path.replace(/.*[\.\/]/, '').toLowerCase(); | |
return this.types[ext] || fallback || this.default_type; | |
}; | |
/** | |
* Return file extension associated with a mime type | |
*/ | |
Mime.prototype.extension = function(mimeType) { | |
return this.extensions[mimeType]; | |
}; | |
// Default instance | |
var mime = new Mime(); | |
// Load local copy of | |
// http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types | |
mime.load(path.join(__dirname, 'types/mime.types')); | |
// Load additional types from node.js community | |
mime.load(path.join(__dirname, 'types/node.types')); | |
// Default type | |
mime.default_type = mime.lookup('bin'); | |
// | |
// Additional API specific to the default instance | |
// | |
mime.Mime = Mime; | |
/** | |
* Lookup a charset based on mime type. | |
*/ | |
mime.charsets = { | |
lookup: function(mimeType, fallback) { | |
// Assume text types are utf8 | |
return (/^text\//).test(mimeType) ? 'UTF-8' : fallback; | |
} | |
} | |
module.exports = mime; | |
}).call(this,"/node_modules\\request\\node_modules\\mime") | |
},{"fs":undefined,"path":undefined}],12:[function(require,module,exports){ | |
var crypto = require('crypto') | |
, qs = require('querystring') | |
; | |
function sha1 (key, body) { | |
return crypto.createHmac('sha1', key).update(body).digest('base64') | |
} | |
function rfc3986 (str) { | |
return encodeURIComponent(str) | |
.replace(/!/g,'%21') | |
.replace(/\*/g,'%2A') | |
.replace(/\(/g,'%28') | |
.replace(/\)/g,'%29') | |
.replace(/'/g,'%27') | |
; | |
} | |
function hmacsign (httpMethod, base_uri, params, consumer_secret, token_secret) { | |
// adapted from https://dev.twitter.com/docs/auth/oauth and | |
// https://dev.twitter.com/docs/auth/creating-signature | |
var querystring = Object.keys(params).sort().map(function(key){ | |
// big WTF here with the escape + encoding but it's what twitter wants | |
return escape(rfc3986(key)) + "%3D" + escape(rfc3986(params[key])) | |
}).join('%26') | |
var base = [ | |
httpMethod ? httpMethod.toUpperCase() : 'GET', | |
rfc3986(base_uri), | |
querystring | |
].join('&') | |
var key = [ | |
consumer_secret, | |
token_secret || '' | |
].map(rfc3986).join('&') | |
return sha1(key, base) | |
} | |
exports.hmacsign = hmacsign | |
exports.rfc3986 = rfc3986 | |
},{"crypto":undefined,"querystring":undefined}],13:[function(require,module,exports){ | |
(function (process,Buffer){ | |
'use strict' | |
var net = require('net') | |
, tls = require('tls') | |
, http = require('http') | |
, https = require('https') | |
, events = require('events') | |
, assert = require('assert') | |
, util = require('util') | |
; | |
exports.httpOverHttp = httpOverHttp | |
exports.httpsOverHttp = httpsOverHttp | |
exports.httpOverHttps = httpOverHttps | |
exports.httpsOverHttps = httpsOverHttps | |
function httpOverHttp(options) { | |
var agent = new TunnelingAgent(options) | |
agent.request = http.request | |
return agent | |
} | |
function httpsOverHttp(options) { | |
var agent = new TunnelingAgent(options) | |
agent.request = http.request | |
agent.createSocket = createSecureSocket | |
return agent | |
} | |
function httpOverHttps(options) { | |
var agent = new TunnelingAgent(options) | |
agent.request = https.request | |
return agent | |
} | |
function httpsOverHttps(options) { | |
var agent = new TunnelingAgent(options) | |
agent.request = https.request | |
agent.createSocket = createSecureSocket | |
return agent | |
} | |
function TunnelingAgent(options) { | |
var self = this | |
self.options = options || {} | |
self.proxyOptions = self.options.proxy || {} | |
self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets | |
self.requests = [] | |
self.sockets = [] | |
self.on('free', function onFree(socket, host, port) { | |
for (var i = 0, len = self.requests.length; i < len; ++i) { | |
var pending = self.requests[i] | |
if (pending.host === host && pending.port === port) { | |
// Detect the request to connect same origin server, | |
// reuse the connection. | |
self.requests.splice(i, 1) | |
pending.request.onSocket(socket) | |
return | |
} | |
} | |
socket.destroy() | |
self.removeSocket(socket) | |
}) | |
} | |
util.inherits(TunnelingAgent, events.EventEmitter) | |
TunnelingAgent.prototype.addRequest = function addRequest(req, host, port) { | |
var self = this | |
if (self.sockets.length >= this.maxSockets) { | |
// We are over limit so we'll add it to the queue. | |
self.requests.push({host: host, port: port, request: req}) | |
return | |
} | |
// If we are under maxSockets create a new one. | |
self.createSocket({host: host, port: port, request: req}, function(socket) { | |
socket.on('free', onFree) | |
socket.on('close', onCloseOrRemove) | |
socket.on('agentRemove', onCloseOrRemove) | |
req.onSocket(socket) | |
function onFree() { | |
self.emit('free', socket, host, port) | |
} | |
function onCloseOrRemove(err) { | |
self.removeSocket() | |
socket.removeListener('free', onFree) | |
socket.removeListener('close', onCloseOrRemove) | |
socket.removeListener('agentRemove', onCloseOrRemove) | |
} | |
}) | |
} | |
TunnelingAgent.prototype.createSocket = function createSocket(options, cb) { | |
var self = this | |
var placeholder = {} | |
self.sockets.push(placeholder) | |
var connectOptions = mergeOptions({}, self.proxyOptions, | |
{ method: 'CONNECT' | |
, path: options.host + ':' + options.port | |
, agent: false | |
} | |
) | |
if (connectOptions.proxyAuth) { | |
connectOptions.headers = connectOptions.headers || {} | |
connectOptions.headers['Proxy-Authorization'] = 'Basic ' + | |
new Buffer(connectOptions.proxyAuth).toString('base64') | |
} | |
debug('making CONNECT request') | |
var connectReq = self.request(connectOptions) | |
connectReq.useChunkedEncodingByDefault = false // for v0.6 | |
connectReq.once('response', onResponse) // for v0.6 | |
connectReq.once('upgrade', onUpgrade) // for v0.6 | |
connectReq.once('connect', onConnect) // for v0.7 or later | |
connectReq.once('error', onError) | |
connectReq.end() | |
function onResponse(res) { | |
// Very hacky. This is necessary to avoid http-parser leaks. | |
res.upgrade = true | |
} | |
function onUpgrade(res, socket, head) { | |
// Hacky. | |
process.nextTick(function() { | |
onConnect(res, socket, head) | |
}) | |
} | |
function onConnect(res, socket, head) { | |
connectReq.removeAllListeners() | |
socket.removeAllListeners() | |
if (res.statusCode === 200) { | |
assert.equal(head.length, 0) | |
debug('tunneling connection has established') | |
self.sockets[self.sockets.indexOf(placeholder)] = socket | |
cb(socket) | |
} else { | |
debug('tunneling socket could not be established, statusCode=%d', res.statusCode) | |
var error = new Error('tunneling socket could not be established, ' + 'statusCode=' + res.statusCode) | |
error.code = 'ECONNRESET' | |
options.request.emit('error', error) | |
self.removeSocket(placeholder) | |
} | |
} | |
function onError(cause) { | |
connectReq.removeAllListeners() | |
debug('tunneling socket could not be established, cause=%s\n', cause.message, cause.stack) | |
var error = new Error('tunneling socket could not be established, ' + 'cause=' + cause.message) | |
error.code = 'ECONNRESET' | |
options.request.emit('error', error) | |
self.removeSocket(placeholder) | |
} | |
} | |
TunnelingAgent.prototype.removeSocket = function removeSocket(socket) { | |
var pos = this.sockets.indexOf(socket) | |
if (pos === -1) return | |
this.sockets.splice(pos, 1) | |
var pending = this.requests.shift() | |
if (pending) { | |
// If we have pending requests and a socket gets closed a new one | |
// needs to be created to take over in the pool for the one that closed. | |
this.createSocket(pending, function(socket) { | |
pending.request.onSocket(socket) | |
}) | |
} | |
} | |
function createSecureSocket(options, cb) { | |
var self = this | |
TunnelingAgent.prototype.createSocket.call(self, options, function(socket) { | |
// 0 is dummy port for v0.6 | |
var secureSocket = tls.connect(0, mergeOptions({}, self.options, | |
{ servername: options.host | |
, socket: socket | |
} | |
)) | |
cb(secureSocket) | |
}) | |
} | |
function mergeOptions(target) { | |
for (var i = 1, len = arguments.length; i < len; ++i) { | |
var overrides = arguments[i] | |
if (typeof overrides === 'object') { | |
var keys = Object.keys(overrides) | |
for (var j = 0, keyLen = keys.length; j < keyLen; ++j) { | |
var k = keys[j] | |
if (overrides[k] !== undefined) { | |
target[k] = overrides[k] | |
} | |
} | |
} | |
} | |
return target | |
} | |
var debug | |
if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) { | |
debug = function() { | |
var args = Array.prototype.slice.call(arguments) | |
if (typeof args[0] === 'string') { | |
args[0] = 'TUNNEL: ' + args[0] | |
} else { | |
args.unshift('TUNNEL:') | |
} | |
console.error.apply(console, args) | |
} | |
} else { | |
debug = function() {} | |
} | |
exports.debug = debug // for test | |
}).call(this,require('_process'),require("buffer").Buffer) | |
},{"_process":undefined,"assert":undefined,"buffer":undefined,"events":undefined,"http":undefined,"https":undefined,"net":undefined,"tls":undefined,"util":undefined}],14:[function(require,module,exports){ | |
module.exports = function () { | |
var s = [], itoh = '0123456789ABCDEF' | |
// Make array of random hex digits. The UUID only has 32 digits in it, but we | |
// allocate an extra items to make room for the '-'s we'll be inserting. | |
for (var i = 0; i <36; i++) s[i] = Math.floor(Math.random()*0x10) | |
// Conform to RFC-4122, section 4.4 | |
s[14] = 4; // Set 4 high bits of time_high field to version | |
s[19] = (s[19] & 0x3) | 0x8 // Specify 2 high bits of clock sequence | |
// Convert to hex chars | |
for (var i = 0; i <36; i++) s[i] = itoh[s[i]] | |
// Insert '-'s | |
s[8] = s[13] = s[18] = s[23] = '-' | |
return s.join('') | |
} | |
},{}],15:[function(require,module,exports){ | |
/*! | |
* Tobi - Cookie | |
* Copyright(c) 2010 LearnBoost <[email protected]> | |
* MIT Licensed | |
*/ | |
/** | |
* Module dependencies. | |
*/ | |
var url = require('url'); | |
/** | |
* Initialize a new `Cookie` with the given cookie `str` and `req`. | |
* | |
* @param {String} str | |
* @param {IncomingRequest} req | |
* @api private | |
*/ | |
var Cookie = exports = module.exports = function Cookie(str, req) { | |
this.str = str; | |
// Map the key/val pairs | |
str.split(/ *; */).reduce(function(obj, pair){ | |
var p = pair.indexOf('='); | |
var key = p > 0 ? pair.substring(0, p).trim() : pair.trim(); | |
var lowerCasedKey = key.toLowerCase(); | |
var value = p > 0 ? pair.substring(p + 1).trim() : true; | |
if (!obj.name) { | |
// First key is the name | |
obj.name = key; | |
obj.value = value; | |
} | |
else if (lowerCasedKey === 'httponly') { | |
obj.httpOnly = value; | |
} | |
else { | |
obj[lowerCasedKey] = value; | |
} | |
return obj; | |
}, this); | |
// Expires | |
this.expires = this.expires | |
? new Date(this.expires) | |
: Infinity; | |
// Default or trim path | |
this.path = this.path | |
? this.path.trim(): req | |
? url.parse(req.url).pathname: '/'; | |
}; | |
/** | |
* Return the original cookie string. | |
* | |
* @return {String} | |
* @api public | |
*/ | |
Cookie.prototype.toString = function(){ | |
return this.str; | |
}; | |
},{"url":undefined}],16:[function(require,module,exports){ | |
/*! | |
* Tobi - CookieJar | |
* Copyright(c) 2010 LearnBoost <[email protected]> | |
* MIT Licensed | |
*/ | |
/** | |
* Module dependencies. | |
*/ | |
var url = require('url'); | |
/** | |
* Initialize a new `CookieJar`. | |
* | |
* @api private | |
*/ | |
var CookieJar = exports = module.exports = function CookieJar() { | |
this.cookies = []; | |
}; | |
/** | |
* Add the given `cookie` to the jar. | |
* | |
* @param {Cookie} cookie | |
* @api private | |
*/ | |
CookieJar.prototype.add = function(cookie){ | |
this.cookies = this.cookies.filter(function(c){ | |
// Avoid duplication (same path, same name) | |
return !(c.name == cookie.name && c.path == cookie.path); | |
}); | |
this.cookies.push(cookie); | |
}; | |
/** | |
* Get cookies for the given `req`. | |
* | |
* @param {IncomingRequest} req | |
* @return {Array} | |
* @api private | |
*/ | |
CookieJar.prototype.get = function(req){ | |
var path = url.parse(req.url).pathname | |
, now = new Date | |
, specificity = {}; | |
return this.cookies.filter(function(cookie){ | |
if (0 == path.indexOf(cookie.path) && now < cookie.expires | |
&& cookie.path.length > (specificity[cookie.name] || 0)) | |
return specificity[cookie.name] = cookie.path.length; | |
}); | |
}; | |
/** | |
* Return Cookie string for the given `req`. | |
* | |
* @param {IncomingRequest} req | |
* @return {String} | |
* @api private | |
*/ | |
CookieJar.prototype.cookieString = function(req){ | |
var cookies = this.get(req); | |
if (cookies.length) { | |
return cookies.map(function(cookie){ | |
return cookie.name + '=' + cookie.value; | |
}).join('; '); | |
} | |
}; | |
},{"url":undefined}],17:[function(require,module,exports){ | |
// Generated by CoffeeScript 1.3.3 | |
(function() { | |
var XMLBuilder, XMLFragment, | |
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; | |
XMLFragment = require('./XMLFragment'); | |
XMLBuilder = (function() { | |
function XMLBuilder(name, xmldec, doctype, options) { | |
this.assertLegalChar = __bind(this.assertLegalChar, this); | |
var att, child, _ref; | |
this.children = []; | |
this.rootObject = null; | |
if (this.is(name, 'Object')) { | |
_ref = [name, xmldec], xmldec = _ref[0], doctype = _ref[1]; | |
name = null; | |
} | |
if (name != null) { | |
name = '' + name || ''; | |
if (xmldec == null) { | |
xmldec = { | |
'version': '1.0' | |
}; | |
} | |
} | |
this.allowSurrogateChars = options != null ? options.allowSurrogateChars : void 0; | |
if ((xmldec != null) && !(xmldec.version != null)) { | |
throw new Error("Version number is required"); | |
} | |
if (xmldec != null) { | |
xmldec.version = '' + xmldec.version || ''; | |
if (!xmldec.version.match(/1\.[0-9]+/)) { | |
throw new Error("Invalid version number: " + xmldec.version); | |
} | |
att = { | |
version: xmldec.version | |
}; | |
if (xmldec.encoding != null) { | |
xmldec.encoding = '' + xmldec.encoding || ''; | |
if (!xmldec.encoding.match(/[A-Za-z](?:[A-Za-z0-9._-]|-)*/)) { | |
throw new Error("Invalid encoding: " + xmldec.encoding); | |
} | |
att.encoding = xmldec.encoding; | |
} | |
if (xmldec.standalone != null) { | |
att.standalone = xmldec.standalone ? "yes" : "no"; | |
} | |
child = new XMLFragment(this, '?xml', att); | |
this.children.push(child); | |
} | |
if (doctype != null) { | |
att = {}; | |
if (name != null) { | |
att.name = name; | |
} | |
if (doctype.ext != null) { | |
doctype.ext = '' + doctype.ext || ''; | |
att.ext = doctype.ext; | |
} | |
child = new XMLFragment(this, '!DOCTYPE', att); | |
this.children.push(child); | |
} | |
if (name != null) { | |
this.begin(name); | |
} | |
} | |
XMLBuilder.prototype.begin = function(name, xmldec, doctype) { | |
var doc, root; | |
if (!(name != null)) { | |
throw new Error("Root element needs a name"); | |
} | |
if (this.rootObject) { | |
this.children = []; | |
this.rootObject = null; | |
} | |
if (xmldec != null) { | |
doc = new XMLBuilder(name, xmldec, doctype); | |
return doc.root(); | |
} | |
name = '' + name || ''; | |
root = new XMLFragment(this, name, {}); | |
root.isRoot = true; | |
root.documentObject = this; | |
this.children.push(root); | |
this.rootObject = root; | |
return root; | |
}; | |
XMLBuilder.prototype.root = function() { | |
return this.rootObject; | |
}; | |
XMLBuilder.prototype.end = function(options) { | |
return toString(options); | |
}; | |
XMLBuilder.prototype.toString = function(options) { | |
var child, r, _i, _len, _ref; | |
r = ''; | |
_ref = this.children; | |
for (_i = 0, _len = _ref.length; _i < _len; _i++) { | |
child = _ref[_i]; | |
r += child.toString(options); | |
} | |
return r; | |
}; | |
XMLBuilder.prototype.is = function(obj, type) { | |
var clas; | |
clas = Object.prototype.toString.call(obj).slice(8, -1); | |
return (obj != null) && clas === type; | |
}; | |
XMLBuilder.prototype.assertLegalChar = function(str) { | |
var chars, chr; | |
if (this.allowSurrogateChars) { | |
chars = /[\u0000-\u0008\u000B-\u000C\u000E-\u001F\uFFFE-\uFFFF]/; | |
} else { | |
chars = /[\u0000-\u0008\u000B-\u000C\u000E-\u001F\uD800-\uDFFF\uFFFE-\uFFFF]/; | |
} | |
chr = str.match(chars); | |
if (chr) { | |
throw new Error("Invalid character (" + chr + ") in string: " + str + " at index " + chr.index); | |
} | |
}; | |
return XMLBuilder; | |
})(); | |
module.exports = XMLBuilder; | |
}).call(this); | |
},{"./XMLFragment":18}],18:[function(require,module,exports){ | |
// Generated by CoffeeScript 1.3.3 | |
(function() { | |
var XMLFragment, | |
__hasProp = {}.hasOwnProperty; | |
XMLFragment = (function() { | |
function XMLFragment(parent, name, attributes, text) { | |
this.isRoot = false; | |
this.documentObject = null; | |
this.parent = parent; | |
this.name = name; | |
this.attributes = attributes; | |
this.value = text; | |
this.children = []; | |
this.assertLegalChar = parent.assertLegalChar; | |
} | |
XMLFragment.prototype.element = function(name, attributes, text) { | |
var child, key, val, _ref, _ref1; | |
if (!(name != null)) { | |
throw new Error("Missing element name"); | |
} | |
name = '' + name || ''; | |
this.assertLegalChar(name); | |
if (attributes == null) { | |
attributes = {}; | |
} | |
if (this.is(attributes, 'String') && this.is(text, 'Object')) { | |
_ref = [text, attributes], attributes = _ref[0], text = _ref[1]; | |
} else if (this.is(attributes, 'String')) { | |
_ref1 = [{}, attributes], attributes = _ref1[0], text = _ref1[1]; | |
} | |
for (key in attributes) { | |
if (!__hasProp.call(attributes, key)) continue; | |
val = attributes[key]; | |
val = '' + val || ''; | |
attributes[key] = this.escape(val); | |
} | |
child = new XMLFragment(this, name, attributes); | |
if (text != null) { | |
text = '' + text || ''; | |
text = this.escape(text); | |
this.assertLegalChar(text); | |
child.raw(text); | |
} | |
this.children.push(child); | |
return child; | |
}; | |
XMLFragment.prototype.insertBefore = function(name, attributes, text) { | |
var child, i, key, val, _ref, _ref1; | |
if (this.isRoot) { | |
throw new Error("Cannot insert elements at root level"); | |
} | |
if (!(name != null)) { | |
throw new Error("Missing element name"); | |
} | |
name = '' + name || ''; | |
this.assertLegalChar(name); | |
if (attributes == null) { | |
attributes = {}; | |
} | |
if (this.is(attributes, 'String') && this.is(text, 'Object')) { | |
_ref = [text, attributes], attributes = _ref[0], text = _ref[1]; | |
} else if (this.is(attributes, 'String')) { | |
_ref1 = [{}, attributes], attributes = _ref1[0], text = _ref1[1]; | |
} | |
for (key in attributes) { | |
if (!__hasProp.call(attributes, key)) continue; | |
val = attributes[key]; | |
val = '' + val || ''; | |
attributes[key] = this.escape(val); | |
} | |
child = new XMLFragment(this.parent, name, attributes); | |
if (text != null) { | |
text = '' + text || ''; | |
text = this.escape(text); | |
this.assertLegalChar(text); | |
child.raw(text); | |
} | |
i = this.parent.children.indexOf(this); | |
this.parent.children.splice(i, 0, child); | |
return child; | |
}; | |
XMLFragment.prototype.insertAfter = function(name, attributes, text) { | |
var child, i, key, val, _ref, _ref1; | |
if (this.isRoot) { | |
throw new Error("Cannot insert elements at root level"); | |
} | |
if (!(name != null)) { | |
throw new Error("Missing element name"); | |
} | |
name = '' + name || ''; | |
this.assertLegalChar(name); | |
if (attributes == null) { | |
attributes = {}; | |
} | |
if (this.is(attributes, 'String') && this.is(text, 'Object')) { | |
_ref = [text, attributes], attributes = _ref[0], text = _ref[1]; | |
} else if (this.is(attributes, 'String')) { | |
_ref1 = [{}, attributes], attributes = _ref1[0], text = _ref1[1]; | |
} | |
for (key in attributes) { | |
if (!__hasProp.call(attributes, key)) continue; | |
val = attributes[key]; | |
val = '' + val || ''; | |
attributes[key] = this.escape(val); | |
} | |
child = new XMLFragment(this.parent, name, attributes); | |
if (text != null) { | |
text = '' + text || ''; | |
text = this.escape(text); | |
this.assertLegalChar(text); | |
child.raw(text); | |
} | |
i = this.parent.children.indexOf(this); | |
this.parent.children.splice(i + 1, 0, child); | |
return child; | |
}; | |
XMLFragment.prototype.remove = function() { | |
var i, _ref; | |
if (this.isRoot) { | |
throw new Error("Cannot remove the root element"); | |
} | |
i = this.parent.children.indexOf(this); | |
[].splice.apply(this.parent.children, [i, i - i + 1].concat(_ref = [])), _ref; | |
return this.parent; | |
}; | |
XMLFragment.prototype.text = function(value) { | |
var child; | |
if (!(value != null)) { | |
throw new Error("Missing element text"); | |
} | |
value = '' + value || ''; | |
value = this.escape(value); | |
this.assertLegalChar(value); | |
child = new XMLFragment(this, '', {}, value); | |
this.children.push(child); | |
return this; | |
}; | |
XMLFragment.prototype.cdata = function(value) { | |
var child; | |
if (!(value != null)) { | |
throw new Error("Missing CDATA text"); | |
} | |
value = '' + value || ''; | |
this.assertLegalChar(value); | |
if (value.match(/]]>/)) { | |
throw new Error("Invalid CDATA text: " + value); | |
} | |
child = new XMLFragment(this, '', {}, '<![CDATA[' + value + ']]>'); | |
this.children.push(child); | |
return this; | |
}; | |
XMLFragment.prototype.comment = function(value) { | |
var child; | |
if (!(value != null)) { | |
throw new Error("Missing comment text"); | |
} | |
value = '' + value || ''; | |
value = this.escape(value); | |
this.assertLegalChar(value); | |
if (value.match(/--/)) { | |
throw new Error("Comment text cannot contain double-hypen: " + value); | |
} | |
child = new XMLFragment(this, '', {}, '<!-- ' + value + ' -->'); | |
this.children.push(child); | |
return this; | |
}; | |
XMLFragment.prototype.raw = function(value) { | |
var child; | |
if (!(value != null)) { | |
throw new Error("Missing raw text"); | |
} | |
value = '' + value || ''; | |
child = new XMLFragment(this, '', {}, value); | |
this.children.push(child); | |
return this; | |
}; | |
XMLFragment.prototype.up = function() { | |
if (this.isRoot) { | |
throw new Error("This node has no parent. Use doc() if you need to get the document object."); | |
} | |
return this.parent; | |
}; | |
XMLFragment.prototype.root = function() { | |
var child; | |
if (this.isRoot) { | |
return this; | |
} | |
child = this.parent; | |
while (!child.isRoot) { | |
child = child.parent; | |
} | |
return child; | |
}; | |
XMLFragment.prototype.document = function() { | |
return this.root().documentObject; | |
}; | |
XMLFragment.prototype.end = function(options) { | |
return this.document().toString(options); | |
}; | |
XMLFragment.prototype.prev = function() { | |
var i; | |
if (this.isRoot) { | |
throw new Error("Root node has no siblings"); | |
} | |
i = this.parent.children.indexOf(this); | |
if (i < 1) { | |
throw new Error("Already at the first node"); | |
} | |
return this.parent.children[i - 1]; | |
}; | |
XMLFragment.prototype.next = function() { | |
var i; | |
if (this.isRoot) { | |
throw new Error("Root node has no siblings"); | |
} | |
i = this.parent.children.indexOf(this); | |
if (i === -1 || i === this.parent.children.length - 1) { | |
throw new Error("Already at the last node"); | |
} | |
return this.parent.children[i + 1]; | |
}; | |
XMLFragment.prototype.clone = function(deep) { | |
var clonedSelf; | |
clonedSelf = new XMLFragment(this.parent, this.name, this.attributes, this.value); | |
if (deep) { | |
this.children.forEach(function(child) { | |
var clonedChild; | |
clonedChild = child.clone(deep); | |
clonedChild.parent = clonedSelf; | |
return clonedSelf.children.push(clonedChild); | |
}); | |
} | |
return clonedSelf; | |
}; | |
XMLFragment.prototype.importXMLBuilder = function(xmlbuilder) { | |
var clonedRoot; | |
clonedRoot = xmlbuilder.root().clone(true); | |
clonedRoot.parent = this; | |
this.children.push(clonedRoot); | |
clonedRoot.isRoot = false; | |
return this; | |
}; | |
XMLFragment.prototype.attribute = function(name, value) { | |
var _ref; | |
if (!(name != null)) { | |
throw new Error("Missing attribute name"); | |
} | |
if (!(value != null)) { | |
throw new Error("Missing attribute value"); | |
} | |
name = '' + name || ''; | |
value = '' + value || ''; | |
if ((_ref = this.attributes) == null) { | |
this.attributes = {}; | |
} | |
this.attributes[name] = this.escape(value); | |
return this; | |
}; | |
XMLFragment.prototype.removeAttribute = function(name) { | |
if (!(name != null)) { | |
throw new Error("Missing attribute name"); | |
} | |
name = '' + name || ''; | |
delete this.attributes[name]; | |
return this; | |
}; | |
XMLFragment.prototype.toString = function(options, level) { | |
var attName, attValue, child, indent, newline, pretty, r, space, _i, _len, _ref, _ref1; | |
pretty = (options != null) && options.pretty || false; | |
indent = (options != null) && options.indent || ' '; | |
newline = (options != null) && options.newline || '\n'; | |
level || (level = 0); | |
space = new Array(level + 1).join(indent); | |
r = ''; | |
if (pretty) { | |
r += space; | |
} | |
if (!(this.value != null)) { | |
r += '<' + this.name; | |
} else { | |
r += '' + this.value; | |
} | |
_ref = this.attributes; | |
for (attName in _ref) { | |
if (!__hasProp.call(_ref, attName)) continue; | |
attValue = _ref[attName]; | |
if (this.name === '!DOCTYPE') { | |
r += ' ' + attValue; | |
} else { | |
r += ' ' + attName + '="' + attValue + '"'; | |
} | |
} | |
if (this.children.length === 0) { | |
if (!(this.value != null)) { | |
r += this.name === '?xml' ? '?>' : this.name === '!DOCTYPE' ? '>' : '/>'; | |
} | |
if (pretty) { | |
r += newline; | |
} | |
} else if (pretty && this.children.length === 1 && (this.children[0].value != null)) { | |
r += '>'; | |
r += this.children[0].value; | |
r += '</' + this.name + '>'; | |
r += newline; | |
} else { | |
r += '>'; | |
if (pretty) { | |
r += newline; | |
} | |
_ref1 = this.children; | |
for (_i = 0, _len = _ref1.length; _i < _len; _i++) { | |
child = _ref1[_i]; | |
r += child.toString(options, level + 1); | |
} | |
if (pretty) { | |
r += space; | |
} | |
r += '</' + this.name + '>'; | |
if (pretty) { | |
r += newline; | |
} | |
} | |
return r; | |
}; | |
XMLFragment.prototype.escape = function(str) { | |
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/'/g, ''').replace(/"/g, '"'); | |
}; | |
XMLFragment.prototype.is = function(obj, type) { | |
var clas; | |
clas = Object.prototype.toString.call(obj).slice(8, -1); | |
return (obj != null) && clas === type; | |
}; | |
XMLFragment.prototype.ele = function(name, attributes, text) { | |
return this.element(name, attributes, text); | |
}; | |
XMLFragment.prototype.txt = function(value) { | |
return this.text(value); | |
}; | |
XMLFragment.prototype.dat = function(value) { | |
return this.cdata(value); | |
}; | |
XMLFragment.prototype.att = function(name, value) { | |
return this.attribute(name, value); | |
}; | |
XMLFragment.prototype.com = function(value) { | |
return this.comment(value); | |
}; | |
XMLFragment.prototype.doc = function() { | |
return this.document(); | |
}; | |
XMLFragment.prototype.e = function(name, attributes, text) { | |
return this.element(name, attributes, text); | |
}; | |
XMLFragment.prototype.t = function(value) { | |
return this.text(value); | |
}; | |
XMLFragment.prototype.d = function(value) { | |
return this.cdata(value); | |
}; | |
XMLFragment.prototype.a = function(name, value) { | |
return this.attribute(name, value); | |
}; | |
XMLFragment.prototype.c = function(value) { | |
return this.comment(value); | |
}; | |
XMLFragment.prototype.r = function(value) { | |
return this.raw(value); | |
}; | |
XMLFragment.prototype.u = function() { | |
return this.up(); | |
}; | |
return XMLFragment; | |
})(); | |
module.exports = XMLFragment; | |
}).call(this); | |
},{}],19:[function(require,module,exports){ | |
// Generated by CoffeeScript 1.3.3 | |
(function() { | |
var XMLBuilder; | |
XMLBuilder = require('./XMLBuilder'); | |
module.exports.create = function(name, xmldec, doctype, options) { | |
if (name != null) { | |
return new XMLBuilder(name, xmldec, doctype, options).root(); | |
} else { | |
return new XMLBuilder(); | |
} | |
}; | |
}).call(this); | |
},{"./XMLBuilder":17}],20:[function(require,module,exports){ | |
/** | |
* Determine if an object is Buffer | |
* | |
* Author: Feross Aboukhadijeh <[email protected]> <http://feross.org> | |
* License: MIT | |
* | |
* `npm install is-buffer` | |
*/ | |
module.exports = function (obj) { | |
return !!(obj != null && | |
(obj._isBuffer || // For Safari 5-7 (missing Object.prototype.constructor) | |
(obj.constructor && | |
typeof obj.constructor.isBuffer === 'function' && | |
obj.constructor.isBuffer(obj)) | |
)) | |
} | |
},{}]},{},[1]); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment