仕事で、ダウンロード途中にネットが切れたりした場合に、ダウンロード途中のファイルを、また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の仕様だかをきちんと理解した上で実装してやれば、まあ大概のレジューム機能付きダウンローダーに対応できるとかなんとか。。。
またそのうち勉強しよう。