2011年10月28日金曜日

JavaのServletでFirefoxのダウンロード再開機能に対応する方法

仕事で、ダウンロード途中にネットが切れたりした場合に、ダウンロード途中のファイルを、また1からダウンロードするのはしんどい、っていう要件があった。

しんどいだけじゃなくて、回線の都合で何回やってもダウンロード終わらないんだよねって。

そんなときに、Firefoxのダウンロード再開機能に対応できるように、サーバー側でコーディングすれば、ダウンロード途中にネットが切れても途中から再開してくれるらしい。

そのために、Servletでどのようなリクエスト、レスポンスの実装をすれば良いのか調べたので、メモしておく。




ポイントは、3つある。

1つ目は、レスポンスヘッダーに「Accept-Ranges: bytes」をセットする。

初回のダウンロードリクエストのレスポンスヘッダーに、「Accept-Ranges: bytes」をセットする。

Firefoxなどダウンロードをリクエストしたクライアント側で、このレスポンスヘッダーを取得できたら、「ああ。このサーバーはレジューム機能を実装してあるんだな。よしやってやんよ。」って理解してくれる。

つまり、サーバー「おれ、ダウンロード再開してもらっても対応できますよ」って言うってこと。


ポイントの2つ目は、リクエストヘッダーに、「Range」が含まれている場合は、途中から返すように実装する。

クライアントは、ダウンロードを途中から再開して欲しいときに、サーバー側にリクエストを投げる際に、「Range」というリクエストヘッダーを渡してくる。

この「Range」は、 こないだ話題になったApache Killer が攻撃する際に利用していたリクエストヘッダーだ。

「Range」には、「どっから-どこまで」を返してねー。といった値が設定されている。

例えば、「Range: bytes=0-499」といった感じでセットされている。

これは、

「bytes」で、「0」から「499」までの、計500バイトを返してねー。

という意味になる。

サーバー側では、request.getHeader("Range") で取り出した値を、解析して

「言われたとおりに返しますけどなにか?」

的な動きを実装してやらないとあかん。


で、最後のポイントは、再開レスポンスヘッダーは色々したらなあかん。

いろいろっていうのは、次の3つ。


  • レスポンスのステータスは、206
  • Content-Lengthは、今から返すファイルのサイズ
  • Content-Rangeというレスポンスヘッダーを用意して、「bytes こっから-ここまで/全体の」って値をセットする


コードは、こんな感じ


response.setStatus(206);
response.setHeader("Content-Length", String.valueOf(fileSize-offset));
response.setHeader("Content-Range", "bytes " + offset + "-" + (fileSize -offset - 1L) + "/" + fileSize);


雑感

一応、以上のポイントをおさえて、こまごまと実装してやれば、Firefoxでダウンロードを中断して再開したら、途中から返して、きちんとダウンロード最後まで出来た。

今回は調べる時間があまりなかったので、とりあえずやっつけ実装をしたが、きちんと理解したわけではない。

なんか、HTTPの仕様だかApacheの仕様だかをきちんと理解した上で実装してやれば、まあ大概のレジューム機能付きダウンローダーに対応できるとかなんとか。。。

またそのうち勉強しよう。