AP_PostPairs charset y encoding

Post Reply
pablo-botella
Posts: 6
Joined: Sun Nov 10, 2019 12:44 am

AP_PostPairs charset y encoding

Post by pablo-botella » Thu Dec 26, 2019 4:50 pm

Pegado del Slack:

Code: Select all

Andreu'); DROP TABLE users; -- 07:18
Buenas
No sé si queda alguien vivo que no esté de vacaciones
Se supone que mod_harbour todavía no es oficialmente "estable", ¿verdad?

Cuando digo estable quiero decir que la retrocompatibilidad sea un problema
Porque creo que tengo un argumento convincente para cambiar la funcionalidad 
de las funciones AP_PostPairs() y hb_UrlDecode() 
Iba a abrir un issue en el github, pero si lo expongo por aquí 
en español y me decís que ni de coña, eso que nos ahorramos. (editado) 


Otto 08:41
Hi Andreu,
how are we affected


Andreu'); DROP TABLE users; -- 08:41
hi basically, if you're only using those two functions as something like 
hb_UrlDecode(AP_PostPairs()["username"]), with this change you could 
just use AP_PostPairs()["username"] but this would make it possible to 
handle file uploads with AP_PostPairs , which isn't really possible right 
now without a second round of parsing the multipart/form-data 
format there's also the fact that hb_UrlDecode doesn't
quite do URL decoding, but URL decoding plus replacing + 's with spaces, 
which makes no sense outside of the www-urlencoded format that AP_PostPairs 
decodes so bundling both in just one function makes sense (not sure if my 
explanation makes sense, though) 

Andreu'); DROP TABLE users; -- 08:52
I expected that AP_PostPairs could also decode whatever encoding the 
browser used after URL decoding, returning a native string (OEM, I guess)
but after looking at the specifications, there's no such luck

Diego Fazio 12:32
Buenos dias. @Andreu'); DROP TABLE users; -- , no conozco exactamente que hace 
hb_UrlDecode, pero lo que comentas es cierto. Si se pudiera evitar hacer dos
pasadas para decodificar la url estaria mejor.

