¿Qué es válido y qué no en una consulta de URI?

100

Antecedentes (pregunta más abajo)

He estado buscando en Google esto de ida y vuelta leyendo RFC y preguntas SO tratando de descifrar esto, pero todavía no tengo Jack.

Así que supongo que votamos por la "mejor" respuesta y eso es todo, ¿o?

Básicamente se reduce a esto.

3.4. Componente de consulta

El componente de consulta es una cadena de información que el recurso debe interpretar.

query = *uric

Dentro de un componente de consulta, los caracteres ";", "/", "?", ":", "@", "&", "=", "+", "," Y "$" están reservados.

Lo primero que me desconcierta es que * uric se define así

uric = reserved | unreserved | escaped

reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","

Sin embargo, esto se aclara algo con párrafos como

La clase de sintaxis "reservada" anterior se refiere a aquellos caracteres que están permitidos dentro de un URI, pero que pueden no estar permitidos dentro de un componente particular de la sintaxis URI genérica; se utilizan como delimitadores de los componentes descritos en la Sección 3.

Los caracteres del conjunto "reservado" no están reservados en todos los contextos. El conjunto de caracteres realmente reservados dentro de cualquier componente de URI dado lo define ese componente. En general, un carácter se reserva si la semántica del URI cambia si el carácter se reemplaza con su codificación US-ASCII de escape.

Este último extracto se siente algo al revés, pero establece claramente que el conjunto de caracteres reservados depende del contexto. Sin embargo, 3.4 establece que todos los caracteres reservados están reservados dentro de un componente de consulta, sin embargo, lo único que cambiaría la semántica aquí es escapar del signo de interrogación (?) Ya que los URI no definen el concepto de una cadena de consulta.

En este punto, he renunciado por completo a los RFC, pero encontré el RFC 1738 particularmente interesante.

Una URL HTTP tiene la forma:

http://<host>:<port>/<path>?<searchpart>

Dentro de los componentes <path> y <searchpart>, "/", ";", "?" están reservados. El carácter "/" se puede utilizar dentro de HTTP para designar una estructura jerárquica.

Interpreto esto al menos con respecto a las URL HTTP que RFC 1738 reemplaza a RFC 2396. Debido a que la consulta URI no tiene noción de una cadena de consulta, la interpretación de reservado no me permite definir cadenas de consulta como estoy acostumbrado haciendo por ahora.

Pregunta

Todo esto comenzó cuando quise pasar una lista de números junto con la solicitud de otro recurso. No pensé mucho en eso, y simplemente lo pasé como valores separados por comas. Para mi sorpresa, la coma se escapó. La consulta page.html?q=1,2,3codificada se convirtió en page.html?q=1%2C2%2C3funciona, pero es fea y no lo esperaba. Fue entonces cuando comencé a revisar los RFC.

Mi primera pregunta es simplemente, ¿es realmente necesario codificar las comas?

Mi respuesta, según RFC 2396: sí, según RFC 1738: no

Más tarde encontré publicaciones relacionadas con el paso de listas entre solicitudes. Donde el enfoque csv estaba posicionado como malo. Esto apareció en su lugar (no había visto esto antes).

page.html?q=1;q=2;q=3

Mi segunda pregunta, ¿es esta una URL válida?

Mi respuesta, según RFC 2396: no, según RFC 1738: no (; está reservado)

No tengo ningún problema con pasar csv siempre que sean números, pero sí, corre el riesgo de tener que codificar y decodificar valores de un lado a otro si de repente se necesita la coma para otra cosa. De todos modos probé la cadena de consulta de punto y coma con ASP.NET y el resultado no fue el que esperaba.

Default.aspx?a=1;a=2&b=1&a=3

Request.QueryString["a"] = "1;a=2,3"
Request.QueryString["b"] = "1"

No veo cómo esto difiere mucho de un enfoque csv, ya que cuando pregunto por "a" obtengo una cadena con comas. ASP.NET ciertamente no es una implementación de referencia, pero aún no me ha defraudado.

Pero lo más importante, mi tercera pregunta, ¿dónde está la especificación para esto? y ¿qué harías o no harías?

