Why does Request["host"] == "dev.testhost.com:1234" whereas Request.Url.Host == "localhost"
Asked Answered
T

3

16

Hi all, I seem to have found a discrepancy when testing ASP.NET applications locally on the built-in web server with Visual Studio 2008 (Cassini).

I've set up a host on my local machine associating dev.testhost.com with 127.0.0.1, since I have an application that needs to change its appearance depending on the host header used to call it.

However, when I request my test application using http://dev.testhost.com:1234/index.aspx, the value of Request.Url.Host is always "localhost". Whereas the value of Request.Headers["host"] is "dev.testhost.com:1234" (as I would expect them both to be).

I'm NOT concerned that the second value includes the port number, but I am mighty confused as to why the HOST NAMES are completely different! Does anyone know if this is a known issue, or by design? Or am I being an idiot?!

I'd rather use Request.Url.Host, since that avoids having to strip out the port number when testing... - Removed due to possibly causing confusion! - Sam

Therine answered 21/12, 2009 at 17:39 Comment(1)
From the MSDN documentation at it looks like the Request.Url ought to be concerned with the request as sent to the server. Quoting from msdn.microsoft.com/en-us/library/system.web.httprequest.aspx ... > HttpRequest Class > Enables ASP.NET to read the HTTP values sent by a client during a Web request. Which is not what it appears to be doing when running in Cassini... Thanks for the answers so far, but I'm really not convinced there's any good reason for the host name to be reported differently for the same request object...Therine
N
9

Request.Headers["host"] is the value received from the application that connects to the server, while the other value is the one the server gets when it tries to get the domain name.

The browser uses in the request the domain name entered because that is used in the case of virtual domains. The server reports the one set in the server preferences, or the first one it finds.

EDIT: Looking at the code of Cassini to see if it uses some particular settings, I noticed the following code:

public string RootUrl {
  get {
    if (_port != 80) {
      return "http://localhost:" + _port + _virtualPath;
    }
    else {
      return "http://localhost" + _virtualPath;
    }
  }
}

//
// Socket listening
//

public void Start() {
  try {
    _socket = CreateSocketBindAndListen(AddressFamily.InterNetwork, IPAddress.Loopback, _port);
  }
  catch {
    _socket = CreateSocketBindAndListen(AddressFamily.InterNetworkV6, IPAddress.IPv6Loopback, _port);
  }
  // …
}

The explanation seems to be that Cassini makes explicit reference to localhost, and doesn't try to make a reverse DNS lookup. Differently, it would not use return "http://localhost" + _virtualPath;.

Nestle answered 21/12, 2009 at 17:48 Comment(6)
Well, the IP address of the server is 127.0.0.1. This has 2 hosts mapped in c:\windows\system32\drivers\etc\hosts: localhost and dev.testhost.com However, when I type in 'dev.testhost.com' the value of HttpContect.Current.Request.Url.Host is 'localhost'? On a production server, it will be whatever I type in. Why is the local testing server (Cassini) different from the live server?Therine
In which order are the hosts defined? Probably the order influences the one reported by the server.Nestle
I just tried changing the order of the hosts and this made no difference! Good idea though ;) I think it would be surprising if this worked, since that would probably require a reverse DNS lookup if it was to work consistently, which I doubt they'd put in a simple-sounding property... I suspect there is a bug in Cassini which causes this discrepancy!Therine
Are you sure there aren't any settings to change which domain name is returned from the server?Nestle
Really, I'm just confused as to why the property Url of the HttpRequest class doesn't match the URL of the HTTP request which the HttpRequest object is meant to represent... If it does some kind of server interrogation to discover some other host name associated with the server, I would expect it to be a property of some other object rather than a HttpRequest instance...Therine
Thank you! This makes perfect sense then, why the behaviour is different on Cassini than IIS :) This is the accepted answer. Could you give me a vote, as I think this justifies the question as legitimate... Thanks again!Therine
E
8

