Uri Constructor .NET Framework Bug? - c#

Why the thirdRelativeUri fails? Is this a .NET bug? Seems like not fixed in 4.0 either.
var googleU = new Uri("http://www.google.com");
var secondRelativeUri = new Uri(googleU,"//test.htm"); // doesn't fail
var thirdRelativeUri = new Uri(googleU,"///test.htm"); // fails - Invalid URI: The hostname could not be parsed.
UPDATE:
#dariom pointed out that this is because protocol relative URL handling in .NET which make sense however this still seems buggy to me:
var thirdRelativeUri = new Uri("///test.htm",UriKind.Relative); // works as expected
var newUri = new Uri(googleU,thirdRelativeUri); //Fails, same error even though it's a relative URI
It fails even when the second Uri is Relative

The file uri scheme (RFC 1738) file://[host]/path shows that host is optional. ///test.html would mean "Since this usually used for local files the host from RFC 1738 is often empty leading to a starting triple /. (ref)"
Change ///test.htm to file:///test.htm and the URI constructor will parse it properly. It's AbsolutePath will be /test.html.
Hope this helps.

I think that the constructor is interpreting "//test.htm" as a URI with no scheme and a hostname of test.htm. You can see this by examining the value of secondRelativeUri - it's "http://test.htm/".
The third URI you're creating is invalid because you have too many slashes.

new Uri(googleU,"//test.htm") mean Uri = http://test.html/ /* valid, Anyway a root somewhere */
new Uri(googleU,"///test.htm") mean Uri = http:///test.html/ /* invalid, Meaningless */
new Uri("///test.htm",UriKind.Relative); //=> Uri = ///test.htm same mistake, not relative location
var r = new Uri("test.htm",UriKind.Relative);
new Uri(googleU, r); // => Uri = http://www.google.com/test.htm

Even when creating relative URLs, .net treats a string that starts with tow slashes as a host name like in "//example.org/document". Similarly three slahes makes a confusion and an exception is thrown. If you are pretty sure these //test.htm and ///test.htm are paths, then you can try using UriBuilder class.

Related

URI encodes control signs into absolute path

We are sending data to an API with several endpoints. For this we put the base URL into a variable and appending the route info to it. But the request cannot be resolved to a service, as the URI-object is putting not printable characters into the path.
The code for create the URI object:
var uri = new Uri(_url + "/api/v1/create");
The result is:
https://localhost%E2%80%8B/api%E2%80%8B/v1%E2%80%8B/create
We are using .Net Framework 4.7.2.
Does anyone know, whats happening?
As canton7 pointed out, the problem had been the zero-length space here
We retyped the whole method calls - not only the URLs - and now the system is running. Thanks.

Invalid URI: Invalid port specified in C# on specifying URL with port number in it like http://localhost:8080/jasperserver/rest

I created a simple function to execute an Http PUT request -
public string checkIfUserExists(string userName)
{
var endPoint = new Uri("http://localhost:8080/jasperserver/rest_v2/users/"+userName);
var request = (HttpWebRequest)WebRequest.Create(endPoint);
request.Method = "PUT";
request.ContentType = "urlencoded";
var response = (HttpWebResponse)request.GetResponse();
return "Success";
}
when I execute this, I get an exception "Invalid URI: Invalid port specified" at the line -
var endPoint = new Uri("http://localhost:8080/jasperserver/rest_v2/users/"+userName);
Any ideas for fixing this? Is the problem with localhost:8080 portion of the URL?
I was facing this problem and found out that it is my carelessness causes this issue. I was getting the issue while I create an instance of HttpRequestMessage as follows.
var request = new HttpRequestMessage(new HttpMethod("PUT"),
$"{_nextcloudConfigurationProvider.NextcloudBaseUrl}{FileConstants.ApiUploadFile.Replace("{UserName}", UserName)}");
The issue was I missed a slash "/" before my second constant. It was remote.php/dav/files/{UserName}/{directoryName}/ instead of /remote.php/dav/files/{UserName}/{directoryName}/. Adding the slash fixed the issue for me.
Just sharing this for the people who miss silly things, like me.
Have a look at this question Invalid URI: Invalid port specified when url has more than one colon
Have you checked your username for characters that could cause a problem?
EDIT after comment - The reason that I referenced this question was because the 'Invalid Port' error occurred not because the actual port was wrong, but because of other invalid characters in the URL. Validating that the username is correctly encoded will prevent this problem.
var endPoint = new Uri("http://localhost:8080/jasperserver/rest_v2/users/"
+ HttpUtility.UrlEncode(userName));
I fixed this error using string.Concat() method:-
var endPoint = new Uri(string.Concat("http://localhost:8080/jasperserver/rest_v2/users/", userName));
Make sure you're using something like https://msdn.microsoft.com/en-us/library/system.web.httputility.urlencode%28v=vs.110%29.aspx on the userName param before you concat it to the URL.

C# Uri class - stripping off a port number from Authority

