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 API の JavaDoc には、EntitiyUtils.consume が載っているのだが,
Android Developers の JavaDoc には EntitiyUtils.consume が載っておらず、
Eclipseで確認した限りでは実装もされていないようだった。
結局Androidでは自前で書くことになりそうだ。
これだけではただの覚書になってしまうが、この件についてはここまでにする。