Exemple #1
0
 public static void AddData(CacheEntry entry)
 {
     Monitor.Enter(_cacheLockObj);
     if (!_cache.Contains(entry.Key))
         _cache.Add(entry.Key, entry);
     Monitor.Exit(_cacheLockObj);
 }
Exemple #2
0
 public static CacheEntry MakeEntry(HttpWebRequest request, HttpWebResponse response,List<Tuple<String,String>> headers, DateTime? expires)
 {
     CacheEntry newEntry = new CacheEntry();
     newEntry.Expires = expires;
     newEntry.DateStored = DateTime.Now;
     newEntry.Headers = headers;
     newEntry.Key = new CacheKey(request.RequestUri.AbsoluteUri, request.UserAgent);
     newEntry.StatusCode = response.StatusCode;
     newEntry.StatusDescription = response.StatusDescription;
     if (response.ContentLength > 0)
         newEntry.ResponseBytes = new Byte[response.ContentLength];
     return newEntry;
 }
        private static void DoHttpProcessing(TcpClient client)
        {
            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);
            CacheEntry   cacheEntry         = null;
            MemoryStream cacheStream        = null;

            if (Server.DumpHeaders || Server.DumpPostData || Server.DumpResponseData)
            {
                //make sure that things print out in order - NOTE: this is bad for performance
                Monitor.TryEnter(_outputLockObj, TimeSpan.FromMilliseconds(-1.0));
            }

            try
            {
                //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);

                HttpWebRequest  webReq;
                HttpWebResponse response = null;
                if (splitBuffer[0].ToUpper() == "CONNECT")
                {
                    //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];
                    while (!String.IsNullOrEmpty(clientStreamReader.ReadLine()))
                    {
                        ;
                    }
                    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: matt-dot-net");
                    connectStreamWriter.WriteLine();
                    connectStreamWriter.Flush();

                    sslStream = new SslStream(clientStream, false);
                    try
                    {
                        sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, true);
                    }
                    catch (Exception)
                    {
                        sslStream.Close();
                        clientStreamReader.Close();
                        connectStreamWriter.Close();
                        clientStream.Close();
                        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.
                    httpCmd = clientStreamReader.ReadLine();
                    if (String.IsNullOrEmpty(httpCmd))
                    {
                        clientStreamReader.Close();
                        clientStream.Close();
                        sslStream.Close();
                        return;
                    }
                    splitBuffer = httpCmd.Split(spaceSplit, 3);
                    method      = splitBuffer[0];
                    remoteUri   = remoteUri + splitBuffer[1];
                }

                //construct the web request that we are going to issue on behalf of the client.
                webReq                 = (HttpWebRequest)HttpWebRequest.Create(remoteUri);
                webReq.Method          = method;
                webReq.ProtocolVersion = version;

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

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


                if (Server.DumpHeaders)
                {
                    Console.WriteLine(String.Format("{0} {1} HTTP/{2}", webReq.Method, webReq.RequestUri.AbsoluteUri, webReq.ProtocolVersion));
                    DumpHeaderCollectionToConsole(webReq.Headers);
                }

                //using the completed request, check our cache
                if (method.ToUpper() == "GET")
                {
                    cacheEntry = ProxyCache.GetData(webReq);
                }
                else if (method.ToUpper() == "POST")
                {
                    char[]       postBuffer = new char[contentLen];
                    int          bytesRead;
                    int          totalBytesRead = 0;
                    StreamWriter sw             = new StreamWriter(webReq.GetRequestStream());
                    while (totalBytesRead < contentLen && (bytesRead = clientStreamReader.ReadBlock(postBuffer, 0, contentLen)) > 0)
                    {
                        totalBytesRead += bytesRead;
                        sw.Write(postBuffer, 0, bytesRead);
                        if (ProxyServer.Server.DumpPostData)
                        {
                            Console.Write(postBuffer, 0, bytesRead);
                        }
                    }
                    if (Server.DumpPostData)
                    {
                        Console.WriteLine();
                        Console.WriteLine();
                    }

                    sw.Close();
                }

                if (cacheEntry == null)
                {
                    //Console.WriteLine(String.Format("ThreadID: {2} Requesting {0} on behalf of client {1}", webReq.RequestUri, client.Client.RemoteEndPoint.ToString(), Thread.CurrentThread.ManagedThreadId));
                    webReq.Timeout = 15000;

                    try
                    {
                        response = (HttpWebResponse)webReq.GetResponse();
                    }
                    catch (WebException webEx)
                    {
                        response = webEx.Response as HttpWebResponse;
                    }
                    if (response != null)
                    {
                        List <Tuple <String, String> > responseHeaders = ProcessResponse(response);
                        StreamWriter myResponseWriter = new StreamWriter(outStream);
                        Stream       responseStream   = response.GetResponseStream();
                        try
                        {
                            //send the response status and response headers
                            WriteResponseStatus(response.StatusCode, response.StatusDescription, myResponseWriter);
                            WriteResponseHeaders(myResponseWriter, responseHeaders);

                            DateTime?  expires  = null;
                            CacheEntry entry    = null;
                            Boolean    canCache = (sslStream == null && ProxyCache.CanCache(response.Headers, ref expires));
                            if (canCache)
                            {
                                entry = ProxyCache.MakeEntry(webReq, response, responseHeaders, expires);
                                if (response.ContentLength > 0)
                                {
                                    cacheStream = new MemoryStream(entry.ResponseBytes);
                                }
                            }

                            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)
                            {
                                if (cacheStream != null)
                                {
                                    cacheStream.Write(buffer, 0, bytesRead);
                                }
                                outStream.Write(buffer, 0, bytesRead);
                                if (Server.DumpResponseData)
                                {
                                    Console.Write(UTF8Encoding.UTF8.GetString(buffer, 0, bytesRead));
                                }
                            }
                            if (Server.DumpResponseData)
                            {
                                Console.WriteLine();
                                Console.WriteLine();
                            }

                            responseStream.Close();
                            if (cacheStream != null)
                            {
                                cacheStream.Flush();
                                cacheStream.Close();
                            }

                            outStream.Flush();
                            if (canCache)
                            {
                                ProxyCache.AddData(entry);
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                        finally
                        {
                            responseStream.Close();
                            response.Close();
                            myResponseWriter.Close();
                        }
                    }
                }
                else
                {
                    //serve from cache
                    StreamWriter myResponseWriter = new StreamWriter(outStream);
                    try
                    {
                        WriteResponseStatus(cacheEntry.StatusCode, cacheEntry.StatusDescription, myResponseWriter);
                        WriteResponseHeaders(myResponseWriter, cacheEntry.Headers);
                        if (cacheEntry.ResponseBytes != null)
                        {
                            outStream.Write(cacheEntry.ResponseBytes, 0, cacheEntry.ResponseBytes.Length);
                            if (ProxyServer.Server.DumpResponseData)
                            {
                                Console.Write(UTF8Encoding.UTF8.GetString(cacheEntry.ResponseBytes));
                            }
                        }
                        myResponseWriter.Close();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    finally
                    {
                        myResponseWriter.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.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();
                }
            }
        }