c# - example - Cómo crear una instancia de Uri analizada con GenericUriParserOptions.DontCompressPath
uri path c# (4)
¿Esto funciona?
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;
}}
Cuando la clase .NET System.Uri
analiza las cadenas, realiza alguna normalización en la entrada, como el esquema inferior y el nombre de host. También recorta los períodos finales de cada segmento de trayectoria. 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 terminar con un período.
¿Cómo puedo deshabilitar este comportamiento de recorte de período de la clase Uri?
Registrar mi propio esquema utilizando UriParser.Register
con un analizador inicializado con GenericUriParserOptions.DontCompressPath
evita el recorte del período, 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, lo que debo hacer para OpenIDs.
Otro método que probé fue registrar mi propio esquema nuevo y programar el analizador personalizado para cambiar el esquema a los esquemas HTTP estándar como parte del análisis:
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();
}
}
Esto en realidad casi funciona. La instancia de Uri
informa https en lugar de httpsx en todas partes, excepto la propiedad Uri.Scheme. Eso es un problema cuando pasas esta instancia de Uri
a HttpWebRequest
para enviar una solicitud a esta dirección. Aparentemente, comprueba la propiedad del Esquema 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:
- Conserva los períodos finales en los segmentos de ruta en
Uri.Path
- Incluye estos periodos en las solicitudes HTTP salientes.
- Lo ideal es que funcione con la confianza media de ASP.NET (pero no es absolutamente necesario).
Debes ser capaz de escapar del ''.'' usando ''% 2E'', pero esa es la salida barata y sucia.
Puede intentar jugar un poco con la opción dontEscape y puede cambiar la forma en que Uri trata a esos personajes.
Más información aquí: http://msdn.microsoft.com/en-us/library/system.uri.aspx
También revise lo siguiente (vea DontUnescapePathDotsAndSlashes): http: // msdn.microsoft.com/en-us/library/system.genericuriparseroptions.aspx
Microsoft dice que se solucionará en .NET 4.0 (aunque de los comentarios se desprende que aún no se ha solucionado)
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 es posible que no cumpla con el requisito de confianza media. Simplemente desplácese hasta la parte inferior y haga clic en la pestaña "Soluciones provisionales".
Gracias a jxdavis y Google por esta respuesta:
http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/5206beca-071f-485d-a2bd-657d635239c9
Tengo curiosidad si parte del problema es que solo contabiliza "no comprimir ruta", en lugar de todos los valores predeterminados del analizador HTTP base: (incluido 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 opuesto a las noticias que tienen banderas (por ejemplo):
private const UriSyntaxFlags NewsSyntaxFlags = (UriSyntaxFlags.AllowIriParsing | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.MayHavePath);
Maldición, Brandon Black me ganó mientras trabajaba en escribir 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
}
}