2010-03-25 15 views
17

Quando la classe .NET System.Uri analizza le stringhe, esegue alcune operazioni di normalizzazione sull'input, ad esempio lo svuotamento dello schema e il nome host. Taglia inoltre i periodi finali da ogni segmento di percorso. Quest'ultima caratteristica è fatale per le applicazioni OpenID perché alcuni OpenID (come quelli emessi da Yahoo) includono segmenti di percorso codificati base64 che possono terminare con un punto.Come creare un'istanza Uri analizzata con GenericUriParserOptions.DontCompressPath

Come disabilitare questo comportamento di taglio periodico della classe Uri?

Registrazione mio sistema utilizzando UriParser.Register con un parser inizializzato con GenericUriParserOptions.DontCompressPath evita il periodo rifilatura, e alcune altre operazioni che sono anche indesiderabile per OpenID. Ma non posso registrare un nuovo parser per schemi esistenti come HTTP e HTTPS, che devo fare per OpenIDs.

Un altro approccio che ho provato era registrando il mio nuovo schema, e la programmazione del parser personalizzato per cambiare lo schema di nuovo alla standard HTTP (s) schemi come parte di analisi:

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

Questo in realtà quasi lavori. L'istanza Uri segnala https anziché httpsx ovunque, tranne la proprietà Uri.Scheme stessa. Questo è un problema quando si passa questa istanza Uri allo HttpWebRequest per inviare una richiesta a questo indirizzo. Apparentemente controlla la proprietà Scheme e non la riconosce come 'https' perché invia semplicemente testo in chiaro alla porta 443 anziché SSL.

Sono contento per qualsiasi soluzione che:

  1. Conserva punti finali in segmenti di percorso in Uri.Path
  2. include questi periodi di richieste HTTP in uscita.
  3. Idealmente funziona con il supporto medio ASP.NET (ma non assolutamente necessario).
+2

Sarebbe più facile se il codice di esempio fosse un test dell'unità guasto per illustrare qual è il problema. – Simon

+0

Il test dell'unità dovrebbe configurare un server Web HTTPS per provare l'errore. :( –

+0

Hai mai risolto questo problema con successo? Hai ancora bisogno di aiuto con questo? – jcolebrand

risposta

4

Microsoft dice che verrà risolto in .NET 4.0 (anche se sembra dai commenti che non è stato ancora fissato)

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

C'è una soluzione alternativa su quella pagina, comunque. Implica l'uso della riflessione per modificare le opzioni, quindi potrebbe non soddisfare il requisito di affidabilità medio. Basta scorrere fino in fondo e fare clic sulla scheda "Workaround".

Grazie a jxdavis e Google per questa risposta:

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

+1

Il bug di MS Connect non è aggiornato, sfortunatamente. Il team di .NET mi ha detto direttamente che .NET 4.0 non risolve il problema del punto.Ma la soluzione è interessante.Grazie –

1

Dovresti riuscire a evitare la "." usando '% 2E', ma questa è la via d'uscita poco costosa e sporca.

Si potrebbe provare a giocare con l'opzione dontEscape un po 'e potrebbe cambiare il modo in cui Uri sta trattando quei personaggi.

Maggiori informazioni qui: http://msdn.microsoft.com/en-us/library/system.uri.aspx

Verificate anche i seguenti (vedi DontUnescapePathDotsAndSlashes): http: // msdn.microsoft.com/en-us/library/system.genericuriparseroptions.aspx

+0

Grazie, Brandon. L'opzione 'DontUnescapePathDotsAndSlashes' è una soluzione possibile, anche se per funzionare efficacemente deve essere applicata ai parser HTTP e HTTPS esistenti, il che è possibile solo in .NET 4.0 (a meno che non si usi il reflection come è stato suggerito in altre risposte qui) –

2

Sono curioso di sapere se una parte del problema è che si sta accounting solo per "non comprimere il percorso", invece di tutti i default del parser HTTP di base: (compresi 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); 

Questo è in contrasto con la notizia che ha bandiere (per esempio):

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

Dang, Brandon Nero mi ha battuto ad esso, mentre stavo lavorando a digitare le cose ...

Questo può aiutare con la leggibilità del codice:

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

funziona?

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, dovrebbe riflettere su m_Table e rimuovere le voci esistenti. –

+1

Perché usare reflection per impostare un flag che può essere facilmente impostato nel costruttore di base se si deriva da 'GenericUriParser'? –

+0

Questo è esattamente il motivo per cui ho aggiunto il commento sopra :-) Volevo impostare m_Table e non m_Flags. –

Problemi correlati