2012-07-02 15 views
6

Ho un codice legacy con cui ho a che fare (quindi non posso usare solo un URL con un componente di nome file codificato) che consente a un utente di scarica un file dal nostro sito web. Poiché i nostri nomi di file sono spesso in molte lingue diverse, sono tutti memorizzati come UTF-8. Ho scritto un codice per gestire la conversione RFC5987 in un parametro filename * appropriato. Funziona perfettamente finché non ho un nome file con caratteri non ASCII e spazi. Per RFC, il carattere dello spazio non fa parte di attr_char quindi viene codificato come% 20. Ho nuove versioni di Chrome e Firefox e tutte si convertono in% 20 in + al download. Ho provato a non codificare lo spazio ea inserire il nome file codificato tra virgolette e ottenere lo stesso risultato. Ho annusato la risposta proveniente dal server per verificare che il contenitore della servlet non stesse masticando con le mie intestazioni e mi sembrano corretti. La RFC ha anche esempi che contengono% 20. Mi manca qualcosa o tutti questi browser hanno un bug relativo a questo?gestione del nome file * parametri con spazi tramite RFC 5987 risultati in '+' nei nomi dei file

Molte grazie in anticipo. Il codice che uso per codificare il nome file è sotto.

Peter

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(); 
} 

Aggiornamento

Ecco uno screenshot della finestra di scaricare ottengo un file con i caratteri cinesi con spazi come indicato nel mio commento.

screen cap of download dialog

+0

Ecco un'intestazione campione che causa il problema: Content Disposition: attachment; nome file * = UTF-8''Museum% 20% 5A% 69% 86.jpg –

+0

Vedere http://greenbytes.de/tech/tc2231/#attwithquotedsemicolon - che il test case ha uno spazio in una stringa tra virgolette e viene visualizzato lavorare in Firefox. Stiamo testando cose diverse? –

+0

Sembra qualcos'altro. Quel test controlla il punto e virgola all'interno di una stringa quotata. Il mio problema è che ho un nome di file con caratteri cinesi e spazi, quindi sto usando il nome del file * e, in forma non indicata, dato che ho letto alcuni documenti che raccomandavano di non usare le virgolette con% escape. Con l'esempio del mio commento sopra i caratteri cinesi sono riconosciuti e convertiti correttamente, ma% 20 viene mappato su +. –

risposta

10

Così come Julian ha sottolineato nei commenti, ho fatto un errore di Java rookie e dimenticato di fare il mio personaggio alla conversione di byte (quindi ho codificato codepoint del personaggio al posto della rappresentazione di byte del personaggio), da cui il la codifica era completamente errata. Questo è chiaramente indicato come requisito in RFC 5987. Inserirò il codice corretto per eseguire la conversione. Una volta che la codifica è corretta, il parametro filename * viene riconosciuto correttamente dal browser e il nome file utilizzato per il download è corretto.

Di seguito è riportato il codice di escape corretto che opera sui byte UTF-8 della stringa. Il nome file che mi stava dando problemi, ora correttamente codificato assomiglia a questo:

Contenuto-disposizione: allegato; filename * = UTF-8''Museum% 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(); 
} 
+0

Vorrei sottolineare che il carattere ''' non è nella lista consentita di rfc5987. – Gedrox

+0

.. ma il carattere '\' '(simbolo accento grave, apice) è. Ho modificato la risposta. – Gedrox

Problemi correlati