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 , head ) {
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 ( err ) {
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