先日はHTTP_STATUS=302が戻るサーバへの対処とリダイレクト処理に言及したが、今日別なサーバに接続してみた所、今度は接続直後の処理が処理がおかしい。
今回の問題が再現するのはBASIC認証が必要なサイトへの接続だ。
URL url = new URL("http://hogehost/require/badicAuth");
URLConnection con = url.openConnection();
con.setDoInput(true);
con.setDoOutput(true);
con.setConnectTimeout(30000) ;
conn.connect();
int http_status = conn.getResponseCode();
http_statusの戻りを判定してその後の処理(301, 401, etc)に移りたいのだが、実際にはhttp_statusの値が初期値の-1のままであり、更にはNullPointerExceptionがスローされしまう。
ならばとヘッダから同ステータスを取得しようと
int http_status = Integer.parseInt(httpcon.getHeaderField("StatusCode"));
これでも結果は同じ。
期待するHTTP_STATUSは当然ながら401なのだがどうしてこんなことになってしまうんだろう。
実装クラスである、org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnection.javaを調べてみたのだが、401(HTTP_UNAUTHORIZED)以降、内部disconnect()メソッドで接続を一端切っており、その後内部ストリームを閉じてクリアしてしまっているため、ストリームの取得に失敗しているらしい。
public int getResponseCode() throws IOException {
// Response Code Sample : "HTTP/1.0 200 OK"
// Call connect() first since getHeaderField() doesn't return exceptions
connect();
doRequest();:
:
:
void doRequestInternal() throws IOException {
int redirect = 0;
while (true) {
:
:
// HTTP authorization failed ?
if (responseCode == HTTP_UNAUTHORIZED) {
// keep asking for username/password until authorized
String challenge = resHeader.get("WWW-Authenticate"); //$NON-NLS-1$
if (challenge == null) {
// KA018=Received authentication challenge is null
throw new IOException(Msg.getString("KA018")); //$NON-NLS-1$
}
// drop everything and reconnect, might not be required for
// HTTP/1.1
endRequest(); ← HTTP_UNAUTHORIZED(401)だったら、
disconnect(); ← それまでのコネクションを切断してしまう :
:
private synchronized void disconnect(boolean closeSocket) {
if (connection != null) {
:
:
connection.closeSocketAndStreams();
} else {
HttpConnectionManager.getDefault().returnConnectionToPool(
connection);
}
connection = null; ←
}
}
:
:
String readln() throws IOException {
boolean lastCr = false;
StringBuffer result = new StringBuffer(80);
int c = is.read(); ← ぬるぽ :
:
}
どうやらバグのようだ。
HttpURLConnection.getResponseCode() returns -1 on second invocation - Stack Overflow
HttpURLConnection getResponseCode - Android Developers Google グループ
内部で使用されているのは知りつつも、依存してはいけないと避けていたのだが、やはりHttpClientを使えということなのかな。