The Request.Headers["host"] is the host as specified in the http header from the browser. (e.g. this is what you'd see if you examined the traffic with Fiddler or HttpWatch)

However, ASP.NET loasds this (and other request info) into a System.Uri instance, which parses the request string into its constituent parts. In this case, "Host" refers to literally the host machine part of the original request (e.g. with the tcp port being in the Port) property.

This System.Uri class is a very useful helper class that takes all the pain out of splitting your request into it's parts, whereas the "Host:" (and for that matter the "GET") from the http header are just raw request data.

Although they both have the same name, they are not meant to be the same thing.

Emigrant answered 21/12, 2009 at 17:48 Comment(3)
Thanks for your answer, what I'm wondering though is how 'splitting up' dev.testhost.com:1234 can result in completely losing the 'dev.testhost.com' part, and have it replaced with 'localhost'? My question wasn't really about the Uri or UriBuilder classes, I understand those well ;) Also, the port number isn't the issue here at all. I've added emphasis to the 3rd paragraph of my question, maybe that will make it clearer? Thanks again ;)Therine
Well - you've said you have associated dev.testhost.com with the IP address 127.0.0.1. However, this IP address always maps to the localhost (by definition - it is the loopback address) - so any name lookup on 127.0.0.1 will map to localhost. When you say you "associating dev.testhost.com with 127.0.0.1" how did you do this? Did you edit the hosts file, or do it some other way?Emigrant
I added the entry in the hosts file. Please see kiamlaluno's answer below... It looks like this is a Cassini-specific issue...Therine
S
1

It's a matter of what the w3 specs say versus what the Microsoft Uri.Host property is supposed to contain. The naming does not imply an attempt by MS to provide identical functionality. The function that does include port numbers is Uri.Authority.

With the update you posted, you're still facing the same problem, just examining a different aspect of it. The Uri.Host property is not explicity or implicity stated to perform the same function as the headers that are defined in the w3 specs. In long form, here are some quotes from the Uri.Host MSDN page:

Uri.Host Property
Gets the host component of this instance.

Property Value

Type: System.String

A String that contains the host name. This is usually the DNS host name or IP address of the server.

There's no guarantee that this will match what is in the headers, just that it represents the host name in some form.

Salangia answered 21/12, 2009 at 17:44 Comment(7)
Thanks for your attempt, but you've mis-read the question, I've added emphasis now on the bit that said I'm NOT concerned that the second value includes the port numberTherine
My answer is still applicable - I've expanded it to make the correlation to your update more obvious, but your basic problem is an assumption that a System.Uri object should directly match up with the http headers you're retrieving with Request.Headers.Salangia
Objects of the System.Uri class just represent URIs in general, my question is about the Request.Url instance of the System.Uri class, as accessed from an aspx page that is being rendered due to a request for a particular URL. What is the point of the property Request.Uri if it does not match the Request's Url? To clarify, you can call 'Request.Url.ToString()' and it still reports http://localhost:1234/Default.aspx whereas the request was for http://dev.testhost.com:1234/Default.aspx...Therine
Simply put, Request.Url is by definition processed, not raw. The responses found in Request.Headers are not. A processed Url.Host should not be expected to match the raw output obtained from Request.Headers["host"] but should be expected to represent the same URI. This may be surprising to you, but it is not an issue.Salangia
But localhost:1234 is not the same URI as dev.testhost.com:1234 they are different as you can see ;)Therine
In the case of your machine they are the same, as they identify the same resource. Hence the name, Universal Resource Identifier/Locator.Salangia
I've been digging into this more, and I can't find any standards on what makes URIs equivalent. I see your point about knowing what the client sent, but I'm still not sure that Cassini or Request.Url returning a different hostname than what you expected is questionable, or if the fact that they are equivalent on your machine means that it is completely acceptable.Salangia

© 2022 - 2024 — McMap. All rights reserved.