Consider this piece of code:
app.on("connection", (clientToProxySocket) => {
console.log("Client connected to proxy");
clientToProxySocket.once("data", (data) => {
let isConnectionTLS = data.toString().indexOf("CONNECT") !== -1;
let port= 80;
let host;
if (isConnectionTLS) {
port= 443;
host= data
.toString().split("CONNECT")[1]
.split(" ")[1]
.split(":")[0];
} else {
host= data.toString().split("Host: ")[1].split("\\n")[0];
}
let proxyToServerSocket = net.createConnection(
{host, port},
() => {}
)
if (isConnectionTLS) {
clientToProxySocket.write("HTTP/1.1 200 OK\r\n\r\n");
} else {
proxyToServerSocket.write(data);
}
const intermediatePipe = new stream.PassThrough();
intermediatePipe.on('data', (chunk) => {
console.log(chunk.toString());
});
clientToProxySocket.pipe(proxyToServerSocket);
proxyToServerSocket.pipe(clientToProxySocket);
// ... more events handling
})
})
//... more events handling
app.listen(
{
host: "0.0.0.0",
port: 8080,
},
() => {
console.log("Server listening on 0.0.0.0:8080");
}
);
My question is about the data event of the clientToProxySocket socket. What confuses me is that some data is consumed by the first listener (the one registered using once), but this consumed data is still being seen in the pipe ( clientToProxySocket.pipe(proxyToServerSocket); ).
I tried this curl command:
curl https://httpbin.org/headers -x http://127.0.0.1:8080 -kv
And paused the code using the debugger to see what is in data, I found:
CONNECT httpbin.org:443 HTTP/1.1
Host: httpbin.org:443
User-Agent: curl/8.7.1
Proxy-Connection: Keep-Alive
This lets me think that httpbin will not see these headers because the are consumed in the first data event and thus the piping will not include them, but curl shows this:
CONNECT httpbin.org:443 HTTP/1.1
Host: httpbin.org:443
User-Agent: curl/8.7.1
Proxy-Connection: Keep-Alive
Actually, httpbin.org have recieved all the headers (the api I used just prints the request headers) while it shouldn't: OK for the CONNECT header to not be as it is performed by us in the net.createConnection call.
My question goes in two parts:
- How could the headers be consumed in the first event but still included in piping?
- How could it be possible to see the headers plainly in an https connections while only
httpbin.orgwho could decrypt the traffic?
EDIT
Now, I understand that the first data is not for the final server, but for the proxy server, this is why it is being sent in plain with no encryption. But should I always wait for the first request header to be received (and consume it until \r\n\r\n) before piping the client request to the remote server (for https, I know for http I can directly pipe it) ?
write, and also avoid to miss data due to receiving data between unregistering thedataevent and start the piping... It is more an algorithmic problem then HTTP-spec related. But still, with HTTPs we don't have this problem ... to be continued ...HTTP/1.1 200 OKor a another response, before continuing the transfer, I guess this is the handshake ... \