Perché il nome host è dichiarato non valido durante la creazione di un URI


17

Esecuzione di questo codice con JDK 1.8:

try {
    System.out.println( new URI(null, null, "5-12-145-35_s-81", 443, null, null, null));
} catch (URISyntaxException e) {
    e.printStackTrace();
}

provoca questo errore: java.net.URISyntaxException: Illegal character in hostname at index 13: //5-12-145-35_s-81:443

Da dove viene questo errore, considerando che tutti i caratteri del nome host sembrano legittimi, in base ai tipi di caratteri URI ?


Se uso questi URL: //5-12-145-35_s-81:443o /5-12-145-35_s-81:443l'errore scompare.


Dai commenti, capisco che, secondo RFC-2396 , il nome host non può contenere caratteri di sottolineatura.

La domanda che rimane ancora è perché un nome host che inizia con una barra o una doppia barra può contenere caratteri di sottolineatura?


1
@ernest_k Lo schema non è indicato, è nullo.
Eugen Covaci,

se vuoi ancora _ in url @ fg78nc la soluzione alternativa funzionerà per te. Non usare / perché il nome host non sarà valido e non creerà campo
salesh

3
Vedi RFC-2396 sezione 3.2.2. Un nome host in un URI può essere solo uno o più gruppi di caratteri alfanumerici + -, separati da punti
Mark Rotteveel,

@MarkRotteveel java.net.URI non è aggiornato con le ultime specifiche
fg78nc

@ fg78nc Sebbene RFC-3986 lo rilassi, menziona ancora che "Un nome registrato destinato alla ricerca nel DNS utilizza la sintassi definita nella Sezione 3.5 di [RFC1034] e nella Sezione 2.1 di [RFC1123]." e questa è sostanzialmente la sintassi della sezione 3.2.2 di RFC-2396.
Mark Rotteveel,

Risposte:


8

Il nome host deve corrispondere alla sintassi seguente:

hostname      = domainlabel [ "." ] | 1*( domainlabel "." ) toplabel [ "." ]
domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
toplabel      = alpha | alpha *( alphanum | "-" ) alphanum

Come puoi vedere, solo .e -sono ammessi, _non lo è.


Quindi dici che //5-12-145-35_s-81:443è permesso, e lo è, ma non per il nome host .

Per vedere come funziona:

URI uriBadHost = URI.create("//5-12-145-35_s-81:443");
System.out.println("uri = " + uriBadHost);
System.out.println("  authority = " + uriBadHost.getAuthority());
System.out.println("  host = " + uriBadHost.getHost());
System.out.println("  port = " + uriBadHost.getPort());
URI uriGoodHost = URI.create("//example.com:443");
System.out.println("uri = " + uriGoodHost);
System.out.println("  authority = " + uriGoodHost.getAuthority());
System.out.println("  host = " + uriGoodHost.getHost());
System.out.println("  port = " + uriGoodHost.getPort());

Produzione

uri = //5-12-145-35_s-81:443
  authority = 5-12-145-35_s-81:443
  host = null
  port = -1
uri = //example.com:443
  authority = example.com:443
  host = example.com
  port = 443

Come si può vedere, quando l' authorityha un nome host valido, l' hoste portvengono analizzati, ma quando non è valida, la authorityviene trattato come testo a mano libera, e non analizzato ulteriormente.


AGGIORNARE

Dal commento:

System.out.println( new URI(null, null, "/5-12-145-35_s-81", 443, null, null, null))uscite: /// 5-12-145-35_s-81: 443. Lo sto dando come nome host

Il URIcostruttore che stai chiamando è un metodo pratico e crea semplicemente una stringa URI completa e quindi analizza quello.

Il passaggio "5-12-145-35_s-81", 443diventa //5-12-145-35_s-81:443.
Il passaggio "/5-12-145-35_s-81", 443diventa ///5-12-145-35_s-81:443.

Nel primo, è un host e una porta e non riesce ad analizzare.
Nel secondo la parte di autorità è vuota ed /5-12-145-35_s-81:443è un percorso .

