571 votes

Comment coder le paramètre de nom de fichier d’en-tête Content-Disposition en HTTP ?

Les applications Web que voulez forcer une ressource qui doit être téléchargé plutôt que directement rendu dans un navigateur Web émettre un Content-Disposition - tête de la réponse HTTP de la forme:

Content-Disposition: attachment; filename=

L' FILENAME paramètre peut être utilisé pour suggérer un nom pour le fichier dans lequel la ressource est téléchargé par le navigateur. RFC 2183 (Content-Disposition), cependant, les états dans la section 2.3 (Le Paramètre Filename) que le nom de fichier ne peut utiliser des caractères US-ASCII:

[RFC 2045] grammaire limite les valeurs de paramètre (et donc Content-Disposition des noms de fichiers) US-ASCII. Nous reconnaissons la grande l'opportunité de permettre l'arbitraire les jeux de caractères dans les noms de fichiers, mais il est au-delà de la portée du présent document de définir les mécanismes nécessaires.

Il existe des preuves empiriques, néanmoins, que la plupart des navigateurs internet les plus populaires d'aujourd'hui semblent permis à des non-caractères US-ASCII encore (pour l'absence d'une norme) sont en désaccord sur le schéma de codage et le jeu de caractères de la spécification du nom de fichier. La Question est alors, quels sont les différents régimes et les codages employées par les navigateurs populaires si le nom de fichier "naïvefile" (sans les guillemets et la troisième lettre est U+00EF) nécessaires pour être encodés dans l'-tête Content-Disposition?

Pour les fins de cette question, les navigateurs les plus courants étant:

  • Firefox
  • Internet Explorer
  • Safari
  • Google Chrome
  • Opéra

401voto

Je sais que c'est un vieux post mais il est toujours très pertinentes. J'ai trouvé que les navigateurs modernes soutien rfc5987, qui permet l'encodage utf-8, le pourcentage codé (url-encodé). Puis Naïf file.txt devient:

Content-Disposition: attachment; filename*=UTF-8''Na%C3%AFve%20file.txt

Safari (5) n'a pas de soutiens et vous, au lieu d'utiliser le Safari standard de l'écriture du nom de fichier directement dans votre codé en utf-8 en-tête:

Content-Disposition: attachment; filename=Naïve file.txt

IE8 et plus ne le supporte pas non plus, et vous devez utiliser l'IE niveau de l'encodage utf-8, le pourcentage codé:

Content-Disposition: attachment; filename=Na%C3%AFve%20file.txt

Dans ASP.Net j'utilise le code suivant:

string contentDisposition;
if (Request.Browser.Browser == "IE" && (Request.Browser.Version == "7.0" || Request.Browser.Version == "8.0"))
    contentDisposition = "attachment; filename=" + Uri.EscapeDataString(fileName);
else if (Request.Browser.Browser == "Safari")
    contentDisposition = "attachment; filename=" + fileName;
else
    contentDisposition = "attachment; filename*=UTF-8''" + Uri.EscapeDataString(fileName);
Response.AddHeader("Content-Disposition", contentDisposition);

J'ai testé le ci-dessus en utilisant IE7, IE8, IE9, Chrome 13, Opera 11, FF5, Safari 5.

Mise À Jour De Novembre 2013:

Voici le code que j'utilise actuellement. J'ai encore à l'appui de IE8, donc je ne peut pas se débarrasser de la première partie. Il s'avère que les navigateurs sur Android utiliser le construit en Android gestionnaire de téléchargement et il ne peut pas analyser de manière fiable les noms de fichier de façon standard.

string contentDisposition;
if (Request.Browser.Browser == "IE" && (Request.Browser.Version == "7.0" || Request.Browser.Version == "8.0"))
    contentDisposition = "attachment; filename=" + Uri.EscapeDataString(fileName);
else if (Request.UserAgent != null && Request.UserAgent.ToLowerInvariant().Contains("android")) // android built-in download manager (all browsers on android)
    contentDisposition = "attachment; filename=\"" + MakeAndroidSafeFileName(fileName) + "\"";
else
    contentDisposition = "attachment; filename=\"" + fileName + "\"; filename*=UTF-8''" + Uri.EscapeDataString(fileName);
Response.AddHeader("Content-Disposition", contentDisposition);

Le ci-dessus est maintenant testé dans IE7-11, Chrome 32, Opera 12, FF25, Safari 6, en utilisant le nom du fichier à télécharger: 你好abcABCæøåÆØÅäöüïëêîâéíáóúýñ½§!#¤%&()=`@£$€{[]}+^~'-_,;.txt

Sur IE7 ça marche pour certains personnages, mais pas tous. Mais qui se soucie de IE7 aujourd'hui?

