Ejemplo n.º 1
0
 public static Control add_ProxyCacheActionsPanel(this ProxyCache proxyCache, Control actionsPanel)
 {
     actionsPanel.add_Label("Settings")
     .append_CheckBox("cache Enabled", (value) => proxyCache.enabled(value)).@checked(proxyCache.enabled())
     .append_Below_Link("show Cache entries", () => ProxyCache.RequestCache.details())
     .append_Link("clear Cache", () => ProxyCache.RequestCache.Clear())
     .append_Link("open a WebBrowser", () => "ProxyChache - test WebBrowser".popupWindow()
                  .add_WebBrowser_Control()
                  .add_NavigationBar()
                  .open("http://www.google.com"));
     return(actionsPanel);
 }
Ejemplo n.º 2
0
        private void DoHttpProcessing(TcpClient client)
        {
            var threadId = Thread.CurrentThread.ManagedThreadId;

            if (ProxyDisabled)
            {
                "[DoHttpProcessing]: ProxyDisabled is set, aborting request".error();
                return;
            }

            Stream       clientStream       = client.GetStream();
            Stream       outStream          = clientStream; //use this stream for writing out - may change if we use ssl
            SslStream    sslStream          = null;
            StreamReader clientStreamReader = new StreamReader(clientStream);

            MemoryStream cacheStream = null;

            try
            {
                HttpWebRequest  webReq             = null;
                HttpWebResponse response           = null;
                var             rawRequestHeaders  = new StringBuilder();
                var             rawResponseHeaders = new StringBuilder();
                byte[]          requestPostBytes   = null;
                var             contentLen         = 0;
                var             skipRemaingSteps   = false;

                //read the first line HTTP command
                String httpCmd = clientStreamReader.ReadLine();
                if (String.IsNullOrEmpty(httpCmd))
                {
                    clientStreamReader.Close();
                    clientStream.Close();
                    return;
                }
                //break up the line into three components
                String[] splitBuffer = httpCmd.Split(spaceSplit, 3);

                String  method    = splitBuffer[0];
                String  remoteUri = splitBuffer[1];
                Version version   = new Version(1, 0);

                ExtraLogging.ifDebug("[{2}][DoHttpProcessing]: Got request for: {0} {1} [{2}]", method, remoteUri, threadId);

                Action handleSLL_CONNECT_withCaller =
                    () => {
                    if (skipRemaingSteps)
                    {
                        return;
                    }

                    if (splitBuffer[0].ToUpper() == "CONNECT")
                    {
                        ExtraLogging.ifInfo("[{1}][DoHttpProcessing][handleSLL_CONNECT_withCaller] {0} [{1}]", remoteUri, threadId);
                        //Browser wants to create a secure tunnel
                        //instead = we are going to perform a man in the middle "attack"
                        //the user's browser should warn them of the certification errors however.
                        //Please note: THIS IS ONLY FOR TESTING PURPOSES - you are responsible for the use of this code
                        remoteUri = "https://" + splitBuffer[1];

                        ExtraLogging.ifInfo("[{1}][DoHttpProcessing][handleSLL_CONNECT_withCaller] updated remoteUri {0}, [{1}]", remoteUri, threadId);

                        while (!String.IsNullOrEmpty(clientStreamReader.ReadLine()))
                        {
                            ;
                        }

                        ExtraLogging.ifInfo("[{0}][DoHttpProcessing][handleSLL_CONNECT_withCaller] after clientStreamReader.ReadLine [{0}]", threadId);

                        StreamWriter connectStreamWriter = new StreamWriter(clientStream);
                        connectStreamWriter.WriteLine("HTTP/1.0 200 Connection established");
                        connectStreamWriter.WriteLine(String.Format("Timestamp: {0}", DateTime.Now.ToString()));
                        connectStreamWriter.WriteLine("Proxy-agent: O2 Platform Web Proxy");
                        connectStreamWriter.WriteLine();

                        connectStreamWriter.Flush();
                        //            ExtraLogging.ifDebug("[{0}][DoHttpProcessing][handleSLL_CONNECT_withCaller] afterFlush [{0}]", threadId);
                        //connectStreamWriter.Close();   //see if it has side effects with ssl sites
                        //ExtraLogging.ifDebug("[DoHttpProcessing][handleSLL_CONNECT_withCaller] afterClose");

/*			                }
 *                                              };
 *
 *                              Action handleSLL_CONNECT_withRemote =
 *                      ()=>{
 *
 *                                      if (skipRemaingSteps)
 *                                                              return;
 */
//			                if (splitBuffer[0].ToUpper() == "CONNECT")
//			                {
                        //ExtraLogging.ifInfo("[DoHttpProcessing][handleSLL_CONNECT_withRemote] {0}", remoteUri);

                        try
                        {
                            var keepStreamOpen             = true;
                            var checkCertificateRevocation = true;
                            ExtraLogging.ifInfo("[{1}][DoHttpProcessing][handleSLL_CONNECT_withCaller] creating sslStream and AuthenticateAsServer {0} [{1}]", remoteUri, threadId);
                            //sslStream = new SslStream(clientStream, false);		//original
                            sslStream = new SslStream(clientStream, keepStreamOpen);
                            //sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, true);   //original
                            //sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, false);
                            sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, checkCertificateRevocation);
                        }
                        catch (Exception ex)
                        {
                            skipRemaingSteps = true;
                            "[{1}][Proxy Server][handleSLL_CONNECT] in sslStream.AuthenticateAsServer: {0} [{1}]".error(ex.Message, threadId);
                            if (ex.Message == "Authentication failed because the remote party has closed the transport stream.")
                            {
                                "[Proxy Server][handleSLL_CONNECT] NOTE: this error is usually callsed by the browser not accepting the temp certificate".info();
                            }
                            else
                            {
                                "[Proxy Server][handleSLL_CONNECT] NOTE: this error is usually caused by running with UAC, start the script in non UAC".info();                          //.lineBefore().lineBeforeAndAfter()
                            }
                            try
                            {
                                sslStream.Close();
                                clientStreamReader.Close();
                                connectStreamWriter.Close();                         // check for side effect
                                clientStream.Close();
                            }
                            catch (Exception ex2)
                            {
                                "[{1}][Proxy Server][handleSLL_CONNECT] in CATCH of sslStream.AuthenticateAsServer: {0} [{1}]".error(ex2.Message, threadId);
                            }
                        }
                        if (skipRemaingSteps)
                        {
                            return;
                        }

                        //HTTPS server created - we can now decrypt the client's traffic
                        clientStream       = sslStream;
                        clientStreamReader = new StreamReader(sslStream);
                        outStream          = sslStream;
                        //read the new http command.
                        try
                        {
                            httpCmd = clientStreamReader.ReadLine();
                        }
                        catch (Exception ex)
                        {
                            "[{1}][Proxy Server] in clientStreamReader.ReadLine() {0} [{1}]".error(ex.Message, threadId);
                            httpCmd = null;
                        }
                        if (String.IsNullOrEmpty(httpCmd))
                        {
                            clientStreamReader.Close();
                            clientStream.Close();
                            sslStream.Close();
                            return;
                        }
                        splitBuffer = httpCmd.Split(spaceSplit, 3);
                        method      = splitBuffer[0];
                        remoteUri   = remoteUri + splitBuffer[1];
                    }
                };

                Action createWebRequest =
                    () => {
                    if (skipRemaingSteps)
                    {
                        return;
                    }
                    ExtraLogging.ifInfo("[{1}][DoHttpProcessing][createWebRequest] {0} [{1}]", remoteUri, threadId);
                    //construct the web request that we are going to issue on behalf of the client.
                    remoteUri              = remoteUri.uri().str();                             // fixes some issues where the uri is missing the initial protocol
                    webReq                 = (HttpWebRequest)HttpWebRequest.Create(remoteUri);
                    webReq.Method          = method;
                    webReq.ProtocolVersion = version;

                    //read the request headers from the client and copy them to our request
                    contentLen = ReadRequestHeaders(clientStreamReader, webReq, rawRequestHeaders);

                    webReq.Proxy                  = null;
                    webReq.KeepAlive              = false;
                    webReq.AllowAutoRedirect      = false;
                    webReq.AutomaticDecompression = DecompressionMethods.None;
                };

                Action capturePostData =
                    () => {
                    if (skipRemaingSteps)
                    {
                        return;
                    }
                    if (method.ToUpper() == "POST")
                    {
                        ExtraLogging.ifInfo("[{1}][DoHttpProcessing][capturePostData] {0} [{1}]", remoteUri, threadId);
                        var bytesToRead  = contentLen;
                        var maxReadBlock = 2048;                                        // try 100 to see better what is going on

                        int bytesRead;
                        //int totalBytesRead = 0;
                        var readString = new StringBuilder();
                        var postData   = new StreamWriter(new MemoryStream());
                        //DCz I had to change how the original was doing since ReadBlock would free on large posts
                        //while (totalBytesRead < contentLen && (bytesRead = clientStreamReader.ReadBlock(postBuffer, 0, contentLen)) > 0)
                        do
                        {
                            var readThisBytes = (bytesToRead > maxReadBlock)
                                                                                                        ? maxReadBlock
                                                                                                        : bytesToRead;
                            char[] postBuffer = new char[readThisBytes];
                            bytesRead = clientStreamReader.Read(postBuffer, 0, readThisBytes);
                            //Weirdly the conversion into string gives me a more accurate length than bytes read
                            var snipptet = Encoding.UTF8.GetBytes(postBuffer).ascii();
                            readString.Append(snipptet);
                            //totalBytesRead += snipptet.size();
                            postData.Write(postBuffer, 0, bytesRead);
                            bytesToRead -= snipptet.size();                     //depending on the chars this will change

                            /*"bytes read:{0} of {1} (from {2}  still left {3})  {4}  readString: {4}".info(
                             *                      bytesRead, readThisBytes, contentLen ,bytesToRead,
                             *                      snipptet, readString.size());*/
                        }while(bytesToRead > 0 || bytesRead == 0);
                        postData.Flush();
                        requestPostBytes = (postData.BaseStream as MemoryStream).ToArray();
                    }
                };


                Action writePostDataToRequestStream =
                    () => {
                    if (skipRemaingSteps)
                    {
                        return;
                    }
                    if (method.ToUpper() == "POST")
                    {
                        ExtraLogging.ifInfo("[{1}][DoHttpProcessing][writePostDataToRequestStream] {0} [{1}]", remoteUri, threadId);
                        var          requestPostChars = Encoding.UTF8.GetChars(requestPostBytes);
                        StreamWriter sw = new StreamWriter(webReq.GetRequestStream());
                        sw.Write(requestPostChars.ToArray(), 0, requestPostChars.Length);
                        sw.Flush();
                        sw.Close();
                    }
                };


                Action getResponse =
                    () => {
                    if (skipRemaingSteps)
                    {
                        return;
                    }
                    ExtraLogging.ifInfo("[{1}][DoHttpProcessing][getResponse] {0} [{1}]", remoteUri, threadId);

                    webReq.Timeout = 15000;
                    try
                    {
                        response = (HttpWebResponse)webReq.GetResponse();
                    }
                    catch (WebException webEx)
                    {
                        response = webEx.Response as HttpWebResponse;
                        "[{1}][DoHttpProcessing][getResponse] {0} [{1}]: {2}".error(remoteUri, threadId, webEx.Message);
                        //webEx.log();
                    }
                };


                Action handleResponse_viaCache =
                    () => {
                    if (skipRemaingSteps)
                    {
                        return;
                    }
                    ExtraLogging.ifInfo("[{1}][DoHttpProcessing][handleResponse_viaCache] {0} [{1}]", remoteUri, threadId);
                    if (proxyCache.enabled())
                    {
                        ExtraLogging.ifInfo("[{1}][DoHttpProcessing][handleResponse_viaCache] Replying using Cache: {0} [{1}]", remoteUri, threadId);
                        //Stream responseStream = response.GetResponseStream();
                        var cacheObject = proxyCache.getMapping(webReq, requestPostBytes);
                        if (cacheObject.notNull())
                        {
                            StreamWriter myResponseWriter = new StreamWriter(outStream);
                            WriteResponseStatus(cacheObject.WebResponse.StatusCode,
                                                cacheObject.WebResponse.StatusDescription,
                                                myResponseWriter);

                            WriteResponseHeaders(myResponseWriter, cacheObject.Response_Headers);
                            outStream.Write(cacheObject.Response_Bytes, 0, cacheObject.Response_Bytes.Length);
                            //responseStream.Close();
                            outStream.Flush();

                            //responseStream.Close();
                            //response.Close();
                            myResponseWriter.Close();
                            skipRemaingSteps = true;
                        }
                    }
                };

                Action handleResponse_viaRealTarget =
                    () => {
                    if (skipRemaingSteps)
                    {
                        return;
                    }

                    ExtraLogging.ifInfo("[{1}][DoHttpProcessing][handleResponse_viaRealTarget]: {0} [{1}]", remoteUri, threadId);
                    if (response == null)
                    {
                        "[{1}][ProxyServer][DoHttpProcessing][handleResponse_viaRealTarget] Response was null {0} [{1}]".error(remoteUri, threadId);
                    }

                    StreamWriter myResponseWriter;
                    Stream       responseStream;
                    List <Tuple <String, String> > responseHeaders = null;
                    var memoryStream = new MemoryStream();
                    var binaryWriter = new  BinaryWriter(memoryStream);

                    Action addResponseToCache =
                        () => {
                        var responseString = response.isNull()
                                                                                                                ? ""
                                                                                                                :       (response.ContentEncoding == "gzip")
                                                                                                                ? memoryStream.ToArray().gzip_Decompress().ascii()
                                                                                                                : memoryStream.ToArray().ascii();

                        var requestResponseData = proxyCache.add(webReq, response, requestPostBytes, memoryStream.ToArray(), responseString);

                        requestResponseData.Request_Headers_Raw  = rawRequestHeaders.str();
                        requestResponseData.Response_Headers_Raw = rawResponseHeaders.str();
                        requestResponseData.Response_Headers     = responseHeaders;

                        if (OnResponseReceived.notNull())
                        {
                            OnResponseReceived(requestResponseData);                            //webReq, response,memoryStream.ToArray().ascii());//UTF8Encoding.UTF8.GetString(memoryStream.ToArray(), 0, (int)memoryStream.Length));
                        }
                    };

                    try
                    {
                        if (response.isNull() || response.StatusCode.str() == "BadRequest")
                        {
                            ExtraLogging.ifInfo("[{0}][ProxyServer][handleResponse] skipping due to response being null or response.StatusCode == BadRequest ", threadId);
                            "[{0}][ProxyServer][handleResponse] skipping due to response being null or response.StatusCode == BadRequest ".error(threadId);
                            addResponseToCache();
                            return;
                        }
                        myResponseWriter = new StreamWriter(outStream);
                        responseStream   = response.GetResponseStream();
                        responseHeaders  = ProcessResponse(response, rawResponseHeaders);
                    }
                    catch (Exception ex)
                    {
                        "[{2}][ProxyServer][handleResponse] before processing response body:  {0}  {1} [{2}]".error(ex.Message, remoteUri, threadId);
                        addResponseToCache();
                        return;
                    }

                    try
                    {
                        //send the response status and response headers
                        WriteResponseStatus(response.StatusCode, response.StatusDescription, myResponseWriter);
                        WriteResponseHeaders(myResponseWriter, responseHeaders);

                        Byte[] buffer;
                        if (response.ContentLength > 0)
                        {
                            buffer = new Byte[response.ContentLength];
                        }
                        else
                        {
                            buffer = new Byte[BUFFER_SIZE];
                        }

                        int bytesRead;



                        while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            binaryWriter.Write(buffer, 0, bytesRead);
                        }

                        binaryWriter.Flush();

                        if (memoryStream.Length > Int32.MaxValue)
                        {
                            "[ProxyServer][handleResponse]: memoryStream.Length >  Int32.MaxValue".error();
                        }

                        try
                        {
                            outStream.Write(memoryStream.ToArray(), 0, (int)memoryStream.Length);
                        }
                        catch (Exception ex)
                        {
                            "[{2}][ProxyServer][handleResponse] in outStream.Write: {0}  {1}".error(ex.Message, remoteUri, threadId);
                        }

                        addResponseToCache();

                        responseStream.Close();
                        outStream.Flush();
                    }
                    catch (Exception ex)
                    {
                        "[{2}][ProxyServer][handleResponse]  while processing response body: {0}  {1} [{2}]".error(ex.logStackTrace().Message, remoteUri, threadId);
                    }
                    finally
                    {
                        responseStream.Close();
                        response.Close();
                        myResponseWriter.Close();
                    }
                };


                handleSLL_CONNECT_withCaller();
                //handleSLL_CONNECT_withRemote();
                // O2 callback
                if (InterceptRemoteUrl.notNull())
                {
                    remoteUri = InterceptRemoteUrl(remoteUri);
                }

                createWebRequest();
                capturePostData();

                //put capturePostDatainterceptor callback here
                handleResponse_viaCache();

                if (HandleWebRequestProxyCommands.notNull() && HandleWebRequestProxyCommands(webReq, remoteUri) == false)                                       // O2 callback
                {
                    skipRemaingSteps = true;
                }

//				handleSLL_CONNECT_withRemote();

                if (InterceptWebRequest.notNull())
                {
                    InterceptWebRequest(webReq);
                }

                writePostDataToRequestStream();

                getResponse();

                handleResponse_viaRealTarget();

                if (skipRemaingSteps)
                {
                    ExtraLogging.ifError("[{1}][DoHttpProcessing] skipRemaingSteps was set for: {0} [{1}]", remoteUri, threadId);
                }

                ExtraLogging.ifDebug("[{1}][DoHttpProcessing] ended for: {0} [{1}]", remoteUri, threadId);
            }
            catch (Exception ex)
            {
                "[ProxyServer][DoHttpProcessing]: {0}".error(ex.logStackTrace().Message);
            }
            finally
            {
                /*if (Server.DumpHeaders || Server.DumpPostData || Server.DumpResponseData)
                 * {
                 *  //release the lock
                 *  Monitor.Exit(_outputLockObj);
                 * }*/

                clientStreamReader.Close();
                clientStream.Close();
                if (sslStream != null)
                {
                    sslStream.Close();
                }
                outStream.Close();
                if (cacheStream != null)
                {
                    cacheStream.Close();
                }
            }
        }