One way is to use HttpSys
and create a local proxy server to handle request on the loopback 127.0.0.1
address. You would be change the system proxy to this address/port and sit between client and server.
This would allow you to modify request/response packets & headers. There's an example here of this approach in C#, and I've amended this below to show how it would work.
public class MyProxy
{
private readonly HttpListener listener;
public MyProxy()
{
listener = new HttpListener();
}
public void Start()
{
listener.Prefixes.Add("http://*:8888/");
listener.Prefixes.Add("https://*:8889/");
listener.Start();
Console.WriteLine("Proxy started, hit enter to stop");
listener.BeginGetContext(GetContextCallback, null);
Console.ReadLine();
listener.Stop();
}
public void GetContextCallback(IAsyncResult result)
{
var context = listener.EndGetContext(result);
listener.BeginGetContext(GetContextCallback, null);
var request = context.Request;
var response = context.Response;
var url = request.Url;
UriBuilder builder = new UriBuilder(url);
builder.Port = url.Port == 8888 ? 80 : 443;
url = builder.Uri;
WebRequest webRequest = WebRequest.Create(url);
webRequest.Proxy = GlobalProxySelection.GetEmptyWebProxy();
WebResponse webResponse = webRequest.GetResponse();
using (Stream reader = webResponse.GetResponseStream())
{
using (Stream writer = response.OutputStream)
{
reader.CopyTo(writer);
}
}
}
}
The downside to this approach is it's quite low level, and affects all traffic on the user machine which may not be desirable. You would have to handle SSL requests, and it would also impact any existing configured proxies.
Another alternative approach is to use the Microsoft Internet Controls
COM component and to extend the WebBrowser
class. There's a SO question here that shows the approach. Unfortunately the version of WebBrowser
in the .NET namespace does not implement the request response objects. The interesting bits are below.
public class ExtendedWebBrowser : WebBrowser
{
...
void BeforeNavigate(object pDisp, ref object url, ref object flags,
ref object targetFrameName, ref object postData,
ref object headers, ref bool cancel)
{
if (!headers.Contains("X-RequestFlag")
{
headers += "X-RequestFlag: true\r\n";
// append custom header here
// cancel current request
cancel = true;
// re-request with amended details
Navigate((string)url, (string)targetFrameName, (byte[])postData,
(string)headers);
}
else
{
base.BeforeNavigate(...);
}
}
}