6

私が扱っているいくつかのレガシー コードがあります (したがって、エンコードされたファイル名コンポーネントを含む URL を使用することはできません)。これにより、ユーザーは Web サイトからファイルをダウンロードできます。多くの場合、ファイル名はさまざまな言語で使用されるため、すべて UTF-8 として保存されます。適切な filename* パラメータへの RFC5987 変換を処理するコードをいくつか書きました。これは、ファイル名に非ASCII文字が含まれるまでうまく機能しスペース。RFC によると、スペース文字は attr_char の一部ではないため、%20 としてエンコードされます。Chrome と Firefox の新しいバージョンを使用していますが、それらはすべてダウンロード時に %20 から + に変換されています。スペースをエンコードせず、エンコードされたファイル名を引用符で囲んでみましたが、同じ結果が得られました。サーバーからの応答を盗聴して、サーブレット コンテナーがヘッダーをいじっていないこと、およびヘッダーが正しいように見えることを確認しました。RFC には、%20 を含む例もあります。何か足りないものがありますか、それともこれらのブラウザのすべてにこれに関連するバグがありますか?

よろしくお願いします。ファイル名をエンコードするために使用するコードは以下のとおりです。

ピーター

public static boolean bcsrch(final char[] chars, final char c) {
    final int len = chars.length;
    int base = 0;
    int last = len - 1; /* Last element in table */
    int p;

    while (last >= base) {
        p = base + ((last - base) >> 1);

        if (c == chars[p])
            return true; /* Key found */
        else if (c < chars[p])
            last = p - 1;
        else
            base = p + 1;
    }

    return false; /* Key not found */
}

public static String rfc5987_encode(final String s) {
    final int len = s.length();
    final StringBuilder sb = new StringBuilder(len << 1);
    final char[] digits = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    final char[] attr_char = {'!','#','$','&','\'','+','-','.','0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','^','_','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','|', '~'};
    for (int i = 0; i < len; ++i) {
        final char c = s.charAt(i);
        if (bcsrch(attr_char, c))
            sb.append(c);
        else {
            final char[] encoded = {'%', 0, 0};
            encoded[1] = digits[0x0f & (c >>> 4)];
            encoded[2] = digits[c & 0x0f];
            sb.append(encoded);
        }
    }

    return sb.toString();
}

アップデート

これは、私のコメントで述べたように、スペースを含む漢字を含むファイルに対して取得したダウンロード ダイアログのスクリーン ショットです。

ダウンロード ダイアログのスクリーン キャップ

4

1 に答える 1

13

Julian がコメントで指摘したように、私は初歩的な Java エラーを犯し、文字からバイトへの変換を行うのを忘れていました (したがって、文字のバイト表現ではなく文字のコードポイントをエンコードしました)。そのため、エンコーディングは完全に正しくありませんでした。これは、RFC 5987 の要件として明確に記載されています。変換を行うための修正済みコードを投稿します。エンコーディングが正しくなると、filename* パラメータがブラウザによって正しく認識され、ダウンロードに使用されるファイル名が正しくなります。

以下は、文字列の UTF-8 バイトで動作する修正されたエスケープ コードです。問題を起こしていたファイル名は、適切にエンコードされて次のようになります。

Content-Disposition:添付ファイル; filename*=UTF-8''ミュージアム%20%E5%8D%9A%E7%89%A9%E9%A6%86.jpg

public static String rfc5987_encode(final String s) throws UnsupportedEncodingException {
    final byte[] s_bytes = s.getBytes("UTF-8");
    final int len = s_bytes.length;
    final StringBuilder sb = new StringBuilder(len << 1);
    final char[] digits = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    final byte[] attr_char = {'!','#','$','&','+','-','.','0','1','2','3','4','5','6','7','8','9',           'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','^','_','`',                        'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','|', '~'};
    for (int i = 0; i < len; ++i) {
        final byte b = s_bytes[i];
        if (Arrays.binarySearch(attr_char, b) >= 0)
            sb.append((char) b);
        else {
            sb.append('%');
            sb.append(digits[0x0f & (b >>> 4)]);
            sb.append(digits[b & 0x0f]);
        }
    }

    return sb.toString();
}
于 2012-07-03T09:14:34.970 に答える