I'm trying tu use System.Uri to strip off various information.
E.g. it gets me Uri.Authority.
When my URI is http://some.domain:52146/something, Uri.Authority.ToString() gives me "some.domain:52146".
I'd rather have "some.domain" and the port with a separate call.
Any ideas whow I could strip off the :port_number stuff most elegantly, either with a Uri-method I don't know of or with some string manipulation?
And getting back the http:// would also be useful (to know for example whether it's http or https).
Use Uri.Host and Uri.Port:
Uri uri = new Uri("http://some.domain:52146/something");
string host = uri.Host; // some.domain
int port = uri.Port; // 52146
Since I learnt about the properties Uri.Host and Uri.Port now I know that Uri.Scheme gives me the protocol.

How to encode a path that contains a hash?

How do you properly encode a path that includes a hash (#) in it? Note the hash is not the fragment (bookmark?) indicator but part of the path name.
For example, if there is a path like this:
http://www.contoso.com/code/c#/somecode.cs
It causes problems when you for example try do this:
Uri myUri = new Uri("http://www.contoso.com/code/c#/somecode.cs");
It would seem that it interprets the hash as the fragment indicator.
It feels wrong to manually replace # with %23. Are there other characters that should be replaced?
There are some escaping methods in Uri and HttpUtility but none seem to do the trick.
There are a few characters you are not supposed to use. You can try to work your way through this very dry documentation, or refer to this handy URL summary on Stack Overflow.
If you check out this very website, you'll see that their C# questions are encoded %23.
Stack Overflow C# Questions
You can do this using either (for ASP.NET):
string.Format("http://www.contoso.com/code/{0}/somecode.cs",
Server.UrlEncode("c#")
);
Or for class libraries / desktop:
string.Format("http://www.contoso.com/code/{0}/somecode.cs",
HttpUtility.UrlEncode("c#")
);
Did some more digging friends and found a duplicate question for Java:
HTTP URL Address Encoding in Java
However, the .Net Uri class does not offer the constructor we need, but the UriBuilder does.
So, in order to construct a proper URI where the path contains illegal characters, do this:
// Build Uri by explicitly specifying the constituent parts. This way, the hash is not confused with fragment identifier
UriBuilder uriBuilder = new UriBuilder("http", "www.contoso.com", 80, "/code/c#/somecode.cs");
Debug.WriteLine(uriBuilder.Uri);
// This outputs: http://www.contoso.com/code/c%23/somecode.cs
Notice how it does not unnecessarily escape parts of the URI that does not need escaping (like the :// part) which is the case with HttpUtility.UrlEncode. It would seem that the purpose of this class is actually to encode the querystring/fragment part of the URL - not the scheme or hostname.
Use UrlEncode: System.Web.HttpUtility.UrlEncode(string)
class Program
{
static void Main(string[] args)
{
string url = "http://www.contoso.com/code/c#/somecode.cs";
string enc = HttpUtility.UrlEncode(url);
Console.WriteLine("Original: {0} ... Encoded {1}", url, enc);
Console.ReadLine();
}
}

Why doesn't FTPWebRequest, or WebRequest in general accept a /../ path?

I am trying to automate some upload/download tasks from an ftp web server. When I connect to the server through client, or through Firefox even, in order to get to my directory, I have to specify a path like this:
ftp://ftpserver.com/../AB00000/incoming/files
If I try to access this:
ftp://ftpserver.com/AB00000/incoming/files
The server throws an error that the directory does not exist. So, the problem:
I am trying to create an FTPWebRequest with the first ftp address, but it always parses out the "/../" part and then my server says the path doesn't exist.
I've tried these:
Uri target = new Uri("ftp://ftpserver.com/../AB00000/incoming/files");
FtpWebRequest request = (FtpWebRequest)WebReqeuest.Create(target);
and
string target = "ftp://ftpserver.com/../AB00000/incoming/files";
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(target);
In the first bit, the path is already incorrect when the Uri object is instantiated, in the second bit, it's after the WebRequest.Create method. Any ideas what's going on?
EDIT:
Additionally, since I posted this, I have tried creating the URI with the no parse option. I have also tried something like this:
string ftpserver = "ftp://ftpserver.com/../";
string path = "12345/01/01/file.toupload";
Uri = new Uri(ftpserver, path, true);
And it always parses out the root part ("/../").
Try escaping the .. with something like:
Uri target = new Uri("ftp://ftpserver.com/%2E%2E/AB00000/incoming/files");
That works according to this blog which I found in this discussion.
Not really sure about it, but it may be for security reasons, since allowing "/../" URIs would potentially let people navigate freely on any server's file system.
Also, the official URI RFC states that when resolving an URI one of the steps performed is actually the removal of "/../" segments, so it's not a problem in the C# library but it's regular URI behavior.
Have you tried using the # symbol like so?
Uri target = new Uri(#"ftp://ftpserver.com/../AB00000/incoming/files");
FtpWebRequest request = (FtpWebRequest)WebReqeuest.Create(target);

Categories