C# web services - why does http://localhost//testservice (two slashes) work? - c#

I am writing a test web service, and noticed a strange corner case. If you include two slashes after the port, the method will be called anyway for localhost, localhost:80, 127.0.0.1, and 127.0.0.1:80. But if I try it on the web server I'm developing on (port 55731), it fails.
localhost.Service1 s = new localhost.Service1();
string uri = "http://localhost//testService.asmx";
s.Url = uri;
double result = s.multiply(5,5);
Here's the specific cases:
uri = "http://localhost//testService.asmx"; // works
uri = "http://localhost:80//testService.asmx"; // works
uri = "http://127.0.0.1//testService.asmx"; // works
uri = "http://127.0.0.1:80//testService.asmx"; // works
uri = "http://localhost:55731//testService.asmx"; // fails - HTTP status 400 - bad request
Any idea why this is the case? I know I should have just one slash after the port, just curious.

It's an implementation detail specific to a web server. One server may consolidate the slashes into a single slash, another may look for a directory with an empty string as the name, or does a pattern check on it.
I'm assuming your webserver on port 80 is differnt from the one on 55731, IIS has many differences from the devserver.

Related

UriHelper how to get production url path

var displayUrl = UriHelper.GetDisplayUrl(Request);
var urlBuilder = new UriBuilder(displayUrl) { Query = null, Fragment = null };
string _activation_url = urlBuilder.ToString().Substring(0, urlBuilder.ToString().LastIndexOf("/")) +"/this_is_my_link.html";
I expect to get correct uri production path, but I still get
http://localhost:5000/api/mdc/this_is_my_link.html
I deployed this on centos 7
please help me..
Thanks
Don
If you are using a reverse proxy, you should read this guide from Microsoft.
Essentially, your reverse proxy should provide these headers to your ASP.NET Core Application:
X-Forwarded-For - The client IP
X-Forwarded-Host - The Host header from the client (e.g. www.example.com:80)
X-Forwarded-Proto - The protocl (e.g. HTTPS)
Then you need to configure your ASP.NET Core application to accept them. You can do so by calling the app.UseForwardedHeaders() method in your Startup's Configure method.
By default (if I'm reading the docs correctly) UseForwardedHeaders (called as above) will accept X-Forwarded-For and X-Forwarded-Proto from a localhost reverse proxy.
If your situation is more complicated than that, you must configure the headers you want/the trusted reverse proxies:
var forwardedOptions = new ForwardedHeadersOptions()
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedProto // allow for, host, and proto (ForwardedHeaders.All also works here)
};
// if it's a single IP or a set of IPs but not a whole subnet
forwardedOptions.KnownProxies.Add(IPAddress.Parse("192.168.0.5"));
// if it's a whole subnet
forwardedOptions.KnownNetworks.Add(new IPNetwork("192.168.0.1", 24)); // 192.168.0.1 - 192.168.0.254
app.UseForwardedHeaders(forwardedOptions);
Also note that, depending on the reverse proxy you use, you might need to configure this on the reverse proxy
on asp core use
absoluteUri = string.Concat(
request.Scheme,
"://",
request.Host.ToUriComponent(),
request.PathBase.ToUriComponent(),
request.Path.ToUriComponent(),
request.QueryString.ToUriComponent());
or you may choose either
Getting absolute URLs using ASP.NET Core

How to get current domain name in ASP.NET

