@@ -83,6 +83,13 @@ function connect (req, _opts, fn) {
8383 socket = net . connect ( proxy ) ;
8484 }
8585
86+ // we need to buffer any HTTP traffic that happens with the proxy before we get
87+ // the CONNECT response, so that if the response is anything other than an "200"
88+ // response code, then we can re-play the "data" events on the socket once the
89+ // HTTP parser is hooked up...
90+ var buffers = [ ] ;
91+ var buffersLength = 0 ;
92+
8693 function read ( ) {
8794 var b = socket . read ( ) ;
8895 if ( b ) ondata ( b ) ;
@@ -91,37 +98,116 @@ function connect (req, _opts, fn) {
9198
9299 function cleanup ( ) {
93100 socket . removeListener ( 'data' , ondata ) ;
101+ socket . removeListener ( 'end' , onend ) ;
94102 socket . removeListener ( 'error' , onerror ) ;
103+ socket . removeListener ( 'close' , onclose ) ;
95104 socket . removeListener ( 'readable' , read ) ;
96105 }
97106
107+ function onclose ( err ) {
108+ console . error ( 'onclose' ) ;
109+ }
110+
111+ function onend ( err ) {
112+ console . error ( 'onend' ) ;
113+ }
114+
98115 function onerror ( err ) {
99116 cleanup ( ) ;
100117 fn ( err ) ;
101118 }
102119
103120 function ondata ( b ) {
121+ buffers . push ( b ) ;
122+ buffersLength += b . length ;
123+ var buffered = Buffer . concat ( buffers , buffersLength ) ;
124+ var str = buffered . toString ( 'ascii' ) ;
125+
126+ if ( ! ~ str . indexOf ( '\r\n\r\n' ) ) {
127+ // keep buffering
128+ debug ( 'have not received end of HTTP headers yet... %j' ) ;
129+ if ( socket . read ) {
130+ read ( ) ;
131+ } else {
132+ socket . once ( 'data' , ondata ) ;
133+ }
134+ return ;
135+ }
136+
137+ var firstLine = str . substring ( 0 , str . indexOf ( '\r\n' ) ) ;
138+ var statusCode = + firstLine . split ( ' ' ) [ 1 ] ;
139+ debug ( 'got proxy server response: "%s"' , firstLine ) ;
140+ //console.log('statusCode: %d', statusCode);
104141 //console.log(b.length, b, b.toString());
105- // TODO: verify that the socket is properly connected, check response...
106-
107- var sock = socket ;
108-
109- if ( secureEndpoint ) {
110- // since the proxy is connecting to an SSL server, we have
111- // to upgrade this socket connection to an SSL connection
112- opts . socket = socket ;
113- opts . servername = opts . host ;
114- opts . host = null ;
115- opts . hostname = null ;
116- opts . port = null ;
117- sock = tls . connect ( opts ) ;
142+
143+ if ( 200 == statusCode ) {
144+ // 200 Connected status code!
145+ var sock = socket ;
146+
147+ // nullify the buffered data since we won't be needing it
148+ buffers = buffered = null ;
149+
150+ if ( secureEndpoint ) {
151+ // since the proxy is connecting to an SSL server, we have
152+ // to upgrade this socket connection to an SSL connection
153+ debug ( 'upgrading proxy-connected socket to TLS connection: "%s"' , opts . host ) ;
154+ opts . socket = socket ;
155+ opts . servername = opts . host ;
156+ opts . host = null ;
157+ opts . hostname = null ;
158+ opts . port = null ;
159+ sock = tls . connect ( opts ) ;
160+ }
161+
162+ cleanup ( ) ;
163+ fn ( null , sock ) ;
164+ } else {
165+ // some other status code that's not 200... need to re-play the HTTP header
166+ // "data" events onto the socket once the HTTP machinery is attached so that
167+ // the user can parse and handle the error status code
168+ cleanup ( ) ;
169+
170+ // save a reference to the concat'd Buffer for the `onsocket` callback
171+ console . error ( 0 , str ) ;
172+ buffers = buffered ;
173+
174+ // need to wait for the "socket" event to re-play the "data" events
175+ req . once ( 'socket' , onsocket ) ;
176+ fn ( null , socket ) ;
118177 }
178+ }
119179
120- cleanup ( ) ;
121- fn ( null , sock ) ;
180+ function onsocket ( socket ) {
181+ // replay the "buffers" Buffer onto the `socket`, since at this point
182+ // the HTTP module machinery has been hooked up for the user
183+ if ( 'function' == typeof socket . ondata ) {
184+ // node <= v0.11.3, the `ondata` function is set on the socket
185+ socket . ondata ( buffers , 0 , buffers . length ) ;
186+ } else if ( socket . listeners ( 'data' ) . length > 0 ) {
187+ // node > v0.11.3, the "data" event is listened for directly
188+ socket . emit ( 'data' , buffers ) ;
189+ } else {
190+ // never?
191+ throw new Error ( 'should not happen...' ) ;
192+ }
193+ buffers = null ;
194+
195+ // XXX: not sure if forcing "end" here is appropriate, but otherwise the
196+ // socket never closes and the tests fail since the proxy server never shuts
197+ // down...
198+ /*
199+ if ('function' == typeof socket.onend) {
200+ socket.onend();
201+ } else {
202+ socket.emit('end');
203+ }
204+ */
205+ //socket.destroy();
122206 }
123207
124208 socket . on ( 'error' , onerror ) ;
209+ socket . on ( 'close' , onclose ) ;
210+ socket . on ( 'end' , onend ) ;
125211
126212 if ( socket . read ) {
127213 read ( ) ;
@@ -136,6 +222,7 @@ function connect (req, _opts, fn) {
136222 msg += 'Proxy-Authorization: Basic ' + new Buffer ( auth ) . toString ( 'base64' ) + '\r\n' ;
137223 }
138224 msg += 'Host: ' + hostname + '\r\n' +
139- '\r\n' ;
225+ 'Connection: close\r\n' +
226+ '\r\n' ;
140227 socket . write ( msg ) ;
141228} ;
0 commit comments