Writing bytes to the wire
As a tester in .NET (more specifically, WCF), every now and then, I end up defining a test requirement that isn't possible to cover with simply using our WCF product code. For example, in 4.0, I wanted to test hitting a service with an Http request that contained an invalid host header. Now, the first thing I turned to was the familiar HttpWebRequest. Poking around at the properties, I couldn't find any way to provida an intentionally incorrect Host header. It was at that time I realized the only way to send this type of request to my server was to use a raw socket. Today, I'd like to share that code with you. The following snippet sends a GET request to Bing and prints the result to the console. Use your imagination with this on how you can potentially modify the raw request sent on the wire. Basically, with this snippet, you have absolute control over the bytes you send.
class Program
{
static void Main(string[] args)
{
// Create the message to be sent on the wire
// The first header contains the resource to which the request is directed.
// It's basically just "https://{host}/{resource}". Here, my resource is "/".
string message = "GET https://www.bing.com/ HTTP/1.1";
message += "\nAccept: text/html, application/xhtml+xml, */*";
message += "\nAccept-Language: en-US";
message += "\nHost: www.bing.com";
message += "\n\n";
// Don't forget those 2 newlines. After that, the message body could be added, but
// for this example, I'm just sending a GET which isn't allowed to contain a body.
// (Though I could still add one since I'm accessing the stream directly. You can't do that with Fiddler.)
// The TcpClient specifies the destination of the request (host) as well as the port.
TcpClient client = new TcpClient("www.bing.com", 80);
NetworkStream networkStream = client.GetStream();
Byte[] data = Encoding.ASCII.GetBytes(message);
networkStream.Write(data, 0, data.Length);
networkStream.Flush();
string responseData = string.Empty;
Int32 bytes;
do
{
data = new Byte[4]; // Yes, this is reading very small chunks at a time.
bytes = networkStream.Read(data, 0, data.Length);
responseData += Encoding.UTF8.GetString(data, 0, bytes);
} while (networkStream.DataAvailable);
// Now we have the response, in a string.
Console.WriteLine(responseData);
Console.ReadLine();
}
}