views:

2986

answers:

5

I need to create a request for a web page delivered to our web sites, but I need to be able to set the host header information too. I have tried this using HttpWebRequest, but the Header information is read only (Or at least the Host part of it is). I need to do this because we want to perform the initial request for a page before the user can. We have 10 web server which are load balanced, so we need to request the file from each of the web servers.

I have tried the following:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.1.5/filename.htm");
request.Headers.Set("Host", "www.mywebsite.com");
WebResponse response = request.GetResponse();

Obviously this does not work, as I can't update the header, and I don't know if this is indeed the right way to do it.

A: 

Alright, little bit of research turns up this:

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=384456

Seems MS may do something about this at some point.

annakata
I get the exception "ArgumentException : The 'Host' header cannot be modified directly. Parameter name: name". I presume that it is read only in the HttpWebRequest class
Xetius
Down vote, because this answer does not work.
Martin Brown
Wouldn't it have been better to create a new answer rather than undelete and completely rewrite your old one?
Martin Brown
eh, possibly - not clear on the etiquette here (pointers anyone?), but I fell on the side of preserving history rather than starting again. I do wonder if I should have preserved the failed answer to visibly display it doesn't work.
annakata
The trouble is that the comments and votes that are still connected to this answer no longer make any sense. As such, in my oppinion, a new answer would have been better.
Martin Brown
+1  A: 

The "Host" header is protected and cannot be modified programmatically. I suppose to work around this, you could try and bind via reflection to the private "InnerCollection" property of the WebRequest object and calling the "Set" ar "Add" method on it to modify the Host header. I haven't tried this, but from a quick look at the source code in Reflector, I think it's easily accomplished. But yeah, binding to private properties of framework objects is not the best way to accomplish things. :) Use only if you MUST.

edit: Or like the other guy mentions in the linked question, just open up a socket and do a quick "GET" manually. Should be a no brainer, if you don't need to tinker with other stuff, like cookies or whatever else niceties the HttpWebRequest provides.

Strelok
+2  A: 

I have managed to find out a more long winded route by using sockets. I found the answer in the MSDN page for IPEndPoint:

string getString = "GET /path/mypage.htm HTTP/1.1\r\nHost: www.mysite.mobi\r\nConnection: Close\r\n\r\n";
Encoding ASCII = Encoding.ASCII;
Byte[] byteGetString = ASCII.GetBytes(getString);
Byte[] receiveByte = new Byte[256];
Socket socket = null;
String strPage = null;
try
{
    IPEndPoint ip = new IPEndPoint(IPAddress.Parse("10.23.1.93"), 80);
    socket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
    socket.Connect(ip);
}
catch (SocketException ex)
{
    Console.WriteLine("Source:" + ex.Source);
    Console.WriteLine("Message:" + ex.Message);
}
socket.Send(byteGetString, byteGetString.Length, 0);
Int32 bytes = socket.Receive(receiveByte, receiveByte.Length, 0);
strPage = strPage + ASCII.GetString(receiveByte, 0, bytes);

while (bytes > 0)
{
    bytes = socket.Receive(receiveByte, receiveByte.Length, 0);
    strPage = strPage + ASCII.GetString(receiveByte, 0, bytes);
}
socket.Close();
Xetius
+1  A: 

I know this is old, but I came across this same exact problem, and I found a better solution to this then using sockets or reflection...

What I did was create a new class that durives from WebHeaderCollection and bypasses validation of what you stick inside it:

public class MyHeaderCollection:WebHeaderCollection
{
    public new void Set(string name, string value)
    {
        AddWithoutValidate(name, value);
    }
    //or
    public new string this[string name]
    {
        get { return base[name]; }
        set { AddWithoutValidate(name, value); }
    }
}

and here is how you use it:

    var http = WebRequest.Create("http://example.com/");
    var headers = new MyHeaderCollection();
    http.Headers = headers;

    //Now you can add/override anything you like without validation:
    headers.Set("Host", http.RequestUri.Host);
    //or
    headers["Host"] = http.RequestUri.Host;

Hope this helps anyone looking for this!

Fox
This doesn't work in 3.5SP1- the collection passed to Headers is not preserved, it gets copied into a new WebHeaderCollection, so all the headers get revalidated.
nitzmahone
A: 

I've tried what Fox suggested but I can't seem to set the Headers class of the HttpWebRequest:

request.Headers = headers;

The Headers property doesn't get set. Any ideas? I'm using .NET 2.0.

Lotte