Как создать экземпляр Uri, проанализированный с помощью GenericUriParserOptions.DontCompressPath - PullRequest
17 голосов
/ 25 марта 2010

Когда класс .NET System.Uri анализирует строки, он выполняет некоторую нормализацию ввода, такую ​​как строчная схема и имя узла. Это также урезает конечные периоды от каждого сегмента пути. Эта последняя функция является фатальной для приложений OpenID, поскольку некоторые OpenID (например, выпущенные в Yahoo) включают закодированные в base64 сегменты пути, которые могут заканчиваться точкой.

Как отключить это поведение обрезки периода в классе Uri?

Регистрация моей собственной схемы с использованием UriParser.Register с помощью синтаксического анализатора, инициализированного GenericUriParserOptions.DontCompressPath, позволяет избежать обрезки периода и некоторых других операций, которые также нежелательны для OpenID. Но я не могу зарегистрировать новый парсер для существующих схем, таких как HTTP и HTTPS, что я должен сделать для OpenID.

Другим подходом, который я попробовал, была регистрация моей новой схемы и программирование пользовательского синтаксического анализатора для изменения схемы обратно к стандартным схемам HTTP (s) в рамках анализа:

public class MyUriParser : GenericUriParser
{
    private string actualScheme;

    public MyUriParser(string actualScheme)
        : base(GenericUriParserOptions.DontCompressPath)
    {
        this.actualScheme = actualScheme.ToLowerInvariant();
    }

    protected override string GetComponents(Uri uri, UriComponents components, UriFormat format)
    {
        string result = base.GetComponents(uri, components, format);

        // Substitute our actual desired scheme in the string if it's in there.
        if ((components & UriComponents.Scheme) != 0)
        {
            string registeredScheme = base.GetComponents(uri, UriComponents.Scheme, format);
            result = this.actualScheme + result.Substring(registeredScheme.Length);
        }

        return result;
    }
}

class Program
{
    static void Main(string[] args)
    {
        UriParser.Register(new MyUriParser("http"), "httpx", 80);
        UriParser.Register(new MyUriParser("https"), "httpsx", 443);
        Uri z = new Uri("httpsx://me.yahoo.com/b./c.#adf");
        var req = (HttpWebRequest)WebRequest.Create(z);
        req.GetResponse();
    }
}

Это на самом деле почти работает. Экземпляр Uri сообщает о https вместо httpsx везде, кроме самого свойства Uri.Scheme. Это проблема, когда вы передаете этот экземпляр Uri в HttpWebRequest для отправки запроса на этот адрес. Очевидно, он проверяет свойство Scheme и не распознает его как «https», потому что он просто отправляет открытый текст на порт 443 вместо SSL.

Я рад любому решению, которое:

  1. Сохраняет конечные периоды в сегментах пути в Uri.Path
  2. Включает эти периоды в исходящие HTTP-запросы.
  3. Идеально работает с доверием среды ASP.NET (но не обязательно).

Ответы [ 4 ]

5 голосов
/ 26 марта 2010

Microsoft говорит, что это будет исправлено в .NET 4.0 (хотя из комментариев видно, что это еще не исправлено)

https://connect.microsoft.com/VisualStudio/feedback/details/386695/system-uri-incorrectly-strips-trailing-dots?wa=wsignin1.0#tabs

Однако на этой странице есть обходной путь. Он предполагает использование отражения для изменения параметров, поэтому он может не соответствовать требованию среднего доверия. Просто прокрутите вниз и нажмите на вкладку «Временные решения».

Спасибо jxdavis и Google за этот ответ:

http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/5206beca-071f-485d-a2bd-657d635239c9

2 голосов
/ 26 марта 2010

Мне любопытно, если отчасти проблема в том, что вы учитываете только «не сжимать путь» вместо всех значений по умолчанию базового парсера HTTP: (включая UnEscapeDotsAndSlashes)

  private const UriSyntaxFlags HttpSyntaxFlags = (UriSyntaxFlags.AllowIriParsing | UriSyntaxFlags.AllowIdn | UriSyntaxFlags.UnEscapeDotsAndSlashes | UriSyntaxFlags.CanonicalizeAsFilePath | UriSyntaxFlags.CompressPath | UriSyntaxFlags.ConvertPathSlashes | UriSyntaxFlags.PathIsRooted | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MustHaveAuthority);

Это в отличие от новостей, которые имеют флаги (например):

 private const UriSyntaxFlags NewsSyntaxFlags = (UriSyntaxFlags.AllowIriParsing | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.MayHavePath);

Данг, Брэндон Блэк избил меня, пока я работал над тем, чтобы набирать тексты ...

Это может помочь с читабельностью кода:

namespace System 
{
    [Flags]
    internal enum UriSyntaxFlags
    {
        AllowAnInternetHost = 0xe00,
        AllowAnyOtherHost = 0x1000,
        AllowDnsHost = 0x200,
        AllowDOSPath = 0x100000,
        AllowEmptyHost = 0x80,
        AllowIdn = 0x4000000,
        AllowIPv4Host = 0x400,
        AllowIPv6Host = 0x800,
        AllowIriParsing = 0x10000000,
        AllowUncHost = 0x100,
        BuiltInSyntax = 0x40000,
        CanonicalizeAsFilePath = 0x1000000,
        CompressPath = 0x800000,
        ConvertPathSlashes = 0x400000,
        FileLikeUri = 0x2000,
        MailToLikeUri = 0x4000,
        MayHaveFragment = 0x40,
        MayHavePath = 0x10,
        MayHavePort = 8,
        MayHaveQuery = 0x20,
        MayHaveUserInfo = 4,
        MustHaveAuthority = 1,
        OptionalAuthority = 2,
        ParserSchemeOnly = 0x80000,
        PathIsRooted = 0x200000,
        SimpleUserSyntax = 0x20000,
        UnEscapeDotsAndSlashes = 0x2000000,
        V1_UnknownUri = 0x10000
    }
}
1 голос
/ 26 марта 2010

Это работает?

public class MyUriParser : UriParser
{
private string actualScheme;

public MyUriParser(string actualScheme)
{
    Type type = this.GetType();
    FieldInfo fInfo = type.BaseType.GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
    fInfo.SetValue(this, GenericUriParserOptions.DontCompressPath);
    this.actualScheme = actualScheme.ToLowerInvariant();
}

protected override string GetComponents(Uri uri, UriComponents components, UriFormat format)
{
    string result = base.GetComponents(uri, components, format);

    // Substitute our actual desired scheme in the string if it's in there. 
    if ((components & UriComponents.Scheme) != 0)
    {
        string registeredScheme = base.GetComponents(uri, UriComponents.Scheme, format);
        result = this.actualScheme + result.Substring(registeredScheme.Length);
    }

    return result;
}}
1 голос
/ 26 марта 2010

Вы должны быть в состоянии избежать экранирования "." используя "% 2E", но это дешевый и грязный выход.

Вы можете попробовать немного поиграть с опцией dontEscape , и это может изменить отношение Ури к этим персонажам.

Больше информации здесь: http://msdn.microsoft.com/en-us/library/system.uri.aspx

Также проверьте следующее (см. DontUnescapePathDotsAndSlashes): http: // msdn.microsoft.com/en-us/library/system.genericuriparseroptions.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...