private static void HandleHttpSessionRequest(TcpClient client, string httpCmd, Stream clientStream, string tunnelHostName, List<string> requestLines, CustomBinaryReader clientStreamReader, StreamWriter clientStreamWriter, string securehost) { if (httpCmd == null) { if (clientStreamReader != null) clientStreamReader.Dispose(); if (clientStreamWriter != null) clientStreamWriter.Dispose(); if (clientStream != null) clientStream.Dispose(); if (client != null) client.Close(); return; } var args = new SessionEventArgs(BUFFER_SIZE); args.Client = client; args.tunnelHostName = tunnelHostName; args.securehost = securehost; try { //break up the line into three components (method, remote URL & Http Version) var splitBuffer = httpCmd.Split(spaceSplit, 3); if (splitBuffer.Length != 3) { TcpHelper.SendRaw(httpCmd, tunnelHostName, requestLines, args.IsSSLRequest, clientStreamReader.BaseStream); if (args != null) args.Dispose(); if (clientStreamReader != null) clientStreamReader.Dispose(); if (clientStreamWriter != null) clientStreamWriter.Dispose(); if (clientStream != null) clientStream.Dispose(); if (client != null) client.Close(); return; } var method = splitBuffer[0]; var remoteUri = splitBuffer[1]; Version version; if (splitBuffer[2] == "HTTP/1.1") { version = new Version(1, 1); } else { version = new Version(1, 0); } if (securehost != null) { remoteUri = securehost + remoteUri; args.IsSSLRequest = true; } //construct the web request that we are going to issue on behalf of the client. args.ProxyRequest = (HttpWebRequest)HttpWebRequest.Create(remoteUri.Trim()); args.ProxyRequest.Proxy = null; args.ProxyRequest.UseDefaultCredentials = true; args.ProxyRequest.Method = method; args.ProxyRequest.ProtocolVersion = version; args.ClientStream = clientStream; args.ClientStreamReader = clientStreamReader; args.ClientStreamWriter = clientStreamWriter; for (int i = 1; i < requestLines.Count; i++) { var rawHeader = requestLines[i]; String[] header = rawHeader.ToLower().Trim().Split(colonSpaceSplit, 2, StringSplitOptions.None); //if request was upgrade to web-socket protocol then relay the request without proxying if ((header[0] == "upgrade") && (header[1] == "websocket")) { TcpHelper.SendRaw(httpCmd, tunnelHostName, requestLines, args.IsSSLRequest, clientStreamReader.BaseStream); if (args != null) args.Dispose(); if (clientStreamReader != null) clientStreamReader.Dispose(); if (clientStreamWriter != null) clientStreamWriter.Dispose(); if (clientStream != null) clientStream.Dispose(); if (client != null) client.Close(); return; } } SetClientRequestHeaders(requestLines, args.ProxyRequest); int contentLen = (int)args.ProxyRequest.ContentLength; args.ProxyRequest.AllowAutoRedirect = false; args.ProxyRequest.AutomaticDecompression = DecompressionMethods.None; //If requested interception if (BeforeRequest != null) { args.RequestHostname = args.ProxyRequest.RequestUri.Host; args.RequestURL = args.ProxyRequest.RequestUri.OriginalString; args.RequestLength = contentLen; args.RequestHttpVersion = version; args.ClientPort = ((IPEndPoint)client.Client.RemoteEndPoint).Port; args.ClientIpAddress = ((IPEndPoint)client.Client.RemoteEndPoint).Address; args.RequestIsAlive = args.ProxyRequest.KeepAlive; BeforeRequest(null, args); } string tmpLine; if (args.CancelRequest) { if (args != null) args.Dispose(); if (clientStreamReader != null) clientStreamReader.Dispose(); if (clientStreamWriter != null) clientStreamWriter.Dispose(); if (clientStream != null) clientStream.Dispose(); if (client != null) client.Close(); return; } args.ProxyRequest.ConnectionGroupName = args.RequestHostname; args.ProxyRequest.AllowWriteStreamBuffering = true; //If request was modified by user if (args.RequestWasModified) { ASCIIEncoding encoding = new ASCIIEncoding(); byte[] requestBytes = encoding.GetBytes(args.RequestHtmlBody); args.ProxyRequest.ContentLength = requestBytes.Length; Stream newStream = args.ProxyRequest.GetRequestStream(); newStream.Write(requestBytes, 0, requestBytes.Length); args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args); } else { //If its a post/put request, then read the client html body and send it to server if (method.ToUpper() == "POST" || method.ToUpper() == "PUT") { SendClientRequestBody(args); //Http request body sent, now wait asynchronously for response args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args); } else { //otherwise wait for response asynchronously args.ProxyRequest.BeginGetResponse(new AsyncCallback(HandleHttpSessionResponse), args); } } //Now read the next request (if keep-Alive is enabled, otherwise exit this thread) //If client is pipeling the request, this will be immediately hit before response for previous request was made tmpLine = null; requestLines.Clear(); while (!String.IsNullOrEmpty(tmpLine = args.ClientStreamReader.ReadLine())) { requestLines.Add(tmpLine); } httpCmd = requestLines.Count() > 0 ? requestLines[0] : null; TcpClient Client = args.Client; //Http request body sent, now wait for next request Task.Factory.StartNew(() => HandleHttpSessionRequest(Client, httpCmd, args.ClientStream, args.tunnelHostName, requestLines, args.ClientStreamReader, args.ClientStreamWriter, args.securehost)); } catch { if (args != null) args.Dispose(); if (clientStreamReader != null) clientStreamReader.Dispose(); if (clientStreamWriter != null) clientStreamWriter.Dispose(); if (clientStream != null) clientStream.Dispose(); if (client != null) client.Close(); } }