Codificación / deencoding de encabezados HTTP en Java

Un encabezado HTTP personalizado se pasa a una aplicación de servlet para fines de autenticación. El valor del encabezado debe poder contener acentos y otros caracteres que no sean ASCII, por lo que debe estar en cierta encoding (idealmente, UTF-8).

Los desarrolladores que controlan el entorno de autenticación me proporcionan este código de Java:

String firstName = request.getHeader("my-custom-header"); String decodedFirstName = new String(firstName.getBytes(),"UTF-8"); 

Pero este código no me parece correcto: presupone la encoding del valor del encabezado, cuando me pareció que había una forma adecuada de especificar una encoding para los valores del encabezado (desde MIME, creo).

Aquí está mi pregunta: ¿cuál es la forma correcta ™ de tratar con los valores de encabezado personalizado que necesitan para soportar una encoding UTF-8:

  • en el cable (cómo se ve el encabezado sobre el cable)
  • desde el punto de vista de la deencoding (cómo decodificarlo usando la API del Servlet de Java, y podemos suponer que request.getHeader () ya hace la desencoding correctamente)

Aquí hay un ejemplo de código independiente del entorno para tratar los encabezados como UTF-8 en caso de que no pueda cambiar su servicio:

 String valueAsISO = request.getHeader("my-custom-header"); String valueAsUTF8 = new String(firstName.getBytes("ISO8859-1"),"UTF-8"); 

De nuevo: el RFC 2047 no se implementa en la práctica. La próxima revisión de HTTP / 1.1 va a eliminar cualquier mención de ello.

Por lo tanto, si necesita transportar caracteres que no sean ASCII, la forma más segura es codificarlos en una secuencia de ASCII, como el encabezado “Slug” en el protocolo de publicación Atom.

El grupo de trabajo HTTPbis es consciente del problema, y ​​los últimos borradores eliminan todo el lenguaje con respecto a la encoding TEXT y RFC 2047, no se usa en la práctica a través de HTTP.

Ver http://trac.tools.ietf.org/wg/httpbis/trac/ticket/74 para la historia completa.

Como ya se mencionó, el primer vistazo siempre debe ir a la especificación HTTP 1.1 (RFC 2616). Dice que el texto en los valores del encabezado debe usar la encoding MIME como se define en RFC 2047 si contiene caracteres de conjuntos de caracteres que no sean ISO-8859-1.

Así que aquí hay una ventaja para ti. Si sus requisitos están cubiertos por el conjunto de caracteres ISO-8859-1, simplemente coloca sus caracteres en sus mensajes de solicitud / respuesta. De lo contrario, la encoding MIME es la única alternativa.

Siempre que el agente de usuario envíe los valores a sus encabezados personalizados de acuerdo con estas reglas, no tendrá que preocuparse por decodificarlos. Eso es lo que debe hacer la API de Servlet.


Sin embargo, hay una razón más básica por la cual su sniplet de código no hace lo que se supone que debe hacer. La primera línea obtiene el valor del encabezado como una cadena de Java. Como sabemos, se representa internamente como UTF8, por lo que en este punto el análisis de mensajes de solicitud HTTP ya está hecho y finalizado.

La siguiente línea obtiene la matriz de bytes de esta cadena. Dado que no se especificó ninguna encoding (en mi humilde opinión, este método sin argumento debería haber quedado obsoleto hace mucho tiempo), se usa la encoding predeterminada del sistema actual, que generalmente no es UTF8 y luego la matriz se convierte de nuevo en encoding UTF8. Outch.

Vea las especificaciones HTTP para las reglas, que dice en la sección 2.2

La regla de TEXTO solo se utiliza para los valores de contenido descriptivo y los valores que no están destinados a ser interpretados por el analizador de mensajes. Las palabras de * TEXT PUEDEN contener caracteres de juegos de caracteres que no sean ISO- 8859-1 [22] solo cuando están codificados según las reglas de RFC 2047 [14].

El código anterior no decodificará correctamente una cadena de encoding RFC2047, lo que me lleva a pensar que el servicio no sigue correctamente las especificaciones, y que simplemente integran los datos brutos del UFP-8 en el encabezado.

Gracias por las respuestas. Parece que lo ideal sería seguir la correcta encoding de encabezado HTTP según RFC 2047. Los valores de encabezado en UTF-8 en el cable se verían así:

 =?UTF-8?Q?...?= 

Ahora, aquí está lo gracioso: ¡parece que ni Tomcat 5.5 ni 6 decodifican correctamente los encabezados HTTP según RFC 2047! El código de Tomcat supone en todas partes que los valores de encabezado usan ISO-8859-1.

Así que para Tomcat, específicamente, voy a trabajar en esto escribiendo un filtro que maneje la desencoding adecuada de los valores del encabezado.