Alan Dean

CTO, Developer, Agile Practitioner

Photograph of Alan Dean

Sunday, June 27, 2010

Routing TcpClient HTTP requests through the default proxy

I’m coding an HttpClient at the moment: mostly for self-education but something useful might arise as well. Here is a trivial example of making an HTTP request using the TcpClient class:

string response = null;
System.Net.Sockets.TcpClient tcp = null;
try
{
    tcp = new System.Net.Sockets.TcpClient("www.example.com", 80);

    using (var stream = tcp.GetStream())
    {
        using (var writer = new System.IO.StreamWriter(stream))
        {
            writer.WriteLine("GET / HTTP/1.1");
            writer.WriteLine("Host: www.example.com");
            writer.WriteLine("Connection: close");
            writer.WriteLine(string.Empty);
            writer.Flush();
            using (var reader = new System.IO.StreamReader(stream))
            {
                response = reader.ReadToEnd();
            }
        }
    }
}
finally
{
    if (null != tcp)
    {
        tcp.Close();
    }
}

HTTP is simply an application-level protocol layered on top of TCP, so this works fine. However, as soon as the HttpClient becomes non-trivial then debugging becomes an issue. Thankfully we have tools in place to see at what’s happening on the wire. Wireshark is an excellent tool which watches all TCP traffic on a network adapter but it is somewhat overkill for watching just HTTP traffic. Fiddler, on the other hand, is my own tool of choice for monitoring HTTP traffic. Unfortunately the code shown above won’t appear in Fiddler as-is. Fiddler acts as a proxy and the code doesn’t cater for that. The TcpClient class doesn’t either because a web proxy works at the HTTP layer rather than TCP.

In over to overcome this limitation, we can use the WebClient class to resolve the default proxy.

var requestUri = new System.Uri("http://www.example.com/");
Uri proxy = null;
using (var web = new System.Net.WebClient())
{
    proxy = web.Proxy.GetProxy(requestUri);
}

tcp = new System.Net.Sockets.TcpClient(proxy.DnsSafeHost, proxy.Port);

Now Fiddler will now happily monitor the traffic. My thanks to @srstrong, @serialseb, @blowdart, @benlovell for helping me figure this out.