John Leidegren
fuente
¿Cómo puede RFC 1738 reemplazar a RFC 2396, cuando RFC 2396 se publicó casi 4 años después?
Matthew Flaschen
1
Con respecto a las URL y lo que prácticamente tiene sentido, es mi interpretación que sí. (Reemplazar probablemente no sea la palabra correcta, sin embargo, porque se ha utilizado en la terminología RFC para los RFC antiguos obsoletos, RFC 1738 no se siente tan obsoleto cuando es la única especificación si se encuentra que le permite poner una cadena de consulta en la parte de búsqueda de la URL)
John Leidegren

Respuestas:

69

El hecho de que un carácter esté reservado dentro de un componente de URL genérico no significa que deba escaparse cuando aparece dentro del componente o dentro de los datos del componente. El carácter también debe definirse como un delimitador dentro de la sintaxis genérica o específica del esquema y la apariencia del carácter debe estar dentro de los datos.

El estándar actual para URI genéricos es RFC 3986 , que tiene esto que decir:

2.2. Personajes reservados

Los URI incluyen componentes y subcomponentes que están delimitados por caracteres en el conjunto "reservado". Estos caracteres se denominan "reservados" porque pueden (o no) estar definidos como delimitadores por la sintaxis genérica, por la sintaxis específica de cada esquema o por la sintaxis específica de la implementación del algoritmo de desreferenciación de un URI. Si los datos de un componente de URI entran en conflicto con el propósito de un carácter reservado como delimitador [énfasis agregado], entonces los datos en conflicto deben estar codificados en porcentaje antes de que se forme el URI.

   reservado = gen-delims / sub-delims

   gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"

   sub-delims = "!" PS
               / "*" / "+" / "," / ";" / "="

3.3. Componente de ruta

[...]
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
[...]

3.4 Componente de consulta

[...]
      consulta = * (pchar / "/" / "?")

Por lo tanto, las comas están explícitamente permitidas dentro de las cadenas de consulta y solo necesitan escaparse en los datos si esquemas específicos lo definen como un delimitador. El esquema HTTP no utiliza la coma o el punto y coma como delimitador en las cadenas de consulta, por lo que no es necesario escapar. Si los navegadores siguen este estándar es otro asunto.

El uso de CSV debería funcionar bien para datos de cadena, solo tiene que seguir las convenciones estándar de CSV y citar los datos o escapar de las comas con barras invertidas.

En cuanto a RFC 2396, también permite comas sin escape en cadenas de consulta HTTP:

2.2. Personajes reservados

Muchos URI incluyen componentes que consisten en, o delimitados por, ciertos caracteres especiales. Estos caracteres se denominan "reservados", ya que su uso dentro del componente URI se limita a su propósito reservado. Si los datos de un componente de URI entran en conflicto con el propósito reservado, entonces los datos en conflicto deben escaparse antes de formar el URI.

Dado que las comas no tienen un propósito reservado bajo el esquema HTTP, no tienen que escaparse en los datos. La nota del § 2.3 acerca de que los caracteres reservados son aquellos que cambian la semántica cuando están codificados en porcentaje se aplica sólo en general; los caracteres pueden estar codificados en porcentaje sin cambiar la semántica para esquemas específicos y aún así estar reservados.

outis
fuente
23

Para responder qué es válido en una cadena de consulta, verifiqué qué caracteres especiales se reemplazan por Chrome al realizar una solicitud:

Space -> %20
! -> !
" -> %22
# -> removed, marks the end of the query string
% -> %
& -> &
' -> %27
( -> (
) -> )
* -> *
+ -> + (this usually means blank when received at the server, so encode if necessary)
, -> ,
- -> -
. -> .
/ -> /
: -> :
; -> ;
< -> %3C
= -> =
> -> %3E
? -> ?
@ -> @
[ -> [
\ -> \
] -> ]
^ -> ^
_ -> _
` -> `
{ -> {
| -> |
} -> }
~ -> ~

Extended ASCII (like °) -> Every character from this set is encoded

Nota: Eso probablemente no significa que no deba escapar caracteres que no fueron reemplazados cuando genera URI para enlaces. Por ejemplo, a menudo se recomienda no utilizar~ en URI debido a problemas de compatibilidad, pero sigue siendo un carácter válido.

Otro ejemplo sería el signo más, que es válido pero generalmente se trata como un espacio en blanco codificado cuando un servidor lo recibe como parte de una solicitud. Por lo tanto, debe codificarse incluso si es válido cuando su propósito es representar un más y no un espacio.

