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

Antecedentes (pregunta más abajo)

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

Entonces creo que solo 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 para ser interpretada por el recurso.

query = *uric

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

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

uric = reserved | unreserved | escaped

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

Sin embargo, esto está algo aclarado por párrafos tales como

La clase de syntax “reservada” anterior se refiere a los caracteres que están permitidos dentro de un URI, pero que no pueden permitirse dentro de un componente particular de la syntax URI genérica; se usan como delimitadores de los componentes descritos en la Sección 3.

Los personajes en el conjunto “reservado” no están reservados en todos los contextos. El conjunto de caracteres realmente reservados dentro de cualquier componente URI determinado está definido por ese componente. En general, un carácter se reserva si la semántica del URI cambia si el carácter se reemplaza con su encoding escapada US-ASCII.

Este último extracto se siente algo retrógrado, pero establece claramente que el conjunto de caracteres reservados depende del contexto. Sin embargo, 3.4 indica 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 escaparse 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 he encontrado que el RFC 1738 es particularmente interesante.

Una URL HTTP toma la forma:

http://:/?

Dentro de los componentes y , “/”, “;”, “?” están reservados. El carácter “/” se puede usar dentro de HTTP para designar una estructura jerárquica.

Lo interpreto 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 reservada realmente no me permite definir cadenas de consulta como estoy acostumbrado a haciendo por ahora.

Pregunta

Todo 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, aunque la coma se escapó. La consulta page.html?q=1,2,3 codificada convertida en page.html?q=1%2C2%2C3 funciona, pero es fea y no la esperaba. Fue entonces cuando comencé a ir a través de RFCs.

Mi primera pregunta es simple: ¿es realmente necesario codificar comas?

Mi respuesta, de acuerdo con RFC 2396: sí, de acuerdo con RFC 1738: no

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

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

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

Mi respuesta, de acuerdo con RFC 2396: no, de acuerdo con RFC 1738: no (; está reservado)

No tengo problemas para pasar csv, siempre y cuando se trate de números, pero sí corre el riesgo de tener que codificar y decodificar valores de ida y vuelta si la coma se necesita repentinamente para otra cosa. De todos modos, probé la cosa de 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 de CSV, ya que cuando pido una “A” obtengo una cadena con comas. ASP.NET ciertamente no es una implementación de referencia, pero aún no me ha decepcionado.

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

Que un personaje esté reservado dentro de un componente de URL genérico no significa que deba ser escapado cuando aparece dentro del componente o dentro de los datos en el componente. El carácter también debe definirse como un delimitador dentro de la syntax 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 generics es RFC 3986 , que tiene esto que decir:

2.2. Caracteres 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) definirse como delimitadores por la syntax genérica, por cada syntax específica del esquema o por la syntax específica de la implementación del algoritmo de desreferenciación de un URI. Si los datos de un componente de URI entrarían en conflicto con el propósito de un carácter reservado como delimitador [énfasis agregado], entonces los datos conflictivos deben estar codificados porcentualmente antes de que se forme el URI.

  reserved = gen-delims / sub-delims

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

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

3.3. Componente de camino

[…]

  pchar = sin reservas / pct-encoded / sub-delims / ":" / "@" 

[…]

3.4 Componente de consulta

[…]

  query = * (pchar / "/" / "?") 

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

Usar CSV debería funcionar bien para los datos de cadena, solo tienes que seguir las convenciones de CSV estándar y cotizar datos o escapar de las comas con barras diagonales inversas.

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

2.2. Caracteres reservados

Muchos URI incluyen componentes que consisten o están delimitados por ciertos caracteres especiales. Estos caracteres se llaman “reservados”, ya que su uso dentro del componente URI está limitado a su propósito reservado. Si los datos de un componente URI entrarían en conflicto con el propósito reservado, entonces los datos en conflicto se deben escapar antes de formar el URI.

Como las comas no tienen un propósito reservado en el esquema HTTP, no es necesario que se escapen en los datos. La nota del § 2.3 sobre los caracteres reservados son aquellos que cambian la semántica cuando el porcentaje de encoding se aplica solo en general; los caracteres pueden estar codificados porcentualmente sin cambiar la semántica para esquemas específicos y aún así ser reservados.

Para responder a lo que es válido en una cadena de consulta, verifiqué qué caracteres especiales son reemplazados 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 debe escapar de los 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 aunque sea válido cuando su propósito es representar un plus y no un espacio.

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

Solo use ?q=1+2+3

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

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

¿Es esta una URL válida?

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

Recomendamos que los implementadores de servidores HTTP y, en particular, los implementadores de CGI admitan el uso de “;” en lugar de “&” para salvar a los autores el problema de escapar de los caracteres “&” de esta manera.

Desafortunadamente, muchos frameworks populares de scripting del lado del servidor, incluido ASP.NET, no son compatibles con este uso.

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

En ASP clásico, verifique Response.QueryString("q").Count y luego use Response.QueryString("q")(0) (y (1) y (2)).

Tenga en cuenta que también vio esto en ASP.NET (creo que no fue intencionado, pero sí 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 tiene a definido dos veces, y obtiene su valor dos veces, separadas por una coma. El uso de todos los signos Default.aspx?a=1&a=2&b=1&a=3 símbolos Default.aspx?a=1&a=2&b=1&a=3 arrojará a como “1,2,3”. Pero estoy seguro de que hay un método para obtener cada elemento individual, en caso de que los elementos mismos contengan comas. Es simplemente la propiedad predeterminada de QueryString no indexado que concatena los subvalores junto con los separadores de coma.

Tuve el mismo problema. La URL que estaba hipervinculada era una URL de un tercero y esperaba una lista de parámetros en formato page.html?q=1,2,3 SOLAMENTE y la URL page.html?q=1%2C2%2C3 no funcionaba. Pude hacerlo funcionar usando javascript. Puede que no sea el mejor enfoque, pero puede verificar la solución aquí si ayuda a alguien.

Si está enviando los caracteres ENCODED al archivo FLASH / SWF , entonces debe CODIFICAR el carácter dos veces. (debido al analizador de Flash)