im writing an HTTP proxy in C#. the proxy should capture both HTTP and HTTPS traffic from the web browser. so far i have implemented the GET and POST requests no problem, but the CONNECT request i am having a little trouble with. there does not appear to be any help whatsoever on the internet regarding the CONNECT request and C#. below are the steps for what i do so far. this example shows what happens when i try to log into my hotmail account, which of course is done securely and thus generates a CONNECT request:
1) my server socket accepts a connection from the web browser
TcpClient tcpBrowser = _proxyServer.AcceptTcpClient()
2) get the stream for the browser
NetworkStream networkStreamBrowser = tcpBrowser.GetStream();
3) read the data from the browser's stream
networkStreamBrowser.Read(buff, 0, buff.Length);
4) i call my own function that parses the above data, to get the host and port number, and the request type. so the data in this case will be:
CONNECT login.live.com:443 HTTP/1.0 User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.5.21022; .NET CLR 3.5.30729; .NET CLR 3.0.30618) Proxy-Connection: Keep-Alive Content-Length: 0 Host: login.live.com Pragma: no-cache
and so from this i get the host (login.live.com), the port (443), and the request type (CONNECT)
5) i detect that this is a CONNECT request, and open up an SSL stream to the above server:
TcpClient clDestination = new TcpClient(); clDestination.Connect(host, port); SslStream sslStream = new SslStream(clDest.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); sslStream.AuthenticateAsClient(strDest);
the ValidateServerCertificate callback fires and i can see at this stage all is good - i have the server certificate.
6) i send an 'ok' message back to the web browser:
string strSSLResponse = "HTTP/1.0 200 Connection established\r\n\r\n"; AsciiEncoding enc = new AsciiEncoding(); byte bytSSLResponse = enc.GetBytes(strSSLResponse); networkStreamBrowser.Write(bytSSLResponse, 0, bytSSLResponse.Length);
7) at this point i expect the web browser to respond by sending the form POST data (my hotmail user name and password that i entered at the begining). i would then simply forward this data on to the server through the SSL stream. however the data that i receive back from the browser is all mangled:
networkStreamBrowser.Read(buff, 0, buff.Length); //confirm that the data is mangled by converting it to string StringBuilder sb = new StringBuilder(); char chArray = new char[iBytesReadFromBrowser]; Array.Copy(bytesReadFromBrowser, chArray, iBytesReadFromBrowser); sb.Append(chArray); string strMangledDataFromBrowser = sb.ToString(); //strMangledDataFromBrowser in the debugger is something like "\0\0S\0\0O\0Iúä^Æ;Gy!ÁÚS¤h2lU\\¨)ð¢tÃ\t \0\01ñ¡K÷½ÃaÌ.¦\\ê<\fsawhm(E/ý\0\b\0\0\n\0\0\0"
what i would EXPECT to get from the browser is something like
POST /ppsecure/post.srf?wa=wsignin1.0&rpsnv=10&ct=1241101484&rver=5.5.4177.0&wp=MBI&wreply=http:%2F%2Fmail.live.com%2Fdefault.aspx&lc=2057&id=64855&mkt=en-GB&bk=1241101484 HTTP/1.1\r\n\r\n //... //... //... //the actual POST data
the reason i would expect to see this is because i have used the fiddler http debugger to view the http requests, and this is what fiddler captures. in addition, the only SSL encryption taking place is between my proxy and the web server - the data between the browser and my proxy should be plain text.
so my question is, why is the data coming back mangled from the web browser ? can you spot anything wrong in my code or my logic ?
any help very much appreciated.