(chunk)
| 241 | // clean up the socket and return an error. Otherwise we establish the tunnel. |
| 242 | let buffer = ''; |
| 243 | function onProxyData(chunk) { |
| 244 | const str = chunk.toString(); |
| 245 | debug('onProxyData', str); |
| 246 | buffer += str; |
| 247 | const headerEndIndex = buffer.indexOf('\r\n\r\n'); |
| 248 | if (headerEndIndex === -1) return headerEndIndex; |
| 249 | const statusLine = buffer.substring(0, buffer.indexOf('\r\n')); |
| 250 | const statusCode = statusLine.split(' ')[1]; |
| 251 | if (statusCode !== '200') { |
| 252 | debug(`onProxyData receives ${statusCode}, cleaning up`); |
| 253 | cleanup(); |
| 254 | const targetHost = proxyTunnelPayload.split('\r')[0].split(' ')[1]; |
| 255 | const message = `Failed to establish tunnel to ${targetHost} via ${agent[kProxyConfig].href}: ${statusLine}`; |
| 256 | const err = new ERR_PROXY_TUNNEL(message); |
| 257 | err.statusCode = NumberParseInt(statusCode); |
| 258 | afterSocket(err, socket); |
| 259 | } else { |
| 260 | // https://datatracker.ietf.org/doc/html/rfc9110#CONNECT |
| 261 | // RFC 9110 says that it can be 2xx but in the real world, proxy clients generally only |
| 262 | // accepts 200. |
| 263 | // Proxy servers are not supposed to send anything after the headers - the payload must be |
| 264 | // be empty. So after this point we will proceed with the tunnel e.g. starting TLS handshake. |
| 265 | debug('onProxyData receives 200, establishing tunnel'); |
| 266 | cleanup(); |
| 267 | |
| 268 | // Reuse the tunneled socket to perform the TLS handshake with the endpoint, |
| 269 | // then send the request. |
| 270 | const { requestOptions } = tunnelConfig; |
| 271 | tunnelConfig.requestOptions = null; |
| 272 | requestOptions.socket = socket; |
| 273 | let tunneldSocket; |
| 274 | const onTLSHandshakeError = (err) => { |
| 275 | debug('Propagate error event from tunneled socket to tunnel socket'); |
| 276 | afterSocket(err, tunneldSocket); |
| 277 | }; |
| 278 | tunneldSocket = tls.connect(requestOptions, () => { |
| 279 | debug('TLS handshake over tunnel succeeded'); |
| 280 | tunneldSocket.removeListener('error', onTLSHandshakeError); |
| 281 | afterSocket(null, tunneldSocket); |
| 282 | }); |
| 283 | tunneldSocket.on('free', () => { |
| 284 | debug('Propagate free event from tunneled socket to tunnel socket'); |
| 285 | socket.emit('free'); |
| 286 | }); |
| 287 | tunneldSocket.on('error', onTLSHandshakeError); |
| 288 | } |
| 289 | return headerEndIndex; |
| 290 | } |
| 291 | |
| 292 | function onProxyEnd() { |
| 293 | cleanup(); |
no test coverage detected
searching dependent graphs…