Mengapa nama host dinyatakan tidak valid saat membuat URI

17

Menjalankan kode ini dengan 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();
}

mengakibatkan kesalahan ini: java.net.URISyntaxException: Illegal character in hostname at index 13: //5-12-145-35_s-81:443

Dari mana asal kesalahan ini, mengingat semua karakter nama host tampak sah, menurut Jenis karakter URI ?


Jika saya menggunakan URL ini: //5-12-145-35_s-81:443atau /5-12-145-35_s-81:443kesalahan hilang.


Dari komentar, saya mengerti bahwa, menurut RFC-2396 , nama host tidak dapat berisi karakter garis bawah.

Pertanyaan yang masih ada adalah mengapa nama host yang dimulai dengan slash atau double slash diizinkan berisi garis bawah?

Eugen Covaci
sumber
1
@ernest_k Skema tidak diberikan, ini nol.
Eugen Covaci
jika Anda masih ingin _ dalam url @ fg78nc solusi akan bekerja untuk Anda. Jangan gunakan / karena nama host akan tidak valid dan tidak akan membuat bidang
salesh
3
Lihat RFC-2396 bagian 3.2.2. Nama inang dalam URI hanya dapat satu atau lebih grup alfanumerik + -, dipisahkan dengan titik
Mark Rotteveel
@MarkRotteveel java.net.URI tidak up to date dengan spesifikasi terbaru
fg78nc
@ fg78nc Meskipun RFC-3986 melonggarkannya, masih menyebutkan bahwa "Nama terdaftar yang dimaksudkan untuk pencarian di DNS menggunakan sintaksis yang didefinisikan dalam Bagian 3.5 dari [RFC1034] dan Bagian 2.1 dari [RFC1123]." , dan itu pada dasarnya adalah sintaks RFC-2396 bagian 3.2.2.
Mark Rotteveel

Jawaban:

8

Nama host harus cocok dengan sintaks berikut:

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

Seperti yang Anda lihat, hanya .dan -diizinkan, _tidak.


Anda kemudian mengatakan bahwa //5-12-145-35_s-81:443itu diperbolehkan, dan memang demikian, tetapi tidak untuk nama host .

Untuk melihat bagaimana hasilnya:

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

Keluaran

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

Seperti yang Anda lihat, ketika authoritymemiliki nama host yang valid, hostdan portdiuraikan, tetapi ketika tidak valid, authoritydiperlakukan sebagai teks bentuk bebas, dan tidak diuraikan lebih lanjut.


MEMPERBARUI

Dari komentar:

System.out.println( new URI(null, null, "/5-12-145-35_s-81", 443, null, null, null))output: /// 5-12-145-35_s-81: 443. Saya memberikannya sebagai nama host

The URIkonstruktor Anda panggil sedang adalah metode kenyamanan, dan sederhana membangun URI tali penuh dan kemudian mem-parsing itu.

Passing "5-12-145-35_s-81", 443menjadi //5-12-145-35_s-81:443.
Passing "/5-12-145-35_s-81", 443menjadi ///5-12-145-35_s-81:443.

Yang pertama, ini adalah host dan port , dan gagal mengurai.
Pada bagian kedua bagian otoritas kosong, dan /5-12-145-35_s-81:443merupakan jalan .

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

Keluaran

uri = ///5-12-145-35_s-81:443
  authority = null
  host = null
  port = -1
  path = /5-12-145-35_s-81:443
Andreas
sumber
Sekarang saya mengerti, tetapi mengapa, katakanlah /a_b, diizinkan. Satu-satunya perbedaan adalah bahwa ini mutlak, bukan relatif
Eugen Covaci
System.out.println( new URI(null, null, "/5-12-145-35_s-81", 443, null, null, null))output: ///5-12-145-35_s-81:443. Saya memberikannya sebagai nama host.
Eugen Covaci
Perilaku ini (ketika nama host mutlak) aneh, untuk sedikitnya. Konstruktor URI memberikan nama host dan port, dan URI yang dihasilkan tidak memiliki satu pun, hanya jalur.
Eugen Covaci
5

Bug ini bukan di Jawa tetapi dalam penamaan host, karena garis bawah bukan karakter yang valid dalam nama host. Meskipun banyak digunakan secara tidak benar, Java menolak untuk menangani nama host tersebut

salesh
sumber
Yang /5-12-145-35_s-81:443ini legal.
Eugen Covaci
2

Garis bawah tidak didukung di URI.

Meskipun nama host mungkin tidak mengandung karakter lain, seperti karakter garis bawah (_), nama DNS lain mungkin berisi garis bawah. [5] [6] Pembatasan ini dicabut oleh RFC 2181, Bagian 11. Sistem seperti DomainKeys dan catatan layanan menggunakan garis bawah sebagai sarana untuk memastikan bahwa karakter khusus mereka tidak bingung dengan nama host. Misalnya, _http._sctp.www.example.com menetapkan pointer layanan untuk host server web berkemampuan SCTP (www) di domain example.com. Meskipun standar, Chrome, Firefox, Internet Explorer, Edge dan Safari memungkinkan menggarisbawahi dalam nama host, meskipun cookie di IE tidak berfungsi dengan benar jika ada bagian dari nama host yang berisi karakter garis bawah

Wikipedia

Dari Javadocs:

public URI (String str) melempar URISyntaxException Throws: URISyntaxException - Jika string yang diberikan melanggar RFC 2396, sebagaimana ditambah oleh penyimpangan di atas

Javadocs

Solusi (Meretas):

    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

Ini dilaporkan sebagai - JDK bug

fg78nc
sumber
1
Wow, itu solusi hacky. Anda dapat menyatakan bahwa ini mungkin pecah di masa depan, karena mengasumsikan internal tentang kelas internal dan menggunakan refleksi untuk mengaksesnya secara langsung. Jadi implementasinya mungkin berubah dengan rilis Java apa pun, dalam hal ini ini bisa pecah. +1 untuk memberikan solusi .
Zabuzard
Sebanyak yang saya inginkan untuk menyelesaikan masalah ini, saya tidak melakukannya, masalah dengan hal-hal ini adalah apa yang Zabuza sebutkan. + Jika kita mulai mematuhi aturan, semuanya akan mulai perlahan runtuh. Ada alasan bagus mengapa ini tidak berhasil.
salesh
@salesh Dan apa alasan bagus itu?
fg78nc
"Sistem seperti DomainKeys dan catatan layanan menggunakan garis bawah sebagai sarana untuk memastikan bahwa karakter khusus mereka tidak bingung dengan nama host." wikipedia dan ada jawaban yang bagus di sini quora
salesh
1
Jika Anda melakukannya, Anda akan mendapatkan nullsebagai tuan rumah.
fg78nc