URI uri1 = new URI(null, null, "/5-12-145-35_s-81", 443, null, null, null);
System.out.println("uri = " + uri1);
System.out.println("  authority = " + uri1.getAuthority());
System.out.println("  host = " + uri1.getHost());
System.out.println("  port = " + uri1.getPort());
System.out.println("  path = " + uri1.getPath());

Produzione

uri = ///5-12-145-35_s-81:443
  authority = null
  host = null
  port = -1
  path = /5-12-145-35_s-81:443

Ora capisco, ma perché, diciamo /a_b, è permesso. L'unica differenza è che questo è assoluto, non relativo
Eugen Covaci,

System.out.println( new URI(null, null, "/5-12-145-35_s-81", 443, null, null, null))uscite: ///5-12-145-35_s-81:443. Lo sto dando come nome host.
Eugen Covaci,

Questo comportamento (quando il nome host è assoluto) è strano, per non dire altro. Il costruttore dell'URI sta fornendo un nome host e una porta e l'URI risultante non ha né uno, né un percorso.
Eugen Covaci,

5

Il bug non è in Java ma nella denominazione dell'host, poiché un carattere di sottolineatura non è un carattere valido in un nome host. Sebbene ampiamente utilizzato in modo errato, Java rifiuta di gestire tali nomi host


Questo /5-12-145-35_s-81:443è legale.
Eugen Covaci,

2

I trattini bassi non sono supportati negli URI.

Mentre un nome host non può contenere altri caratteri, come il carattere di sottolineatura (_), altri nomi DNS possono contenere il carattere di sottolineatura. [5] [6] Questa limitazione è stata revocata da RFC 2181, Sezione 11. Sistemi come DomainKeys e record di servizio utilizzano il carattere di sottolineatura come mezzo per assicurare che il loro carattere speciale non sia confuso con i nomi host. Ad esempio, _http._sctp.www.example.com specifica un puntatore di servizio per un host web server (www) con funzionalità SCTP nel dominio example.com. Nonostante lo standard, Chrome, Firefox, Internet Explorer, Edge e Safari consentono i caratteri di sottolineatura nei nomi host, sebbene i cookie in IE non funzionino correttamente se una parte del nome host contiene un carattere di sottolineatura

Wikipedia

Da Javadocs:

URI pubblico (String str) genera URISyntaxException Genera: URISyntaxException - Se la stringa specificata viola RFC 2396, come aumentato dalle deviazioni precedenti

javadocs

(Hacky) Soluzione:

    URI url = URI.create("https://5-12-145-35_s-8:8080");

    System.out.println(url.getHost()) // null

    if (url.getHost() == null) {
        final Field hostField = URI.class.getDeclaredField("host");
        hostField.setAccessible(true);
        hostField.set(url, "5-12-145-35_s-81");
    }
    System.out.println(url.getHost()); // 5-12-145-35_s-81

Questo è stato segnalato come - bug JDK


1
Caspita, questa è una soluzione confusa. Si può affermare che ciò potrebbe interrompersi in futuro, dato che sta assumendo internals su una classe interna e utilizza la riflessione per accedervi direttamente. Quindi l'implementazione potrebbe cambiare con qualsiasi versione di Java, nel qual caso ciò potrebbe interrompersi. +1 per fornire una soluzione però.
Zabuzard,

Per quanto volessi rimediare a questa soluzione alternativa, il problema con queste cose è proprio quello di cui parla Zabuza. + Se iniziamo a obbedire alle regole tutto inizierà lentamente a collassare. C'è una buona ragione per cui questo non funziona in primo luogo.
salesh,

@salesh E qual è quella buona ragione?
fg78nc,

"I sistemi come DomainKeys e i record di servizio utilizzano il carattere di sottolineatura come mezzo per assicurare che il loro carattere speciale non sia confuso con i nomi host." wikipedia e qui c'è una buona risposta quora
salesh,

1
Se lo fai otterrai nullcome host.
fg78nc,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.