Повреждение имени файла при загрузке файла (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");
}
До сих пор это работало хорошо, пока кто-то не обнаружил, что это плохо работает с длинными именами файлов.Например: あああああああああああああああ2008.10.1あ.doc
.Если я изменю одну из однобайтовых точек на однобайтовое подчеркивание или удалю первый символ, все будет работать нормально.т.е. это зависит от длины и URL-кодировки символа точки.Ниже приведено несколько примеров.
Это сломано (あああああああああああああああ2008.10.1あ.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;
Все в порядке (あああああああああああああああ2008_10.1あ.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;
Это тоже прекрасно (あああああああああああああああ2008.10.1あ.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 обрабатывает экранирование имени файла несколько по-другому:имя файла заключено в кавычки (двойные кавычки), а однобайтовые точки не экранируются 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) на длину имени файла в байтах (я полагаю, ошибка).Таким образом, даже если имя файла состоит только из однобайтовых символов, начало имени файла усекается.Ограничение составляет около 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 не настроен на постоянное использование UTF-8 в URL-адресах, которые не используются по умолчанию), и, как упоминалось ранее, существуют ограничения по длине (я слышал, что это исправлено в IE8, но я еще не пробовал).
Я думаю, что эта проблема исправлена в IE8, я видел, как она работает в IE 8.