O nome do arquivo corrupção no download de arquivo (IE)
-
03-07-2019 - |
Pergunta
Eu tenho implementado um mecanismo de upload-de download de arquivo simples. Quando um usuário clica em um nome de arquivo, o arquivo é baixado com estes cabeçalhos 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
Eu também suportar nomes de arquivos japoneses. A fim de fazer isso, eu codificar o nome do arquivo com este método 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");
}
Isso funcionou bem até agora, até que alguém descobriu que ele não funciona bem com nomes de arquivo longos. Por exemplo: あああああああああああああああ2008.10.1あ.doc
. Se eu mudar um dos pontos de byte único para um sublinhado de byte único, ou se eu remover o primeiro caractere, ele funciona OK. ou seja, depende do comprimento e URL-codificação de um caractere de ponto.
Seguem-se alguns exemplos.
Esta é quebrado (あああああああああああああああ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;
Este é OK (あああああああああああああああ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;
Esta é também fino (あああああああああああああああ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;
Alguém tem uma pista?
Solução
alças gmail nome do arquivo escapar um pouco diferente: o nome do arquivo é citado (aspas), e períodos de byte único não são escapou-URL. Desta forma, o nome de arquivo longo na questão é OK.
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"
No entanto, ainda há uma limitação (aparentemente IE-only) no byte de comprimento do nome do arquivo (um bug, presumo). Assim, mesmo se o nome do arquivo é feito de apenas caracteres de byte único, o início do nome do arquivo é truncado. A limitação é de cerca de 160 bytes.
Outras dicas
Como mencionado acima, Content-Disposition e Unicode é impossível começar a trabalhar todos os principais navegadores sem navegador cheirar e retornando cabeçalhos diferentes para cada um.
A minha solução foi evitar o cabeçalho Content-Disposition inteiramente, e anexar o nome do arquivo para o final da URL para enganar o navegador em pensar que estava ficando um arquivo diretamente. por exemplo.
http://www.xyz.com/cgi-bin/dynamic.php/あああああああああああああああ2008.10.1あ.doc
Isto, naturalmente, pressupõe que você saiba o nome do arquivo quando você cria o link, embora um cabeçalho de redirecionamento rápido poderia defini-lo sob demanda.
O principal problema aqui é que o IE não suporta a RFC relevantes, aqui: RFC2231. Veja ponteiros e casos de teste . Além disso, a solução que você usa para o IE (apenas usando por cento escapou UTF-8) tem vários problemas adicionais; Ele pode não funcionar em todos os locais (tanto quanto eu recordar, o método falha na Coreia, a menos que o IE é configurado para usar sempre UTF-8 em URLs que não é o padrão), e, como mencionado anteriormente, existem limites de comprimento (I ouvir que que foi corrigido no IE8, mas eu não tentei ainda).
Eu acho que este problema é corrigido no IE8, eu já vi isso funcionar no IE 8.