MasterYodaの昼下がり

日々の備忘録的なアレ

androidでホスト名に_(アンダースコア)が入っていると通信に失敗する

タイトルの通りandroidでホスト名に_(アンダースコア)が入っていると通信に失敗する。
同じホストに対しiosで通信を試みたところ問題は発生しなかった。

通信失敗時のスタックトレース

E/AndroidRuntime(1278):Causedby: java.lang.NullPointerException
E
/AndroidRuntime(1278):>---at libcore.net.http.HttpConnection$Address.hashCode(HttpConnection.java:343)
E
/AndroidRuntime(1278):>---at java.util.HashMap.get(HashMap.java:298)
E
/AndroidRuntime(1278):>---at libcore.net.http.HttpConnectionPool.get(HttpConnectionPool.java:67)
E
/AndroidRuntime(1278):>---at libcore.net.http.HttpConnection.connect(HttpConnection.java:128)
E
/AndroidRuntime(1278):>---at libcore.net.http.HttpEngine.openSocketConnection(HttpEngine.java:308)
E
/AndroidRuntime(1278):>---at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:460)
E
/AndroidRuntime(1278):>---at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:432)
E
/AndroidRuntime(1278):>---at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:282)
E
/AndroidRuntime(1278):>---at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:232)
E
/AndroidRuntime(1278):>---at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:273)
E
/AndroidRuntime(1278):>---at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:479)
E
/AndroidRuntime(1278):>---at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:133)

コードから原因を追っていったところ、スタックトレースにも出ているとおり
libcore.net.http.HttpConnection$Address.hashCodeメソッド内の
uriHost.hashCode()NullPointerExceptionが発生していた。

uriHostjava.net.URIクラスのgetHostメソッドの結果が格納されている。
java.net.URIクラスはRFC2396に準拠しており、ホスト名に使用する文字は以下のように定義されている。

RFC2396
3.2.2.Server-based NamingAuthority

hostport
= host [":" port ]
host
= hostname |IPv4address
hostname
=*( domainlabel ".") toplabel ["."]
domainlabel
= alphanum | alphanum *( alphanum |"-") alphanum
toplabel
= alpha | alpha *( alphanum |"-") alphanum

上記のようにホスト名として定義されてる文字として_(アンダースコア)は定義されておらず、
ライブラリの実装によっては問題を引き起こす模様/(^o^)\。

今回の事象の場合、ホスト名に_(アンダースコア)が入っているとjava.net.URI.getHost()の返り値がnullになってしまう。
という予想が立ったので以下のテストコードで挙動を確認。

・テストコード
URLは仮のもの

package test;

import java.net.URI;
import java.net.URISyntaxException;

public class UriWithUnderScoreTest {

/**
* @param args
* @throws URISyntaxException
*/

public static void main(String[] args) throws URISyntaxException {
// TODO Auto-generated method stub

String uri_underscore ="http://api_dev.hogehoge.net/player/get";
System.out.println("uri="+ uri_underscore);
System.out.println("URI.getHost()="+new URI(uri_underscore).getHost());

String uri_hyphen ="http://api-dev.hogehoge/player/get";
System.out.println("uri="+ uri_hyphen);
System.out.println("URI.getHost()="+new URI(uri_hyphen).getHost());
}

}

・結果

uri=http://api_dev.hogehoge.net/player/get
URI
.getHost()=null
uri
=http://api-dev.hogehoge.net/player/get
URI
.getHost()=api-dev.hogehoge.net

結果に出力されたとおり、ホスト名に_(アンダースコア)が入っているとnullが返り、
_(アンダースコア)を-(ハイフン)に置き換えたところ期待どおりの結果が返ってくる。