Andreu'); DROP TABLE users; -- 13:25
Buenas. Las URL soportan caracteres ASCII, y hay ciertos caracteres (? y # en particular)
que tienen un significado especial, así que todo lo que no sea alfanumérico o en un rango
limitado de puntuación se escapa con % más la codificación hexadecimal del byte: %20 
para el espacio.

Esta codificación es a nivel de bytes: para codificar un caracter que no sea ASCII se convierte
a UTF-8 primero

Esta codificación se usa con la mayor parte de la URL, aunque no con el nombre de dominio porque 
históricamente los nombres de dominio eran solo ASCII y con el query string (la parte ?a=b&c=d 
que se ve en todas partes), por motivos que yo no conozco, además de la codificación normal, los espacios 
se reemplazan por el caracter '+' hb_UrlDecode ahora mismo decodifica los '+' en espacios, que es perfecto 
para cuerpos de POST urlencoded y el query string, pero no para cosas como hacer un controlador como el 
de génesis (cuando digo arriba ASCII quiero decir ASCII-128, como lo usa todo el mundo que no se crió con 
MSDOS :cara_con_ojos_en_blanco:)


Pablo Botella 16:15
@Andreu'); DROP TABLE users; -- que hace PHP?
$_POST_[]  te las da ya sin urlencoding?

Andreu'); DROP TABLE users; -- 16:16
creo que sí, pero ahora mismo no estoy seguro
https://github.com/php/php-src/blob/master/main/php_variables.c#L282

php/php-src
The PHP Interpreter. Contribute to php/php-src development by creating an account on GitHub.
sí aunque voy a buscar la función php_url_decode para asegurarme

Pablo Botella 16:20
lo suyo sería mirar en php que podría ser un buen modelo en que capa está haciendo el urldecode, si no lo está haciendo entonces dejamos AP_PostPairs tal como está y si php si que hace el decode pues podrías probar y haces un pull request y propones el cambio
no busques php_url-decode
php es un mod en linux?
porque estaba pensando que con windows es un fastcgi desde hace mucho


Andreu'); DROP TABLE users; -- 16:22
en apache/linux creo que es un mod, pero en nginx se usa la versión de fastcgi

Pablo Botella 16:23
pasame el link del git si lo tienes a mano, pls
Andreu'); DROP TABLE users; -- 16:25
el link de qué git?


Pablo Botella 16:25
de mod php
pero bueno busco en la web de php  :cara_ligeramente_sonriente: con esto de las navidades me estoy volviendo vago


Andreu'); DROP TABLE users; -- 16:28
git clone https://github.com/php/php-src.git
./configure --with-apxs2=/usr/local/apache2/bin/apxs --with-mysql
make
make install
el libphp7.so que genera (en sistemas linux) es el mod de apache


Pablo Botella 16:29
thx


Andreu'); DROP TABLE users; -- 16:30
apxs es un ejecutable que para ti vendrá en la distribución de apache para windows


Pablo Botella 16:31
con el codigo me sobra


Pablo Botella 16:36
Aquí creo que para no ir dando tumbos lo suyo es primero mirar php como modelo, y preparar un spec, definiendo el punto en 
que se hace cada conversión ,juego de caracteres, encoding,... ponemos un doc y se lo enseñamos a los mozos estos que 
andan por aquí y luego lo implementamos.  Aquí creo que es más importante el spec que el código en si, porque porque ahí 
vamos a enganchar luego o revisar como están enganchados, fastcgi, iis, httpapi, ....

Andreu'); DROP TABLE users; -- 16:41
Pensaba reescribir la función AP_PostPairs en un par de días. Documentar lo que hace PHP va a tardar más que eso.

Pablo Botella 16:42
reescríbela si quieres antes y luego la revisamos y se ajusta
voy a pegarle un miradita al codigo de php y hago un hilo para esto en el foro

Andreu'); DROP TABLE users; -- 16:44
Pero sospecho que PHP sigue las especificaciones de application/x-www-form-urlencoded  del WHATWG 
(https://url.spec.whatwg.org/#application/x-www-form-urlencoded) y multipart/form-data  
(https://tools.ietf.org/html/rfc7578) al pie de la letra y sin decodificar caracteres (aunque bytes sí)

Pablo Botella 16:45
bueno pues revisamos si las sigue y si es así ya tenemos a donde agarrarnos
Last edited by pablo-botella on Thu Dec 26, 2019 5:37 pm, edited 2 times in total.

pablo-botella
Posts: 6
Joined: Sun Nov 10, 2019 12:44 am

Re: AP_PostPairs charset y encoding

Post by pablo-botella » Thu Dec 26, 2019 4:52 pm

otro párrafo más pegado del slack:

Code: Select all


Andreu'); DROP TABLE users; -- 16:49
btw, la especificación de application/x-www-form-urlencoded pone que:
A legacy server-oriented implementation might have to support encodings 
other than UTF-8 as well as have special logic for  tuples of which the name 
is `_charset`. Such logic is not described here as only UTF-8 is conforming.

Pero en la práctica, si sigues las especificaciones de HTML y de codificación
a application/x-www-form-urlencoded, te puedes encontrar con codificaciones
que no son UTF-8 usadas sin el campo _charset Así que la decodificación de 
caracteres se deja mejor al usuario, por peligroso que esto pueda ser 
en la práctica

pablo-botella
Posts: 6
Joined: Sun Nov 10, 2019 12:44 am

Re: AP_PostPairs charset y encoding

Post by pablo-botella » Thu Dec 26, 2019 6:00 pm

otro más:

Code: Select all


Andreu'); DROP TABLE users; -- 17:54
@Pablo Botella Hay una cosa de las que PHP hace en las funciones urlencode/urldecode con la que 
estoy muy en desacuerdo supongo que tiene sentido, pero se puede crear un contexto de programación 
en el que lo deje de tener


Andreu Botella
Site Admin
Posts: 11
Joined: Sun Nov 10, 2019 12:36 am

Re: AP_PostPairs charset y encoding

Post by Andreu Botella » Thu Dec 26, 2019 6:15 pm

HTML describe tres representaciones distintas de los valores de un formulario para transporte por POST:
  • application/x-www-form-urlencoded. Este formato usa solo caracteres ASCII, y sus nombres y valores representan cadenas de texto (Unicode), no bytes/ficheros.

    El algoritmo de decodificación de la especificación asume que, tras decodificar los bytes con el percent-encoding, el resultado son bytes UTF-8. Pero si se siguen los algoritmos de la especificación de HTML para enviar formularios, la codificación de caracteres usada es aquella que usa la página HTML (excepto si usa UTF-16, en cuyo caso se usa UTF-8). Si en los datos del formulario hay un nombre con la cadena de bytes "_charset", su valor es el nombre de la codificación del formulario, pero este nombre no tiene por qué estar, incluso cuando la codificación no es UTF-8.
  • multipart/form-data. Este es un formato definido por las especificaciones de MIME. Es un formato binario, y permite representar valores que sean cadenas de texto (Unicode), o cadenas de bytes (ficheros de subida, por ejemplo). Los valores que son cadenas de bytes (ficheros) se tratan de forma distinta a los valores que son cadenas de texto, ya que pueden tener cabeceras (Content-Type se usa para indicar el tipo MIME del fichero), y pueden llevar asociado un nombre de fichero distinto al nombre de la entrada en el formulario.

    Las especificaciones de este formato tratan los valores en forma de cadena de texto (y los nombres de fichero) como cadenas en binario, por lo que no se puede asumir mucho sobre su contenido. Sin embargo, la especificación de HTML manda que la codificación de caracteres usada en ambos casos sea aquella que usa la página HTML (excepto si usa UTF-16, en cuyo caso se usa UTF-8). Si en los datos del formulario hay un nombre con la cadena de bytes "_charset", su valor es el nombre de la codificación del formulario, pero este nombre no tiene por qué estar, sea cual sea la codificación. Los ficheros se mandan byte por byte tal cual están en el sistema de ficheros original, sin normalizar charsets o saltos de línea.
  • text/plain. HTML permite enviar este formato, pero la misma especificación advierte de que este es un formato ambiguo, hecho para que lo lean humanos y no para que lo interpreten máquinas.
  • application/json. Aunque HTML no reconoce ni permite enviar este formato desde un formulario, JSON se usa mucho como el cuerpo de peticiones en servicios REST. En este contexto la codificación que se usa casi universalmente es UTF-8 sin marca de orden de bytes.
La función AP_PostPairs incluida en mod_harbour pretende decodificar el formato application/x-www-form-urlencoded, pero se queda corta. La definición de este formato (ignorando cuestiones de codificación de caracteres) incluye una codificación de bytes que AP_PostPairs no deshace; esto se puede lograr usando hb_UrlDecode(AP_PostPairs()), pero esto es mucho menos que ideal (véase abajo con respecto a hb_UrlDecode). Creo que es importante que AP_PostPairs devuelva un hash que contenga todos los campos del formulario, da igual en qué formato venga (excepto text/plain por los motivos comentados arriba). Si el formato no se reconoce, NIL parece aceptable como valor de retorno.

Dado que la codificación application/x-www-form-urlencoded no solo se usa para los cuerpos de peticiones POST, sino también para las query string de las URLs, sería interesante considerar una función ParseUrlEncoded que tome una cadena y la decodifique como si fuera el cuerpo de una petición con este formato. También sería interesante generar este formato, quizá con una función FormatUrlEncoded.

Sobre la función hb_UrlDecode, hay dos tipos de codificaciones que tienen lugar en una URL (aparte de Punycode/IDNA, que se aplica a nombres de dominios y no hace falta implementarse en servidores):
  • Percent-encoding. Esta es una codificación de bytes definida por el estándar URL del WHATWG (y anteriormente por varios estándares del IETF), por el cual los bytes que no sean aceptables se codifican como un caracter '%' seguido por dos cifras hexadecimales correspondientes al código del byte. A la hora de codificar, el estándar URL define varios conjuntos de bytes que no son aceptables en distintos contextos: el más estricto sería el userinfo percent-encode set. A la hora de decodificar no hace falta tener en cuenta estos contextos, cualquier byte codificado se decodifica. Esta codificación se usa sobre todo en el path de la URL. Un espacio ' ' se representa como "%20". No hay una función predefinida en (mod_)harbour que deshaga esta codificación.
  • Serialización de bytes en application/x-www-form-urlencoded. Esta codificación es una variante del percent-encoding usada solo con application/x-www-form-urlencoded, que codifica el espacio ' ' como el byte '+', no como la cadena "%20". Esta codificación es la que hb_UrlDecode deshace.
Si movemos la decodificación completa de application/x-www-form-urlencoded a la función AP_PostPairs, podemos dejar hb_UrlDecode para que implemente la codificación percent-encoding, quizá junto a la función correspondiente hb_UrlEncode. Esto serviría para hacer controladores de MVC que soporten nombres con espacios.

-----------------------------------------------------------

Lo de arriba son las definiciones de los distintos formatos de las representaciones de formularios que se usan, así como problemas con las funciones AP_PostPairs y hb_UrlDecode y una sugerencia de cómo se podrían arreglar. En posts posteriores compararemos esta propuesta con funcionalidades similares y distintas de otros lenguajes de back-end.

Andreu Botella
Site Admin
Posts: 11
Joined: Sun Nov 10, 2019 12:36 am

Re: AP_PostPairs charset y encoding

Post by Andreu Botella » Sun Jan 05, 2020 10:54 pm

Como referencia de cómo hace las cosas PHP, https://github.com/php/php-src es el repositorio principal de sus fuentes, y el módulo de PHP para Apache está en https://github.com/php/php-src/tree/mas ... he2handler

Post Reply