Чому ім’я хоста визнано недійсним під час створення URI


17

Запуск цього коду за допомогою 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();
}

призводить до цієї помилки: java.net.URISyntaxException: Illegal character in hostname at index 13: //5-12-145-35_s-81:443

Звідки ця помилка, зважаючи на те, що всі символи імені хоста здаються законними, відповідно до типів символів URI ?


Якщо я використовую ці URL-адреси: //5-12-145-35_s-81:443або /5-12-145-35_s-81:443помилка зникла.


З коментарів я розумію, що відповідно до RFC-2396 , ім'я хоста не може містити символів підкреслення.

Питання, яке все ще має місце, полягає в тому, чому ім'я хоста, що починається з косою або подвійною косою рисою, може містити підкреслення?


1
@ernest_k Схема не задана, вона є нульовою.
Євген Коваці

якщо ви все ще хочете _ у URL-адресі @ fg78nc, вирішення буде працювати для вас. Не використовуйте / тому, що ім'я хоста буде недійсним і не створюватиме поле
продаж

3
Див. Розділ 3.2.2 RFC-2396 . Іменем хоста в URI може бути лише одна або декілька буквено-цифрових груп -, розділених крапками
Mark Rotteveel

@MarkRotteveel java.net.URI не в курсі останніх специфікацій
fg78nc

@ fg78nc Хоча RFC-3986 розслабляє це, він все ще згадує, що "Зареєстроване ім'я, призначене для пошуку в DNS, використовує синтаксис, визначений у розділі 3.5 [RFC1034] та в розділі 2.1 [RFC1123]". , і це в основному синтаксис RFC-2396 розділу 3.2.2.
Марк Ротвевель

Відповіді:


8

Ім'я хоста повинно відповідати такому синтаксису:

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

Як бачите, тільки .і -дозволено, _це не так.


Потім ви говорите, що //5-12-145-35_s-81:443це дозволено, і це так, але не для імені хоста .

Щоб побачити, як це можна зробити:

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

Вихідні дані

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

Як ви бачите, коли authorityмає дійсне ім'я хоста, то hostі portаналізуються, але коли не є дійсним, цей authorityтекст розглядається як текст вільної форми і далі не розбирається.


ОНОВЛЕННЯ

З коментаря:

System.out.println( new URI(null, null, "/5-12-145-35_s-81", 443, null, null, null))виходи: /// 5-12-145-35_s-81: 443. Я даю це ім'я хоста

URIКонструктор ви викликаєте зручний метод, і він просто будує повну рядок URI , а потім розбирає це.

Проходження "5-12-145-35_s-81", 443стає //5-12-145-35_s-81:443.
Проходження "/5-12-145-35_s-81", 443стає ///5-12-145-35_s-81:443.

По-перше, це хост і порт , і не вдається проаналізувати.
У другій авторитетна частина порожня, і /5-12-145-35_s-81:443це шлях .

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

Вихідні дані

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

Тепер я розумію, але чому, скажімо /a_b, дозволено. Різниця лише в тому, що ця абсолютна, а не відносна
Євген Коваці

System.out.println( new URI(null, null, "/5-12-145-35_s-81", 443, null, null, null))виходи: ///5-12-145-35_s-81:443. Я даю це ім'я хоста.
Євген Коваці

Така поведінка (коли ім'я хоста абсолютно), як мінімум, дивно. Конструктор URI вказує ім'я хоста та порт, а отриманий URI не має жодного, а лише шлях.
Євген Коваці

5

Помилка не в Java, а в іменуванні хоста, оскільки підкреслення не є дійсним символом в імені хоста. Хоча широко використовується неправильно, Java відмовляється обробляти такі імена хостів


Цей /5-12-145-35_s-81:443законний.
Євген Коваці

2

Підкреслення не підтримуються в URI.

Хоча ім'я хоста може не містити інших символів, таких як символ підкреслення (_), інші імена DNS можуть містити підкреслення. [5] [6] Це обмеження було знято розділом 11. RFC 2181. Такі системи, як DomainKeys та службові записи, використовують підкреслення як засіб гарантувати, що їх особливий характер не плутається з іменами хостів. Наприклад, _http._sctp.www.example.com вказує службовий вказівник для хоста веб-сервера для веб-сервера (www) у домені example.com. Незважаючи на стандарт, Chrome, Firefox, Internet Explorer, Edge та Safari дозволяють підкреслити імена хостів, хоча файли cookie в IE працюють неправильно, якщо будь-яка частина імені хоста містить символ підкреслення

Вікіпедія

Від Javadocs:

public URI (String str) кидає URISyntaxException Throw: URISyntaxException - Якщо дана рядок порушує RFC 2396, доповнені вищезазначеними відхиленнями

Javadocs

(Хекі) Рішення:

    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

Про це повідомлялося як - помилка JDK


1
Нічого собі, це хакітне рішення. Ви можете стверджувати, що це може зламатися в майбутньому, оскільки воно передбачає внутрішній клас про внутрішній клас і використовує роздуми для доступу до нього безпосередньо. Таким чином, реалізація може змінитися з будь-яким випуском Java, і в цьому випадку це може зламатись. Хоча +1 для надання рішення .
Забузар

Скільки б я хотів вирішити цей спосіб, який я цього не зробив, проблема цих речей - саме те, що згадує Забуза. + Якщо ми почнемо виконувати правила, все почне повільно руйнуватися. Є вагома причина, чому це не працює в першу чергу.
продаж

@salesh І що це за причина?
fg78nc

"Такі системи, як DomainKeys і службові записи, використовують підкреслення як засіб, щоб переконатися, що їх особливий характер не плутають з іменами хостів." Вікіпедія, і тут хороша відповідь квора
продаж

1
Якщо ви це зробите, ви отримаєте nullяк господар.
fg78nc
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.