Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative to .NET's Uri implementation?

Tags:

c#

.net

uri

ftp

I have a problem with the .NET's Uri implementation. It seems that if the scheme is "ftp", the query part is not parsed as a Query, but as a part of the path instead.

Take the following code for example:

Uri testuri = new Uri("ftp://user:pass@localhost/?passive=true");
Console.WriteLine(testuri.Query); // Outputs an empty string
Console.WriteLine(testuri.AbsolutePath); // Outputs "/%3Fpassive=true"

It seems to me that the Uri class wrongfully parses the query part as a part of the path. However changing the scheme to http, the result is as expected:

Uri testuri = new Uri("http://user:pass@localhost/?passive=true");
Console.WriteLine(testuri.Query); // Outputs "?passive=true"
Console.WriteLine(testuri.AbsolutePath); // Outputs "/"

Does anyone have a solution to this, or know of an alternative Uri class that works as expected?

like image 556
Johnny Egeland Avatar asked Feb 10 '09 11:02

Johnny Egeland


2 Answers

Well, the problem is not that I am unable to create a FTP connection, but that URI's are not parsed accoding to RFC 2396.

What I actually intended to do was to create a Factory that provides implementations of a generic File transfer interface (containing get and put methods), based on a given connection URI. The URI defines the protocol, user info, host and path, and any properties needed to be passed should be passed through the Query part of the URI (such as the Passive mode option for the FTP connection).

However this proved difficult using the .NET Uri implementation, because it seems to parse the Query part of URI's differently based on the schema.

So I was hoping that someone knew a workaround to this, or of an alternative to the seemingly broken .NET Uri implementation. Would be nice to know before spending hours implementing my own.

like image 118
Johnny Egeland Avatar answered Oct 26 '22 12:10

Johnny Egeland


I have been struggling with the same issue for a while. Attempting to replace the existing UriParser for the "ftp" scheme using UriParser.Register throws an InvalidOperationException because the scheme is already registered.

The solution I have come up with involves using reflection to modify the existing ftp parser so that it allows the query string. This is based on a workaround to another UriParser bug.

MethodInfo getSyntax = typeof(UriParser).GetMethod("GetSyntax", System.Reflection.BindingFlags.Static
                                                              | System.Reflection.BindingFlags.NonPublic);
FieldInfo flagsField = typeof(UriParser).GetField("m_Flags", System.Reflection.BindingFlags.Instance
                                                           | System.Reflection.BindingFlags.NonPublic);
if (getSyntax != null && flagsField != null)
{
    UriParser parser = (UriParser)getSyntax.Invoke(null, new object[] { "ftp"});
    if (parser != null)
    {
        int flagsValue = (int)flagsField.GetValue(parser);

        // Set the MayHaveQuery attribute
        int MayHaveQuery = 0x20;
        if ((flagsValue & MayHaveQuery) == 0) flagsField.SetValue(parser, flagsValue | MayHaveQuery);
    }
}

Run that somewhere in your initialization, and your ftp Uris will have the query string go into the Query parameter, as you would expect, instead of Path.

like image 27
Dave Andersen Avatar answered Oct 26 '22 14:10

Dave Andersen