title: C# Local Tcp Proxy
body: <p>I'm doing a local proxy to which I redirect browsers on my system (mainly Chrome and Firefox).
  So far I've managed to get it to work, but I'm having some trouble.</p>
  
  <p>When I navigate (in the browser) to some websites (e.g. css-tricks.com) things will blow up:</p>
  
  <h3>Log</h3>
  
  <pre><code>GET http://css-tricks.com/ HTTP/1.1
  Host: css-tricks.com
  Proxy-Connection: keep-alive
  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1521.0 Safari/537.36
  Accept-Encoding: gzip,deflate,sdch
  Accept-Language: en-US,en;q=0.8
  
  HTTP/1.1 301 Moved Permanently
  Date: Tue, 28 May 2013 21:00:49 GMT
  Server: Apache
  X-Pingback: http://css-tricks.com/xmlrpc.php
  Expires: Wed, 11 Jan 1984 05:00:00 GMT
  Cache-Control: no-cache, must-revalidate, max-age=0
  Pragma: no-cache
  X-Powered-By: W3 Total Cache/0.9.2.10
  Location: http://css-tricks.comhttp/css-tricks.com/
  X-Powered-By: PleskLin
  Vary: User-Agent,Accept-Encoding
  Content-Encoding: gzip
  Content-Length: 20
  Content-Type: text/html; charset=UTF-8
  
  GET http://css-tricks.comhttp/css-tricks.com/ HTTP/1.1
  Host: css-tricks.comhttp
  Proxy-Connection: keep-alive
  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1521.0 Safari/537.36
  Accept-Encoding: gzip,deflate,sdch
  Accept-Language: en-US,en;q=0.8
  
  Exception: No such host is known.
  </code></pre>
  
  <h3>Code</h3>
  
  <pre><code>    private void Listen()
      {
          try
          {
              //server is a TcpListener
              var result = server.BeginAcceptTcpClient(Bridge, server);
          }
          catch (SocketException e)
          {
              log("SocketException: {0}", e);
              server.Stop();
          }
      }
  
      private void Bridge(IAsyncResult result)
      {
          try
          {
              if (stopped) return;
              var client = server.EndAcceptTcpClient(result);
              var t = new Thread(() =&gt; this.Connect(client));
              t.Start();
              this.Listen();
          }
          catch (Exception ex)
          {
              log("Error: {0}", ex.Message);
          }
      }
  
      private void Connect(TcpClient client)
      {
          using (client)
          {
              client.NoDelay = true;
              client.ReceiveBufferSize = Environment.SystemPageSize;
  
              using (var stream = client.GetStream())
              {
                  var buffer = new byte[client.ReceiveBufferSize];
  
                  using (var ms = new MemoryStream())
                  {
                      do
                      {
                          var i = stream.Read(buffer, 0, buffer.Length);
                          ms.Write(buffer, 0, i);
                          Thread.Sleep(1);
                      }
                      while (stream.DataAvailable &amp;&amp; stream.CanRead);
                      var data = ms.ToArray();
                      if (data.Length &gt; 0 &amp;&amp; stream.CanWrite)
                      {
                          Forward(data, stream);
                      }
                  }
  
              }
          }
  
      }
  
      private void Forward(byte[] data, Stream stream_browser)
      {
          var text = Encoding.ASCII.GetString(data);
          string[] lines = Regex.Split(text, "\r\n"), items = lines[0].Split(' ');
          string method = items[0], url = items[1];
          var headers = new Dictionary&lt;string, string&gt;();
  
          log(text);
  
          if (method == "CONNECT")
          {
              data = Encoding.ASCII.GetBytes("HTTP/1.1 404 NOT FOUND");
              stream_browser.Write(data, 0, data.Length);
              return;
          }
  
          for (var i = 1; i &lt; lines.Length; i++)
          {
              var index = lines[i].IndexOf(':');
              if (index &lt; 0) continue;
              string header = lines[i].Remove(index), value = lines[i].Substring(index + 1).TrimStart(' ');
              headers.Add(header.ToLower(), value);
          }
  
          var host = headers["host"];
  
          //cache is a ConcurrentDictionary I use to minimize DNS calls
          IPAddress ip;
          if (cache.ContainsKey(host))
          {
              cache.TryGetValue(host, out ip);
          }
          else
          {
              var ips = Dns.GetHostAddresses(host);
              if (ips.Length == 0)
              {
                  log("Couldn't resolve the IP of {0}", host);
                  return;
              }
              ip = ips[0];
              cache.TryAdd(host, ip);
  
          }
  
          using (var client = new TcpClient())
          {
              client.Connect(ip, 80);
              client.NoDelay = true;
              client.ReceiveBufferSize = Environment.SystemPageSize;
              using (var stream = client.GetStream())
              {
                  stream.Write(data, 0, data.Length);
                  var buffer = new byte[client.ReceiveBufferSize];
                  using (stream_browser)
                  {
                      int len;
                      while ((len = stream.Read(buffer, 0, buffer.Length)) &gt; 0)
                      {
                          stream_browser.Write(buffer, 0, len);
                          log(Encoding.Default.GetString(buffer));
                      }
                  }
              }
  
          }
      }
  </code></pre>
  
  <p>Thanks.</p>