ファイルダウンロード時のファイル名の破損(IE)
-
03-07-2019 - |
質問
単純なファイルのアップロードとダウンロードのメカニズムを実装しました。ユーザーがファイル名をクリックすると、次のHTTPヘッダーでファイルがダウンロードされます。
HTTP/1.1 200 OK
Date: Tue, 30 Sep 2008 14:00:39 GMT
Server: Microsoft-IIS/6.0
Content-Disposition: attachment; filename=filename.doc;
Content-Type: application/octet-stream
Content-Length: 10754
日本語のファイル名もサポートしています。そのために、次のjavaメソッドでファイル名をエンコードします。
private String encodeFileName(String name) throws Exception{
String agent = request.getHeader("USER-AGENT");
if(agent != null && agent.indexOf("MSIE") != -1){ // is IE
StringBuffer res = new StringBuffer();
char[] chArr = name.toCharArray();
for(int j = 0; j < chArr.length; j++){
if(chArr[j] < 128){ // plain ASCII char
if (chArr[j] == '.' && j != name.lastIndexOf("."))
res.append("%2E");
else
res.append(chArr[j]);
}
else{ // non-ASCII char
byte[] byteArr = name.substring(j, j + 1).getBytes("UTF8");
for(int i = 0; i < byteArr.length; i++){
// byte must be converted to unsigned int
res.append("%").append(Integer.toHexString((byteArr[i]) & 0xFF));
}
}
}
return res.toString();
}
// Firefox/Mozilla
return MimeUtility.encodeText(name, "UTF8", "B");
}
これまでのところ、長いファイル名ではうまく機能しないことが判明するまで、うまく機能していました。例:&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354; &#12354;&#12354;&#12354;&#12354; 2008.10.1&#12354; .doc
。シングルバイトのドットの1つをシングルバイトの下線に変更した場合、または最初の文字を削除した場合、問題なく動作します。つまり、ドット文字の長さとURLエンコードに依存します。
以下にいくつかの例を示します。
これは壊れています(&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354; &#12354;&#12354;&#12354;&#12354;&#12354; 2008.10.1&#12354; .doc
):
Content-Disposition: attachment; filename=%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%822008%2E10%2E1%e3%81%82.doc;
これは問題ありません(&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354; &#12354;&#12354;&#12354;&#12354;&#12354; 2008_10.1&#12354; .doc
):
Content-Disposition: attachment; filename=%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%822008_10%2E1%e3%81%82.doc;
これも問題ありません(&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354;&#12354; ;&#12354;&#12354;&#12354;&#12354;&#12354; 2008.10.1&#12354; .doc
):
Content-Disposition: attachment; filename=%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%82%e3%81%822008%2E10%2E1%e3%81%82.doc;
誰にも手がかりがありますか?
解決
gmailは、ファイル名のエスケープを多少異なる方法で処理します。ファイル名は引用符で囲まれ(二重引用符)、1バイトのピリオドはURLエスケープされません。 このように、質問の長いファイル名は問題ありません。
Content-Disposition: attachment; filename="%E3%81%82%E3%81%82%E3%81%82%E3%81%82%E3%81%82%E3%81%82%E3%81%82%E3%81%82%E3%81%82%E3%81%82%E3%81%82%E3%81%82%E3%81%82%E3%81%82%E3%81%822008.10.1%E3%81%82.doc"
ただし、ファイル名のバイト長には制限があります(明らかにIEのみ)(バグだと思います)。そのため、ファイル名が1バイト文字のみで構成されている場合でも、ファイル名の先頭は切り捨てられます。 制限は約160バイトです。
他のヒント
前述のように、Content-DispositionとUnicodeは、ブラウザーのスニッフィングとそれぞれに異なるヘッダーを返すことなく、すべてのメインブラウザーを動作させることは不可能です。
私の解決策は、Content-Dispositionヘッダーを完全に回避し、URLの末尾にファイル名を追加して、ブラウザにファイルを直接取得していると思わせるようにすることでした。例:
http://www.xyz.com/cgi-bin/dynamic.php/あああああああああああああああ2008.10.1あ.doc
これは、リンクを作成するときにファイル名を知っていることを当然前提としていますが、クイックリダイレクトヘッダーはオンデマンドで設定できます。
ここでの主な問題は、IEが関連するRFCをサポートしていないことです。RFC2231。 ポインターとテストケースをご覧ください。さらに、IEで使用する回避策(パーセントエスケープされたUTF-8を使用するだけ)には、いくつかの追加の問題があります。それはすべてのロケールで動作しない可能性があります(覚えている限り、韓国ではIEは常にデフォルトではないURLでUTF-8を使用するように設定されていない限りメソッドは失敗します)、そして前述のように、長さの制限があります(I それはIE8で修正されたと聞きましたが、まだ試していませんでした。
この問題はIE8で修正されたと思います。IE8で動作するのを見てきました。