Tizen 2.1 base
[platform/framework/web/web-ui-fw.git] / libs / js / jquery-mobile-1.2.0 / node_modules / grunt / node_modules / prompt / node_modules / winston / node_modules / loggly / node_modules / request / tunnel.js
1 'use strict';
2
3 var net = require('net');
4 var tls = require('tls');
5 var http = require('http');
6 var https = require('https');
7 var events = require('events');
8 var assert = require('assert');
9 var util = require('util');
10
11
12 exports.httpOverHttp = httpOverHttp;
13 exports.httpsOverHttp = httpsOverHttp;
14 exports.httpOverHttps = httpOverHttps;
15 exports.httpsOverHttps = httpsOverHttps;
16
17
18 function httpOverHttp(options) {
19   var agent = new TunnelingAgent(options);
20   agent.request = http.request;
21   return agent;
22 }
23
24 function httpsOverHttp(options) {
25   var agent = new TunnelingAgent(options);
26   agent.request = http.request;
27   agent.createSocket = createSecureSocket;
28   return agent;
29 }
30
31 function httpOverHttps(options) {
32   var agent = new TunnelingAgent(options);
33   agent.request = https.request;
34   return agent;
35 }
36
37 function httpsOverHttps(options) {
38   var agent = new TunnelingAgent(options);
39   agent.request = https.request;
40   agent.createSocket = createSecureSocket;
41   return agent;
42 }
43
44
45 function TunnelingAgent(options) {
46   var self = this;
47   self.options = options || {};
48   self.proxyOptions = self.options.proxy || {};
49   self.maxSockets = self.options.maxSockets || http.Agent.defaultMaxSockets;
50   self.requests = [];
51   self.sockets = [];
52
53   self.on('free', function onFree(socket, host, port) {
54     for (var i = 0, len = self.requests.length; i < len; ++i) {
55       var pending = self.requests[i];
56       if (pending.host === host && pending.port === port) {
57         // Detect the request to connect same origin server,
58         // reuse the connection.
59         self.requests.splice(i, 1);
60         pending.request.onSocket(socket);
61         return;
62       }
63     }
64     socket.destroy();
65     self.removeSocket(socket);
66   });
67 }
68 util.inherits(TunnelingAgent, events.EventEmitter);
69
70 TunnelingAgent.prototype.addRequest = function addRequest(req, host, port) {
71   var self = this;
72
73   if (self.sockets.length >= this.maxSockets) {
74     // We are over limit so we'll add it to the queue.
75     self.requests.push({host: host, port: port, request: req});
76     return;
77   }
78
79   // If we are under maxSockets create a new one.
80   self.createSocket({host: host, port: port, request: req}, function(socket) {
81     socket.on('free', onFree);
82     socket.on('close', onCloseOrRemove);
83     socket.on('agentRemove', onCloseOrRemove);
84     req.onSocket(socket);
85
86     function onFree() {
87       self.emit('free', socket, host, port);
88     }
89
90     function onCloseOrRemove(err) {
91       self.removeSocket();
92       socket.removeListener('free', onFree);
93       socket.removeListener('close', onCloseOrRemove);
94       socket.removeListener('agentRemove', onCloseOrRemove);
95     }
96   });
97 };
98
99 TunnelingAgent.prototype.createSocket = function createSocket(options, cb) {
100   var self = this;
101   var placeholder = {};
102   self.sockets.push(placeholder);
103
104   var connectOptions = mergeOptions({}, self.proxyOptions, {
105     method: 'CONNECT',
106     path: options.host + ':' + options.port,
107     agent: false
108   });
109   if (connectOptions.proxyAuth) {
110     connectOptions.headers = connectOptions.headers || {};
111     connectOptions.headers['Proxy-Authorization'] = 'Basic ' +
112         new Buffer(connectOptions.proxyAuth).toString('base64');
113   }
114
115   debug('making CONNECT request');
116   var connectReq = self.request(connectOptions);
117   connectReq.useChunkedEncodingByDefault = false; // for v0.6
118   connectReq.once('response', onResponse); // for v0.6
119   connectReq.once('upgrade', onUpgrade);   // for v0.6
120   connectReq.once('connect', onConnect);   // for v0.7 or later
121   connectReq.once('error', onError);
122   connectReq.end();
123
124   function onResponse(res) {
125     // Very hacky. This is necessary to avoid http-parser leaks.
126     res.upgrade = true;
127   }
128
129   function onUpgrade(res, socket, head) {
130     // Hacky.
131     process.nextTick(function() {
132       onConnect(res, socket, head);
133     });
134   }
135
136   function onConnect(res, socket, head) {
137     connectReq.removeAllListeners();
138     socket.removeAllListeners();
139
140     if (res.statusCode === 200) {
141       assert.equal(head.length, 0);
142       debug('tunneling connection has established');
143       self.sockets[self.sockets.indexOf(placeholder)] = socket;
144       cb(socket);
145     } else {
146       debug('tunneling socket could not be established, statusCode=%d',
147             res.statusCode);
148       var error = new Error('tunneling socket could not be established, ' +
149                             'sutatusCode=' + res.statusCode);
150       error.code = 'ECONNRESET';
151       options.request.emit('error', error);
152       self.removeSocket(placeholder);
153     }
154   }
155
156   function onError(cause) {
157     connectReq.removeAllListeners();
158
159     debug('tunneling socket could not be established, cause=%s\n',
160           cause.message, cause.stack);
161     var error = new Error('tunneling socket could not be established, ' +
162                           'cause=' + cause.message);
163     error.code = 'ECONNRESET';
164     options.request.emit('error', error);
165     self.removeSocket(placeholder);
166   }
167 };
168
169 TunnelingAgent.prototype.removeSocket = function removeSocket(socket) {
170   var pos = this.sockets.indexOf(socket)
171   if (pos === -1) {
172     return;
173   }
174   this.sockets.splice(pos, 1);
175
176   var pending = this.requests.shift();
177   if (pending) {
178     // If we have pending requests and a socket gets closed a new one
179     // needs to be created to take over in the pool for the one that closed.
180     this.createSocket(pending, function(socket) {
181       pending.request.onSocket(socket);
182     });
183   }
184 };
185
186 function createSecureSocket(options, cb) {
187   var self = this;
188   TunnelingAgent.prototype.createSocket.call(self, options, function(socket) {
189     // 0 is dummy port for v0.6
190     var secureSocket = tls.connect(0, mergeOptions({}, self.options, {
191       socket: socket
192     }));
193     cb(secureSocket);
194   });
195 }
196
197
198 function mergeOptions(target) {
199   for (var i = 1, len = arguments.length; i < len; ++i) {
200     var overrides = arguments[i];
201     if (typeof overrides === 'object') {
202       var keys = Object.keys(overrides);
203       for (var j = 0, keyLen = keys.length; j < keyLen; ++j) {
204         var k = keys[j];
205         if (overrides[k] !== undefined) {
206           target[k] = overrides[k];
207         }
208       }
209     }
210   }
211   return target;
212 }
213
214
215 var debug;
216 if (process.env.NODE_DEBUG && /\btunnel\b/.test(process.env.NODE_DEBUG)) {
217   debug = function() {
218     var args = Array.prototype.slice.call(arguments);
219     if (typeof args[0] === 'string') {
220       args[0] = 'TUNNEL: ' + args[0];
221     } else {
222       args.unshift('TUNNEL:');
223     }
224     console.error.apply(console, args);
225   }
226 } else {
227   debug = function() {};
228 }
229 exports.debug = debug; // for test