Thursday, July 31, 2008

Request.Url and the missing port

We have this web application that needs to call a third party site that then redirects back to us. The other app is using a configured URL to redirect back. In order to develop and debug the application, we used a router redirect with a different port like this: the external site calls http://myExternalIp:81 and it gets redirected to my own computer on port 80.

I was amazed to notice that when entering my local page, Request.Url would be in the format http://myExternalIp, without the 81 port. As the page was executed in order to debug it, I was baffled by this behaviour. I tried a few things, then I decided to replicate it on a simple empty site and there it was. The only thing I could find that had any information about the original port number was Request.Headers["Host"] which looked something like myExternalIp:81.

I guess this is a bug in the Request object, since it uses the port of the actual server instead of the one of the request, since my server was responding on port 80 on localhost and not 81.

Here is a small method that gets the real Request URL:

public static Uri GetRealRequestUri()
if ((HttpContext.Current == null) ||
(HttpContext.Current.Request == null))
throw new ApplicationException("Cannot get current request.");
return GetRealRequestUri(HttpContext.Current.Request);

public static Uri GetRealRequestUri(HttpRequest request)
if (String.IsNullOrEmpty(request.Headers["Host"]))
return request.Url;
UriBuilder ub = new UriBuilder(request.Url);
string[] realHost = request.Headers["Host"].Split(':');
string host = realHost[0];
ub.Host = host;
string portString = realHost.Length > 1 ? realHost[1] : "";
int port;
if (int.TryParse(portString, out port))
ub.Port = port;
return ub.Uri;


Anonymous said...

Well, I had the same today.
The story goes a little further...

You CAN get the port number from the url by using Request.RequestUrl.Port (this will show your port 81 again.).

But now the "magic": Copy the URL into a normal string, and observe that the port number is gone.
Now use the string.Replace() function to rplace 'http://' with something totally different like: 'http:$//' (in fact, make it an invalid URL).

When you now look at your string, the port number had magically appeared!

So .NET abuses the string to hide URL specific data FROM THE DEVELOPER!!

It typically microsoft... sigh..

Percival Burger said...

I found this page from a google search because I also just discovered the magical disappearance of the port numbers from strings. Aaargh!!!
There's no port numbers in the strings when I response.write or put in a label: Request.Url.ToString(), Request.Url.AbsoluteUri, Request.Url.OriginalString.
But when I, from code, generate an email including one of those strings, then suddenly the port number is preserved.. and it causes the link in the email to NOT WORK!!!
Thank you M$ for causing me bugs and wasting my time finding and coding around this bizarre behavior.