C'est la fonction que j'utilise pour générer sûr les noms de fichiers pour Android. Notez que je ne sais pas quels sont les caractères pris en charge sur Android, mais que j'ai testé que ces travaux pour assurer:

private static readonly Dictionary<char, char> AndroidAllowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-+,@£$€!½§~'=()[]{}0123456789".ToDictionary(c => c);
private string MakeAndroidSafeFileName(string fileName)
{
    char[] newFileName = fileName.ToCharArray();
    for (int i = 0; i < newFileName.Length; i++)
    {
        if (!AndroidAllowedChars.ContainsKey(newFileName[i]))
            newFileName[i] = '_';
    }
    return new string(newFileName);
}

@TomZ: je l'ai testé dans IE7 et IE8 et il s'est avéré que je n'ai pas besoin d'échapper l'apostrophe ('). Avez-vous un exemple où il échoue?

@Dave Van den Eynde: la Combinaison de deux noms de fichier sur une ligne selon RFC6266 fonctionne sauf pour Android et IE7+8 et j'ai mis à jour le code pour tenir compte de cela. Merci pour la suggestion.

@Thilo: Aucune idée sur GoodReader ou tout autre navigateur. Vous pourriez avoir de la chance en utilisant le Android approche.

177voto

porneL Points 42805

Il est simple et très robuste alternative: utiliser une URL qui contient le nom de fichier que vous voulez.

Lorsque le nom après le dernier slash est celui que vous voulez, vous n'avez pas besoin de tout des en-têtes supplémentaires!

Cette astuce fonctionne:

/real_script.php/fake_filename.doc

Et si votre serveur prend en charge la réécriture d'URL (par exemple, mod_rewrite dans Apache), alors vous pouvez bien cacher la partie du script.

Les caractères dans l'Url doit être en UTF-8, urlencoded octet-par-octet:

/mot%C3%B6rhead   # motörhead

102voto

Jim Points 39574

Il y a une discussion de ce, y compris des liens vers de test du navigateur et d'une compatibilité ascendante, dans le projet de RFC 5987, "Jeu de Caractères et la Langue de Codage pour le Protocole de Transfert Hypertexte (HTTP) Champ d'en-Tête Paramètres."

RFC 2183 indique que ces en-têtes doivent être codées conformément à la norme RFC 2184, qui a été rendu obsolète par la RFC 2231, couverts par le projet RFC ci-dessus.

78voto

MvG Points 22342

RFC 6266 décrit les "Utilisation du Contenu-Disposition Champ d'en-Tête dans le Protocole de Transfert Hypertexte (HTTP)". Citation de:

6. L'Internationalisation Des Considérations

Le "filename*" paramètre (Section 4.3), en utilisant l'encodage défini dans [RFC5987], permet au serveur de transmettre les caractères en dehors de la ISO-8859-1 jeu de caractères, et aussi à l'option de spécifier la langue en cours d'utilisation.

Et dans leur section exemples:

Cet exemple est le même que celui ci-dessus, mais en y ajoutant le "nom de fichier" paramètre pour la compatibilité avec les agents utilisateurs ne mettent pas en œuvre RFC 5987:

Content-Disposition: attachment;
                     filename="EURO rates";
                     filename*=utf-8''%e2%82%ac%20rates

Remarque: les agents utilisateurs qui ne prennent pas en charge la RFC 5987encodage ignorer "filename*" lorsqu'elle survient après "filename".

Dans l'Annexe D il y a aussi une longue liste de propositions visant à accroître l'interopérabilité. Il souligne également à un site qui compare les implémentations. Le courant passe-tests adapté pour les noms de fichiers communs comprennent:

  • attwithisofnplain: plaine de l'ISO-8859-1 nom de fichier entre guillemets et sans codage. Cela nécessite un nom de fichier qui est ISO-8859-1 et ne contiennent pas de signes de pourcentage, au moins pas en face de chiffres hexadécimaux.
  • attfnboth: deux paramètres dans l'ordre décrit ci-dessus. Devrait fonctionner pour la plupart des noms de fichier sur la plupart des navigateurs, bien que IE8 va utiliser le "filename" paramètre.

Que la RFC 5987 à son tour références RFC 2231, qui décrit le format réel. 2231 est principalement pour la messagerie, et 5987 nous dit ce que les pièces peuvent être utilisés pour les en-têtes HTTP. Ne pas confondre avec les en-têtes MIME utilisé à l'intérieur d'un multipart/form-data HTTP corps, qui est régie par la RFC 2388 (section 4.4 ) et le HTML 5 projet.

16voto

Atif Aziz Points 16967

Le document suivant, lié au projet de RFC mentionné par Jim dans sa réponse , aborde en outre la question et vaut certainement une note directe ici:

Cas de test pour l'en-tête HTTP Content-Disposition et l'encodage RFC 2231/2047

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X