1+ var util = require ( 'util' ) ,
2+ https = require ( 'https' ) ,
3+ http = require ( 'http' ) ,
4+ lls = require ( 'tls' ) ;
5+
6+ function HttpsProxyAgent ( options ) {
7+ https . Agent . call ( this , options ) ;
8+
9+ this . proxyHost = options . proxyHost ;
10+ this . proxyPort = options . proxyPort ;
11+
12+ this . createConnection = function ( opts , callback ) {
13+ // do a CONNECT request
14+ var req = http . request ( {
15+ host : options . proxyHost ,
16+ port : options . proxyPort ,
17+ method : 'CONNECT' ,
18+ path : opts . host + ':' + opts . port ,
19+ headers : {
20+ host : opts . host
21+ }
22+ } ) ;
23+
24+ req . on ( 'connect' , function ( res , socket ) {
25+ var cts = lls . connect ( {
26+ host : opts . host ,
27+ socket : socket
28+ } , function ( ) {
29+ callback ( false , cts ) ;
30+ } ) ;
31+ } ) ;
32+
33+ req . on ( 'error' , function ( err ) {
34+ callback ( err , null ) ;
35+ } ) ;
36+
37+ req . end ( ) ;
38+ } ;
39+ }
40+
41+ util . inherits ( HttpsProxyAgent , https . Agent ) ;
42+
43+ // Almost verbatim copy of http.Agent.addRequest
44+ HttpsProxyAgent . prototype . addRequest = function ( req , options ) {
45+ var name = options . host + ':' + options . port ;
46+ if ( options . path ) name += ':' + options . path ;
47+
48+ if ( ! this . sockets [ name ] ) this . sockets [ name ] = [ ] ;
49+
50+ if ( this . sockets [ name ] . length < this . maxSockets ) {
51+ // if we are under maxSockets create a new one.
52+ this . createSocket ( name , options . host , options . port , options . path , req , function ( socket ) {
53+ req . onSocket ( socket ) ;
54+ } ) ;
55+ } else {
56+ // we are over limit so we'll add it to the queue.
57+ if ( ! this . requests [ name ] )
58+ this . requests [ name ] = [ ] ;
59+ this . requests [ name ] . push ( req ) ;
60+ }
61+ } ;
62+
63+ // Almost verbatim copy of http.Agent.createSocket
64+ HttpsProxyAgent . prototype . createSocket = function ( name , host , port , localAddress , req , callback ) {
65+ var self = this ;
66+ var options = util . _extend ( { } , self . options ) ;
67+ options . port = port ;
68+ options . host = host ;
69+ options . localAddress = localAddress ;
70+
71+ options . servername = host ;
72+ if ( req ) {
73+ var hostHeader = req . getHeader ( 'host' ) ;
74+ if ( hostHeader )
75+ options . servername = hostHeader . replace ( / : .* $ / , '' ) ;
76+ }
77+
78+ self . createConnection ( options , function ( err , s ) {
79+ if ( err ) {
80+ err . message += ' while connecting to HTTP(S) proxy server ' + self . proxyHost + ':' + self . proxyPort ;
81+
82+ if ( req )
83+ req . emit ( 'error' , err ) ;
84+ else
85+ throw err ;
86+
87+ return ;
88+ }
89+
90+ if ( ! self . sockets [ name ] ) self . sockets [ name ] = [ ] ;
91+
92+ self . sockets [ name ] . push ( s ) ;
93+
94+ var onFree = function ( ) {
95+ self . emit ( 'free' , s , host , port , localAddress ) ;
96+ } ;
97+
98+ var onClose = function ( ) {
99+ // this is the only place where sockets get removed from the Agent.
100+ // if you want to remove a socket from the pool, just close it.
101+ // all socket errors end in a close event anyway.
102+ self . removeSocket ( s , name , host , port , localAddress ) ;
103+ } ;
104+
105+ var onRemove = function ( ) {
106+ // we need this function for cases like HTTP 'upgrade'
107+ // (defined by WebSockets) where we need to remove a socket from the pool
108+ // because it'll be locked up indefinitely
109+ self . removeSocket ( s , name , host , port , localAddress ) ;
110+ s . removeListener ( 'close' , onClose ) ;
111+ s . removeListener ( 'free' , onFree ) ;
112+ s . removeListener ( 'agentRemove' , onRemove ) ;
113+ } ;
114+
115+ s . on ( 'free' , onFree ) ;
116+ s . on ( 'close' , onClose ) ;
117+ s . on ( 'agentRemove' , onRemove ) ;
118+
119+ callback ( s ) ;
120+ } ) ;
121+ } ;
122+
123+ module . exports = HttpsProxyAgent ;
0 commit comments