También disponible en: English · Português · Français · العربية
Generador y analizador de multipart/form-data
Escribe la petición que mandaría un navegador para subir un archivo, o pega una y averigua qué recibe de verdad el servidor.
Qué es multipart/form-data
multipart/form-data es el formato con el que un navegador manda un formulario que lleva un archivo. En vez de una sola cadena de pares clave-valor, el cuerpo se corta en partes separadas por un delimitador llamado frontera, y cada parte lleva sus propias cabeceras. Toda parte debe declarar Content-Disposition: form-data con un parámetro name que diga de qué campo del formulario viene; la parte que representa un archivo añade un parámetro filename y normalmente un Content-Type.
La frontera es el único parámetro obligatorio de la cabecera Content-Type de la petición, porque sin ella el receptor no tiene forma de saber dónde acaba una parte y empieza la siguiente. Tiene que ser una cadena que no aparezca dentro de ninguna parte, y la especificación MIME la limita a 70 caracteres. Por eso los navegadores generan algo largo y con pinta de aleatorio en vez de algo legible.
Hay dos detalles del formato que despistan porque parecen ruido de formato. Los finales de línea son pares CRLF y no saltos sueltos, en todas partes, incluida la línea en blanco que separa las cabeceras de una parte de su contenido. Y el delimitador final lleva dos guiones más al final: eso es lo que dice que el cuerpo terminó en vez de haberse cortado por el camino.
Cómo usarlo
- Elige un modo. Crear una petición toma un campo de texto y uno de archivo y escribe los bytes que mandaría un navegador. Leer una petición toma un cuerpo que ya tengas y deduce las partes que saca de él un servidor.
- En modo creación, escribe el nombre de archivo que te importa. Los botones de ejemplo cubren un nombre sencillo, uno con tildes, uno que no se puede recuperar y otro con comillas dobles. Fíjate en la fila de abajo: enseña cómo viaja cada nombre y si la transformación se puede deshacer.
- En modo lectura, pega el cuerpo y la frontera. Puedes pegar la cabecera Content-Type entera y la frontera se saca de ahí. La tabla enumera cada parte que recibe el servidor; los hallazgos de abajo se dividen en errores, que rompen algo; avisos, que significan que la petición no la montó un navegador; y notas, que conviene saber y no son fallos.
Tres especificaciones, tres respuestas sobre el nombre del archivo
Pregunta cómo meter un nombre de archivo fuera de US-ASCII en una subida y te encuentras tres respuestas incompatibles, todas normativas, y esta página existe porque la primera a la que echaría mano cualquiera está prohibida de forma explícita.
La RFC 7578 lo zanja en una nota: la codificación de la RFC 5987, la que añadiría un parámetro filename* a la cabecera Content-Disposition, no debe usarse aquí. Eso es justo lo contrario de la regla para una descarga. En una respuesta HTTP, la RFC 6266 exige filename* para cualquier nombre que US-ASCII no sepa expresar, y este sitio tiene una página aparte sobre cómo hacerlo bien. Misma cabecera, mismo parámetro, instrucción opuesta, y lo único que decide cuál se aplica es si viaja en una respuesta o dentro del cuerpo de una petición.
La misma sección ofrece luego una segunda respuesta: los nombres de archivo pueden ir con codificación de porcentaje, igual que se codificaría una URI file:. Y en el párrafo siguiente admite la tercera, que es lo que pasa de verdad: hay sistemas muy desplegados que mandan nombres con octetos fuera de US-ASCII directamente, normalmente en UTF-8. Esa concesión merece leerse dos veces, porque una especificación que reconoce que el mundo hace otra cosa es una especificación diciéndote qué va a recibir tu código.
Lo que hacen los navegadores es la tercera. El estándar HTML define el algoritmo que siguen, y manda el nombre como bytes en crudo en la codificación del formulario, sin ningún parámetro que lo anuncie. Así que un receptor que se equivoque al adivinar produce mojibake, y no hay nada en la petición con lo que corregirlo. El generador de aquí hace lo que hace un navegador, y la fila de debajo enseña el recuento de bytes por delante del de caracteres, que es esa decisión hecha visible.
El escapado no se puede deshacer
El algoritmo del estándar HTML escapa exactamente tres caracteres en el nombre de un campo o de un archivo: un salto de línea pasa a %0A, un retorno de carro a %0D y unas comillas dobles a %22. Y luego cierra la lista con todas las letras: el agente de usuario no debe realizar ningún otro escapado.
Esa última frase es la interesante, porque significa que el signo de porcentaje nunca se toca. Un archivo que se llame de verdad a%0Ab.txt y otro cuyo nombre contenga un salto de línea real llegan los dos como a%0Ab.txt, y no hay nada en la petición que los distinga. Lo mismo pasa con %0D frente a un retorno de carro y con %22 frente a unas comillas. Medido contra una implementación real del algoritmo, no razonado: los tres pares salen idénticos.
Así que la transformación es de ida por diseño, y el arreglo evidente —escapar también el porcentaje— es justo lo que la norma prohíbe. Cualquier cosa que guarde un archivo subido con el nombre que le dieron está dando por hecho, calladamente, que esto no ocurre. Es raro, y no es imposible: un porcentaje seguido de dos dígitos hexadecimales es exactamente la forma que adopta un nombre que ya pasó por una codificación de URL más arriba.
La herramienta lo señala en vez de arreglarlo, porque no hay arreglo que aplicar. Cuando un nombre comparte sus bytes con otro, la fila de debajo lo dice, y quien lee decide si eso importa para lo que está construyendo.
Lo que esto no te va a decir
Esto lee el texto que pegas y nada más. Un navegador no puede inspeccionar las peticiones de otro sitio, así que la herramienta no sabe si el cuerpo que miras es el que se manda, si la cabecera Content-Type que lo acompaña encaja, ni qué hizo un servidor con él después.
El generador escribe un cuerpo, no una petición. Enseña la cabecera Content-Type que tiene que acompañarlo, porque ahí vive la frontera y sin ella el cuerpo no significa nada, pero el resto de la petición —el método, la ruta, la longitud— es cosa tuya. Pega el cuerpo en el cliente con el que estés probando en vez de esperar que esto mande algo.
Hay una simplificación deliberada. El contenido real de una parte son bytes, y un navegador mete tan tranquilo un JPEG en una; esto trabaja en texto, así que la parte de archivo lleva un relleno en vez de un archivo de verdad. Todo lo demás —la estructura, las cabeceras, el escapado y los delimitadores— es exactamente lo que produce un navegador, y de eso va la página; pero no midas el tamaño de una subida real por lo que ves aquí.
Por último, el formato tiene un mecanismo antiguo que esto no implementa: Content-Transfer-Encoding, que en su día permitía que una parte fuera quoted-printable para sobrevivir a un transporte de siete bits. La RFC 7578 dice a los emisores que no la generen sobre un transporte que lleva binario, y HTTP lo lleva, así que la herramienta la señala si pegas una en vez de hacer como si fuera normal.
¿Por qué es gratis?
Crear y leer un cuerpo de petición es trabajo de texto y corre en tu navegador. No hay ningún servidor de por medio, así que no hay nada que cobrar ni cuenta que crear.
No se sube nada y no se guarda nada. Recarga la página y habrá olvidado lo que pegaste.