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スキームが指定されていません。nullです。
Eugen Covaci

URLに_が必要な場合は、@ fg78ncの回避策が役立ちます。ホスト名が無効になり、フィールドが作成されないため、/を使用しないでください
salesh

3
RFC-2396セクション3.2.2を参照してください。URIのホスト名は、-ドットで区切られた英数字+の1つ以上のグループのみにすることができます
Mark Rotteveel

@MarkRotteveel java.net.URIが最新の仕様で最新ではない
fg78nc

@ fg78nc RFC-3986では緩和されていますが、「DNSでのルックアップを目的とした登録名は、[RFC1034]のセクション3.5および[RFC1123]のセクション2.1で定義された構文を使用する」と述べています。、そしてそれは基本的にRFC-2396セクション3.2.2の構文です。
Mark Rotteveel

回答:


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ます。

最初は、それはホストポートであり、解析に失敗します。
2番目の場合、権限部分は空で/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許可されているのでしょうか。唯一の違いは、この1つは、相対的な絶対的ではないということである
オイゲンCovaci

System.out.println( new URI(null, null, "/5-12-145-35_s-81", 443, null, null, null))出力:///5-12-145-35_s-81:443。ホスト名として指定しています。
Eugen Covaci

控えめに言っても、この動作(ホスト名が絶対の場合)は奇妙です。URIのコンストラクターはホスト名とポートを指定しており、結果のURIにはパスが1つもありません。
Eugen Covaci

5

下線はホスト名で有効な文字ではないため、このバグはJavaではなく、ホストの命名にあります。広く使用されていますが、Javaはそのようなホスト名の処理を拒否しています


これ/5-12-145-35_s-81:443は合法です。
Eugen Covaci

2

アンダースコアはURIではサポートされていません。

ホスト名にはアンダースコア文字(_)などの他の文字を含めることはできませんが、他のDNS名にはアンダースコアを含めることができます。[5] [6] この制限はRFC 2181、セクション11で解除されました。DomainKeysやサービスレコードなどのシステムは、アンダースコアを使用して、特殊文字がホスト名と混同されないようにします。たとえば、_http._sctp.www.example.comは、example.comドメインのSCTP対応のWebサーバーホスト(www)のサービスポインターを指定します。標準にかかわらず、Chrome、Firefox、Internet Explorer、Edge、およびSafariでは、ホスト名にアンダースコアを使用できますが、ホスト名の一部にアンダースコア文字が含まれている場合、IEのCookieは正しく機能しません

ウィキペディア

Javadocsから:

public URI(String str)はURISyntaxExceptionをスローしますスロー: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 。
ザブザード

私がしなかったこの回避策をしたかったのと同じように、これらの問題はZabuzaが言及したものにすぎません。+ルールを守り始めると、すべてがゆっくりと崩壊し始めます。これが最初からうまくいかないのには十分な理由があります。
販売

@saleshその正当な理由は何ですか?
fg78nc

「DomainKeysやサービスレコードなどのシステムでは、アンダースコアを使用して、特殊文字がホスト名と混同されないようにします。」 ウィキペディア、ここで良い答えがありますquora
salesh

1
それを行うとnull、ホストとして取得します。
fg78nc
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.