2010-03-25 14 views
17

Cuando la clase .NET System.Uri analiza cadenas, realiza cierta normalización en la entrada, como la configuración de la estructura inferior y el nombre de host. También recorta los períodos finales de cada segmento de ruta. Esta última característica es fatal para las aplicaciones OpenID porque algunos OpenID (como los emitidos por Yahoo) incluyen segmentos de ruta codificados en base64 que pueden finalizar con un período.Cómo crear una instancia de Uri analizada con GenericUriParserOptions.DontCompressPath

¿Cómo puedo desactivar este comportamiento de ajuste de período de la clase Uri?

El registro de mi propio esquema usando UriParser.Register con un analizador inicializado con GenericUriParserOptions.DontCompressPath evita el período de recorte, y algunas otras operaciones que también son indeseables para OpenID. Pero no puedo registrar un nuevo analizador para esquemas existentes como HTTP y HTTPS, que debo hacer para OpenID.

Otro enfoque que probé fue registrando mi nuevo esquema, y ​​programar el analizador personalizado para cambiar el esquema de nuevo al estándar HTTP (s) esquemas como parte del análisis sintáctico:

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(); 
    } 
} 

En realidad, esto casi trabajos. La instancia Uri informa https en lugar de httpsx en todas partes, excepto la propiedad Uri.Scheme. Ese es un problema cuando pasa esta instancia Uri al HttpWebRequest para enviar una solicitud a esta dirección. Aparentemente, comprueba la propiedad Scheme y no la reconoce como 'https' porque simplemente envía texto sin formato al puerto 443 en lugar de SSL.

estoy feliz por cualquier solución que:

  1. Conserva detrás de los períodos en los segmentos de trazado en Uri.Path
  2. incluye estos períodos en las solicitudes HTTP salientes.
  3. Lo ideal es que funcione con la confianza media de ASP.NET (pero no es absolutamente necesario).
+2

Sería más fácil si su código de muestra fuera una prueba de unidad defectuosa para ilustrar cuál es el problema. – Simon

+0

La prueba unitaria tendría que configurar un servidor web HTTPS para probar el error. :( –

+0

¿Alguna vez resolvió esto con éxito? ¿Todavía necesita ayuda con esto? – jcolebrand

Respuesta

4

Microsoft dice que será fijado en .NET 4.0 (aunque se desprende de los comentarios que no se ha fijado todavía)

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

Sin embargo, hay una solución en esa página. Sin embargo, implica el uso de la reflexión para cambiar las opciones, por lo que puede no cumplir con el requisito de confianza medio. Simplemente desplácese hasta la parte inferior y haga clic en la pestaña "Soluciones".

Gracias a jxdavis y Google para esta respuesta:

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

+1

El error de MS Connect está desactualizado, desafortunadamente. El equipo de .NET me ha dicho directamente que .NET 4.0 no soluciona el error de punto. Pero la solución es interesante. Gracias. –

1

Deberías poder escaparte del '.' usando '% 2E', pero esa es la salida barata y sucia.

Puede intentar jugar con la opción dontEscape un poco y puede cambiar la forma en que Uri trata a esos caracteres.

Más información aquí: http://msdn.microsoft.com/en-us/library/system.uri.aspx

También echa un vistazo a la siguiente (ver DontUnescapePathDotsAndSlashes): http: // msdn.microsoft.com/en-us/library/system.genericuriparseroptions.aspx

+0

Gracias, Brandon. La opción 'DontUnescapePathDotsAndSlashes' es una solución posible, aunque para funcionar efectivamente debe aplicarse a los analizadores HTTP y HTTPS existentes, lo cual solo es posible en .NET 4.0 (a menos que utilice el reflejo como se ha sugerido en otras respuestas aquí). –

2

Tengo curiosidad por si parte del problema es que sólo son la contabilidad de "no comprima ruta", en lugar de toda la incumplimientos del analizador HTTP base de: (incluyendo 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); 

eso es en comparación con la noticia de que tiene banderas (por ejemplo):

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

Dang, Brandon Negro se me adelantó, mientras yo estaba trabajando en escribir las cosas ...

Esto puede ayudar con la legibilidad del código:

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

hace este trabajo?

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; 
}} 
+0

Sorr y, debería estar reflejando en m_Table y eliminando las entradas existentes. –

+1

¿Por qué usar reflection para establecer un indicador que se puede establecer fácilmente en el constructor base si se deriva de 'GenericUriParser'? –

+0

Eso es exactamente por qué agregué el comentario anterior :-) Quise establecer m_Table y no m_Flags. –

Cuestiones relacionadas