Entonces, para responder lo que se debe codificar: caracteres no válidos y caracteres que desea tratar literalmente pero que tienen un significado especial o pueden causar problemas en el servidor.

usuario764754
fuente
¿Es /programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b#1;c#2un parámetro de consulta válido?
Sumit Jain
@SumitJain No, porque #no puede aparecer dentro de la parte de consulta de un URI tal como está. Deberá codificarlo como %23, de modo que el URI debería ser /programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b%231;c%232.
Dai
10

Solo usa ?q=1+2+3

Estoy respondiendo aquí una cuarta pregunta :) que no se preguntó pero todo comenzó con: ¿cómo paso la lista de números a-la valores separados por comas? Me parece que el mejor enfoque es simplemente pasarlos separados por espacios, donde los espacios se codificarán en forma de URL +. Funciona muy bien, siempre que sepa que los valores de la lista no contienen espacios (algo que los números tienden a no hacerlo).

Nas Banov
fuente
Si bien esto debería ser un comentario (ya que no responde a la pregunta), gracias. +tiene aún más sentido en el caso específico de que estaba buscando usar una coma.
Gajus
6

page.html? q = 1; q = 2; q = 3

¿Es esta una URL válida?

Si. El ;está reservado, pero no por un RFC. El contexto que define este componente es la definición del application/x-www-form-urlencodedtipo de medio, que es parte del estándar HTML (sección 17.13.4.1 ). En particular, la nota disimulada escondida en la sección B.2.2 :

Recomendamos que los implementadores del servidor HTTP y, en particular, los implementadores CGI admitan el uso de ";" en lugar de "&" para evitar a los autores la molestia de escapar de los caracteres "&" de esta manera.

Desafortunadamente, muchos marcos de scripting del lado del servidor populares, incluido ASP.NET, no admiten este uso.

bobince
fuente
Entonces, si bien la ?q=1;q=2;q=3consulta es válida, es ambigua: algunos marcos del lado del servidor la leerán en el sentido { q: '1;q=2;q=3' }, otros pueden hacerlo de manera similar { q: {'1', '2', '3'}}.
Nas Banov
1
Si. Y lo que es peor, HTML5 ahora no incluye el lenguaje sobre ;, lo que significa que HTML4 y HTML5 son inconsistentes. Uf, los peligros del lenguaje no normativo en un documento de especificaciones ...
bobince
@NasBanov Y otros (por ejemplo, PHP) lo interpretarán como{ q: 3 }
Nicholas Shanks
1
@NicholasShanks - donde PHP está involucrado, ¡todas las apuestas están canceladas! :)
Nas Banov
1

Me gustaría señalar que también page.html?q=1&q=2&q=3es una URL válida. Esta es una forma completamente legítima de expresar una matriz en una cadena de consulta. La tecnología de su servidor determinará exactamente cómo se presenta.

En ASP clásico, verifica Response.QueryString("q").County luego usa Response.QueryString("q")(0)(y (1) y (2)).

Tenga en cuenta que también vio esto en su ASP.NET (creo que no fue intencionado, pero mire):

Default.aspx?a=1;a=2&b=1&a=3

Request.QueryString["a"] = "1;a=2,3"
Request.QueryString["b"] = "1"

Observe que el punto y coma se ignora, por lo que ha adefinido dos veces y obtuvo su valor dos veces, separados por una coma. El uso de todos los símbolos de unión Default.aspx?a=1&a=2&b=1&a=3dará acomo resultado "1,2,3". Pero estoy seguro de que hay un método para obtener cada elemento individual, en caso de que los elementos contengan comas. Es simplemente la propiedad predeterminada del QueryString no indexado que concatena los subvalores junto con los separadores de coma.

ErikE
fuente
1

Tuve el mismo problema. La URL que tenía hipervínculo era una URL de terceros y esperaba una lista de parámetros en formato page.html?q=1,2,3SOLAMENTE y la URL page.html?q=1%2C2%2C3no funcionó. Pude hacerlo funcionar usando javascript. Puede que no sea el mejor enfoque, pero puede consultar la solución aquí si ayuda a alguien.

barra oblicua
fuente
-3

Si está enviando los caracteres CODIFICADOS a un archivo FLASH / SWF , ¡entonces debería CODIFICAR el carácter dos veces! (debido al analizador de Flash)

T.Todua
fuente