HttpEntity中のInputStreamについて

DefaultHttpClient を使ってpostをするとき、
HttpPostでリクエストを作り,HttpPost.setEntityでリクエストパラメータを仕込む
大雑把には下記のようになる

 File file = new File(path);
 HttpPost request = new HttpPost();
 request.setEntity(new InputStreamEntity(new FileInputStream(file)));
 DefaultHttpClient client = new DefaultHttpClient();
 HttpResponse response = client.execute(request);

普通に考えると、
この時仕込んだInputStreamを使用後にcloseしなくてはいけないが、
DefaultHttpClientの使用例を調べた際、closeしている記述が見当たらなかった。
ひょっとしてexecute内でcloseしてくれているのかと思ったが,そのような説明もなかったので、
本当に必要か、コードを追って見てみた。

今振り返ると、実際にcloseせずに大量にFileInputStreamを作ってexecuteしてみるのが
手っ取り早いし確実な確認方法だったと思う。
結論を言えばやはりcloseは必要なようだ。

DefaultHttpClient.executeをたどると、

DefaultHttpClient.execute → AbstractHttpClient.execute →
DefaultRequestDirector.execute →
DefaultRequestDirector.tryExecute
HttpRequestExecutor.execute→
HttpRequestExecutor.doSendRequest→
HttpClientConnection.sendRequestEntity;

と、sendRequestEntityに行き着く。DefaultRequestDirector.executeが、
コネクションを開いて,sendし、receiveし、redirect等の処理をしている実態のようだった。
このDefaultRequestDirector.executeや他のメソッドを眺めてみたが、
リクエストのentityについてconsumeしている処理は見当たらなかった。

HttpClientConnectionは、

DefaultHttpClient→
SingleClientConnManager(いくつかあるようだが今回はこれを辿った)→
DefaultClientConnectionOperator→
DefaultClientConnection→
AbstractHttpClientConnection

とたどっていくと、AbstractHttpClientConnectionがその実態であることが分かる
AbstractHttpClientConnection.sendRequestEntityをさらに辿ると、

AbstractHttpClientConnection.sendRequestEntity→
EntitySerializer.serialie→
HttpEntity.writeTo

となって、ようやくInputStream.readをよんでいるメソッドに行き着いた

ここまでで InputStream の close をしているような箇所は出会わず、
HttpEntityの実態であるInputStreamEntityのwriteToではJavaDocにあるようにcloseはしていない。

というわけで、やはりInputStreamのcloseは必要で,上記例では、下記のようなものを書く必要がある

 File file = new File(path);
 HttpPost request = new HttpPost();
 request.setEntity(new InputStreamEntity(new FileInputStream(file)));
 DefaultHttpClient client = new DefaultHttpClient();
 HttpResponse response = client.execute(request);
 request.getEntity().getContent().close();

ちなみに、HttpEntity.consumeContent は depriciated であり,
InputStreamをとりだして、直接 close することが推奨されている
直接が推奨されているが、DefaultRequestDirector.execute をみると、
再利用するresponseをクリアする際には,EntityUtils.consumeを使っていることが分かる。
EntityUtilsには、Entity操作でよく利用する処理が入っているようで、
おそらくこのユーティリティの利用が望ましいのだろう。

と思ったら,HttpCore 4.1 APIJavaDoc には、EntitiyUtils.consume が載っているのだが,
Android Developers の JavaDoc には EntitiyUtils.consume が載っておらず、
Eclipseで確認した限りでは実装もされていないようだった。
結局Androidでは自前で書くことになりそうだ。

これだけではただの覚書になってしまうが、この件についてはここまでにする。