I want to get the current domain name in asp.net c#.
I am using this code.
string DomainName = HttpContext.Current.Request.Url.Host;
My URL is localhost:5858but it's returning only localhost.
Now, I am using my project in localhost. I want to get localhost:5858.
For another example, when I am using this domain
www.somedomainname.com
I want to get somedomainname.com
Please give me an idea how to get the current domain name.
Try getting the “left part” of the url, like this:
string domainName = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority);
This will give you either http://localhost:5858 or https://www.somedomainname.com whether you're on local or production. If you want to drop the www part, you should configure IIS to do so, but that's another topic.
Do note that the resulting URL will not have a trailing slash.
Using Request.Url.Host is appropriate - it's how you retrieve the value of the HTTP Host: header, which specifies which hostname (domain name) the UA (browser) wants, as the Resource-path part of the HTTP request does not include the hostname.
Note that localhost:5858 is not a domain name, it is an endpoint specifier, also known as an "authority", which includes the hostname and TCP port number. This is retrieved by accessing Request.Uri.Authority.
Furthermore, it is not valid to get somedomain.com from www.somedomain.com because a webserver could be configured to serve a different site for www.somedomain.com compared to somedomain.com, however if you are sure this is valid in your case then you'll need to manually parse the hostname, though using String.Split('.') works in a pinch.
Note that webserver (IIS) configuration is distinct from ASP.NET's configuration, and that ASP.NET is actually completely ignorant of the HTTP binding configuration of the websites and web-applications that it runs under. The fact that both IIS and ASP.NET share the same configuration files (web.config) is a red-herring.
Here is a screenshot of Request.RequestUri and all its properties for everyone's reference.
You can try the following code :
Request.Url.Host +
(Request.Url.IsDefaultPort ? "" : ":" + Request.Url.Port)
I use it like this in asp.net core 3.1
var url =Request.Scheme+"://"+ Request.Host.Value;
www.somedomain.com is the domain/host. The subdomain is an important part. www. is often used interchangeably with not having one, but that has to be set up as a rule (even if it's set by default) because they are not equivalent. Think of another subdomain, like mx.. That probably has a different target than www..
Given that, I'd advise not doing this sort of thing. That said, since you're asking I imagine you have a good reason.
Personally, I'd suggest special-casing www. for this.
string host = HttpContext.Current.Request.Url.GetComponents(UriComponents.HostAndPort, UriFormat.Unescaped);;
if (host.StartsWith("www."))
return host.Substring(4);
else
return host;
Otherwise, if you're really 100% sure that you want to chop off any subdomain, you'll need something a tad more complicated.
string host = ...;
int lastDot = host.LastIndexOf('.');
int secondToLastDot = host.Substring(0, lastDot).LastIndexOf('.');
if (secondToLastDot > -1)
return host.Substring(secondToLastDot + 1);
else
return host;
Getting the port is just like other people have said.
HttpContext.Current.Request.Url.Host is returning the correct values. If you run it on www.somedomainname.com it will give you www.somedomainname.com. If you want to get the 5858 as well you need to use
HttpContext.Current.Request.Url.Port
the Request.ServerVariables object works for me. I don't know of any reason not to use it.
ServerVariables["SERVER_NAME"] and ServerVariables["HTTP_URL"] should get what you're looking for
You can try the following code to get fully qualified domain name:
Request.Url.Scheme + System.Uri.SchemeDelimiter + Request.Url.Host
Here is a quick easy way to just get the name of the url.
var urlHost = HttpContext.Current.Request.Url.Host;
var xUrlHost = urlHost.Split('.');
foreach(var thing in xUrlHost)
{
if(thing != "www" && thing != "com")
{
urlHost = thing;
}
}
To get base URL in MVC even with subdomain www.somedomain.com/subdomain:
var url = $"{Request.Url.GetLeftPart(UriPartial.Authority)}{Url.Content("~/")}";
string domainName = HttpContext.Request.Host.Value;
this line should solve it
Try this:
#Request.Url.GetLeftPart(UriPartial.Authority)

IIS treats double-encoded forward slashes in URLs differently on the first request than it does on subsequent requests

Recently my team was asked to implement an HttpModule for an ASP.NET MVC application that handled double-encoded URLs on IIS 7 and .NET 3.5. Here's the crux of the problem:
We sometimes get URLs that have double-encoded forward slashes that look like so:
http://www.example.com/%252fbar%5cbaz/foo
There are other formats that we have to handle as well, but they all have something in common, they have a double-encoded forward slash.
To fix this, we wrote an HttpModule that only acts when a URL has a double encoded forward slash, and we redirect it to a sane URL. The details aren't important, but there are two bits that are:
We can't control the fact that these URLs have double-encoded forward slashes
And we have not ugpraded to .NET 4.0 yet, nor is it on the immediate horizon.
Here's the problem:
The first request after IIS starts up shows a different URL than the second request does.
If we used the URL from the above example, the first request to IIS would look like:
http://www.example.com/bar/baz/foo
and the second request would look like:
http://www.example.com/%252fbar%5cbaz/foo
This was done by inspecting the Application.Request.Url.AbsolutePath property while debugging.
Here's the smallest code example that should reproduce the problem (create a new MVC application, and register the following HttpModule):
public class ForwardSlashHttpModule : IHttpModule
{
internal IHttpApplication Application { get; set; }
public void Dispose()
{
Application = null;
}
public void Init(HttpApplication context)
{
Initialize(new HttpApplicationAdapter(context));
}
internal void Initialize(IHttpApplication context)
{
Application = context;
context.BeginRequest += context_BeginRequest;
}
internal void context_BeginRequest(object sender, EventArgs e)
{
var url = Application.Request.Url.AbsolutePath; //<-- Problem point
//Do stuff with Url here.
}
}
Then, call the same URL on localhost:
http://www.example.com/%252fbar%5c/foo
NB: Make sure to insert a Debugger.Launch() call before the line in context_BeginRequest so that you'll be able to see it the first time IIS launches
When you execute the first request, you should see:
http://example.com/bar/foo
on subsequent requests, you should see:
http://example.com//bar/foo.
My question is: Is this a bug in IIS? Why does it provide different URLs when calling Application.Request.Url.AbsolutePath the first time, but not for any subsequent request?
Also: It doesn't matter whether the first request is for a double encoded URL or not, the second request will always be handled appropriately by IIS (or at least, as appropriate as handling double-encoded forward slashes can be). It's that very first request that is the problem.
Update
I tried a few different properties to see if one had different values on the first request:
First Request
string u = Application.Request.Url.AbsoluteUri;
"http://example.com/foo/baz/bar/"
string x = Application.Request.Url.OriginalString;
"http://example.com:80/foo/baz/bar"
string y = Application.Request.RawUrl;
"/%2ffo/baz/bar"
bool z = Application.Request.Url.IsWellFormedOriginalString();
true
The only interesting thing is that the Application.Request.RawUrl emits a single-encoded Forward slash (%2f), and translates the encoded backslash (%5c) to a forwardslash (although everything else does that as well).
The RawUrl is still partially encoded on the first request.
Second Request
string u = Application.Request.Url.AbsoluteUri;
"http://example.com//foo/baz/bar"
string x = Application.Request.Url.OriginalString;
"http://example.com:80/%2ffoo/baz/bar"
string y = Application.Request.RawUrl;
"/%2ffoo/baz/bar"
bool z = Application.Request.Url.IsWellFormedOriginalString();
false
Interesting points from the second request:
IsWellFormedOriginalString() is false. On the first request it was true.
The RawUrl is the same (potentially helpful).
The AbsoluteUri is different. On the second request, it has two forward slashes.
Update
Application.Request.ServerVariables["URL"] = /quotes/gc/v12/CMX
Application.Request.ServerVariables["CACHE_URL"] = http://example.com:80/%2ffoo/baz/bar
Open Questions
This seems like a bug in either IIS or .NET. Is it?
This only matters for the very first request made by an application after an iisreset
Besides using RawUrl (as we'd have to worry about a lot of other problems if we parsed the Raw Url instead of using the 'safe' URL provided by .NET), what other methods are there for us to handle this?
Keep in mind, the physical impact of this problem is low: For it to be an actual problem, the first request to the web server from a client would have to be for the above specific URL, and the chances of that happening are relatively low.
Request.Url can be decoded already - I wouldn't trust it for what you are doing.
See the internal details at:
Querystring with url-encoded ampersand prematurely decoded within Request.Url
The solution is to access the values directly via Request.RawUrl.
I realize your prob is with the path, but it seems the same thing is going on. Try the RawUrl - see if it works for you instead.
This really isn't an answer, but possibly a step in the right direction. I haven't had time to create a test harness to prove anything.
I followed this.PrivateAbsolutePath through Reflector and it goes on and on. There is a lot of string manipulation when it's accessed.
public string AbsolutePath
{
get
{
if (this.IsNotAbsoluteUri)
{
throw new InvalidOperationException(SR.GetString("net_uri_NotAbsolute"));
}
string privateAbsolutePath = this.PrivateAbsolutePath; //HERE
if (this.IsDosPath && (privateAbsolutePath[0] == '/'))
{
privateAbsolutePath = privateAbsolutePath.Substring(1);
}
return privateAbsolutePath;
}
}

How to use WebClient.DownloadData(to a local DummyPage.aspx)

I'm following a tutorial on this link http://www.codeproject.com/KB/aspnet/ASPNETService.aspx
Now I'm stuck at these codes
private const string DummyPageUrl =
"http://localhost/TestCacheTimeout/WebForm1.aspx";
private void HitPage()
{
WebClient client = new WebClient();
client.DownloadData(DummyPageUrl);
}
My local application address has a port number after "localhost", so how can I get the full path (can it be done in Application_Start method)? I want it to be very generic so that it can work in any cases.
Thanks a lot!
UPDATE
I tried this in the Application_Start and it runs fine, but return error right away when published to IIS7
String path = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) + VirtualPathUtility.ToAbsolute("~/");
If it is calling back to the same server, perhaps use the Request object:
var url = new Uri(Request.Url, "/TestCacheTimeout/WebForm1.aspx").AbsoluteUri;
Otherwise, store the other server's details in a config file or the database, and just give it the right value.
But a better question would be: why would you talk via http to yourself? Why not just call a class method? Personally I'd be using an external scheduled job to do this.
You need an answer that works when you roll out to a different environment that maybe has a virtual application folder.
// r is Request.Url
var url = new Uri(r, System.Web.VirtualPathUtility.ToAbsolute("~/Folder/folder/page.aspx")).AbsoluteUri;
This will work in all cases and no nasty surprises when you deploy.
I suspect you're using the ASP.NET development server that's built-in to Visual Studio, which has a tendency to change port numbers by default. If that's the case, then you might try simply configuring the development server to always use the same port, as described here. Then just add the port number to your URL, like so:
private const string DummyPageUrl =
"http://localhost:42001/TestCacheTimeout/WebForm1.aspx";

Truncating Query String & Returning Clean URL C# ASP.net

I would like to take the original URL, truncate the query string parameters, and return a cleaned up version of the URL. I would like it to occur across the whole application, so performing through the global.asax would be ideal. Also, I think a 301 redirect would be in order as well.
ie.
in: www.website.com/default.aspx?utm_source=twitter&utm_medium=social-media
out: www.website.com/default.aspx
What would be the best way to achieve this?
System.Uri is your friend here. This has many helpful utilities on it, but the one you want is GetLeftPart:
string url = "http://www.website.com/default.aspx?utm_source=twitter&utm_medium=social-media";
Uri uri = new Uri(url);
Console.WriteLine(uri.GetLeftPart(UriPartial.Path));
This gives the output: http://www.website.com/default.aspx
[The Uri class does require the protocol, http://, to be specified]
GetLeftPart basicallys says "get the left part of the uri up to and including the part I specify". This can be Scheme (just the http:// bit), Authority (the www.website.com part), Path (the /default.aspx) or Query (the querystring).
Assuming you are on an aspx web page, you can then use Response.Redirect(newUrl) to redirect the caller.
Here is a simple trick
Dim uri = New Uri(Request.Url.AbsoluteUri)
dim reqURL = uri.GetLeftPart(UriPartial.Path)
Here is a quick way of getting the root path sans the full path and query.
string path = Request.Url.AbsoluteUri.Replace(Request.Url.PathAndQuery,"");
This may look a little better.
string rawUrl = String.Concat(this.GetApplicationUrl(), Request.RawUrl);
if (rawUrl.Contains("/post/"))
{
bool hasQueryStrings = Request.QueryString.Keys.Count > 1;
if (hasQueryStrings)
{
Uri uri = new Uri(rawUrl);
rawUrl = uri.GetLeftPart(UriPartial.Path);
HtmlLink canonical = new HtmlLink();
canonical.Href = rawUrl;
canonical.Attributes["rel"] = "canonical";
Page.Header.Controls.Add(canonical);
}
}
Followed by a function to properly fetch the application URL.
Works perfectly.
I'm guessing that you want to do this because you want your users to see pretty looking URLs. The only way to get the client to "change" the URL in its address bar is to send it to a new location - i.e. you need to redirect them.
Are the query string parameters going to affect the output of your page? If so, you'll have to look at how to maintain state between requests (session variables, cookies, etc.) because your query string parameters will be lost as soon as you redirect to a page without them.
There are a few ways you can do this globally (in order of preference):
If you have direct control over your server environment then a configurable server module like ISAPI_ReWrite or IIS 7.0 URL Rewrite Module is a great approach.
A custom IHttpModule is a nice, reusable roll-your-own approach.
You can also do this in the global.asax as you suggest
You should only use the 301 response code if the resource has indeed moved permanently. Again, this depends on whether your application needs to use the query string parameters. If you use a permanent redirect a browser (that respects the 301 response code) will skip loading a URL like .../default.aspx?utm_source=twitter&utm_medium=social-media and load .../default.aspx - you'll never even know about the query string parameters.
Finally, you can use POST method requests. This gives you clean URLs and lets you pass parameters in, but will only work with <form> elements or requests you create using JavaScript.
Take a look at the UriBuilder class. You can create one with a url string, and the object will then parse this url and let you access just the elements you desire.
After completing whatever processing you need to do on the query string, just split the url on the question mark:
Dim _CleanUrl as String = Request.Url.AbsoluteUri.Split("?")(0)
Response.Redirect(_CleanUrl)
Granted, my solution is in VB.NET, but I'd imagine that it could be ported over pretty easily. And since we are only looking for the first element of the split, it even "fails" gracefully when there is no querystring.

Categories

Resources