web-dev-qa-db-fra.com

Qu'est-ce qui est valide et qu'est-ce qui ne se trouve pas dans une requête URI?

Contexte (question plus bas)

Je cherchais Google dans les RFC et SO) questions pour tenter de résoudre ce problème, mais je n'ai toujours pas de prise.

Donc, je suppose que nous votons simplement pour la "meilleure" réponse et c'est tout, ou?

Fondamentalement, cela se résume à cela.

3.4. Composant de requête

Le composant de requête est une chaîne d'informations à interpréter par la ressource.

query = *uric

Dans un composant de requête, les caractères ";", "/", "?", ":", "@", "&", "=", "+", "," Et "$" sont réservés.

La première chose qui me dépasse est que * uric est défini comme ceci

uric = reserved | unreserved | escaped

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

Ceci est toutefois quelque peu clarifié par des paragraphes tels que

La classe de syntaxe "reserved" ci-dessus fait référence aux caractères autorisés dans un URI, mais pouvant ne pas l'être dans un composant particulier de la syntaxe générique d'URI; ils sont utilisés comme délimiteurs des composants décrits dans la section 3.

Les caractères du jeu "réservé" ne sont pas réservés dans tous les contextes. L'ensemble de caractères réellement réservés au sein d'un composant URI donné est défini par ce composant. En général, un caractère est réservé si la sémantique de l'URI change si le caractère est remplacé par son codage US-ASCII échappé.

Ce dernier extrait semble un peu à l’arrière, mais il est clairement indiqué que le jeu de caractères réservé dépend du contexte. Cependant, 3.4 indique que tous les caractères réservés sont réservés dans un composant de requête, cependant, la seule chose qui changerait la sémantique ici échappe au point d'interrogation (?), Car les URI ne définissent pas le concept de chaîne de requête.

À ce stade, j'ai totalement abandonné les RFC, mais le RFC 1738 est particulièrement intéressant.

Une URL HTTP prend la forme:

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

Dans les composants <path> et <searchpart>, "/", ";", "?" sont réservés. Le caractère "/" peut être utilisé dans HTTP pour désigner une structure hiérarchique.

J'interprète cela du moins en ce qui concerne les URL HTTP que la RFC 1738 remplace la RFC 2396. Comme la requête URI n'a aucune notion de chaîne de requête, l'interprétation de reserved ne me permet pas vraiment de définir des chaînes de requête comme je suis habitué à le faire. faire maintenant.

Question

Tout cela a commencé lorsque je voulais transmettre une liste de numéros avec la demande d'une autre ressource. Je n'y ai pas beaucoup réfléchi et je l'ai simplement passé sous forme de valeurs séparées par des virgules. À ma grande surprise, la virgule s'est échappée. La requête page.html?q=1,2,3 encodé transformé en page.html?q=1%2C2%2C3 ça marche, mais c'est moche et je ne m'y attendais pas. C'est à ce moment que j'ai commencé à passer en revue les RFC.

Ma première question est simplement la suivante: le codage par des virgules est-il vraiment nécessaire?

Ma réponse, selon RFC 2396: oui, selon RFC 1738: non

Plus tard, j'ai trouvé des articles sur le passage de listes entre les demandes. Où l'approche CSV était posée comme aussi mauvaise. Ceci est apparu à la place, (je n'ai jamais vu ça auparavant).

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

Ma deuxième question, est-ce une URL valide?

Ma réponse, selon RFC 2396: non, selon RFC 1738: non (; est réservé)

Je n'ai aucun problème à transmettre csv tant que ce sont des nombres, mais oui, vous courez le risque de devoir encoder et décoder des valeurs dans les deux sens si la virgule est soudainement nécessaire pour autre chose. Quoi qu'il en soit, j'ai essayé la chaîne de requête point-virgule avec ASP.NET et le résultat n'était pas ce à quoi je m'attendais.

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

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

Je ne vois pas en quoi cela diffère grandement de l'approche csv, car lorsque je demande "a", je reçois une chaîne avec des virgules. ASP.NET n’est certainement pas une implémentation de référence, mais il ne m’a pas encore laissé tomber.

Mais plus important encore - ma troisième question - où est la spécification pour cela? et que feriez-vous ou ne feriez-vous pas?

90
John Leidegren

Qu'un caractère soit réservé dans un composant URL générique ne signifie pas qu'il doit être échappé lorsqu'il apparaît dans le composant ou dans les données du composant. Le caractère doit également être défini en tant que délimiteur dans la syntaxe générique ou spécifique au schéma, et l'apparence du caractère doit être comprise dans les données.

La norme actuelle pour les URI génériques est RFC 3986 , ce qui signifie:

2.2. Caractères réservés

Les URI incluent des composants et des sous-composants délimités par des caractères du jeu "réservé". Ces caractères sont appelés "réservés" car ils peuvent (ou non) être définis comme des délimiteurs par la syntaxe générique, par chaque syntaxe spécifique au schéma ou par la syntaxe spécifique à l'implémentation de l'algorithme de déréférencement d'un URI. Si les données d'un composant URI sont en conflit avec le but du caractère réservé en tant que délimiteur [italiques ajoutés], les données en conflit doivent être codées pour cent avant le L'URI est formé.

   reserved = gen-delims/sous-delims 
 
 gen-delims = ":"/"/"/"?"/"#"/"["/"]"/"@" 
 
 sub-delims = "!"/"$"/"&"/"'"/"("/")" 
/"*"/"+"/","/";"/"="

.3. Composant de chemin

[...]
pchar = non réservé/pct-encodé/sous-delims/":"/"@"
[...]

Composant de requête 3.4

[...]
      requête = * (pchar/"/"/"?")

Ainsi, les virgules sont explicitement autorisées dans les chaînes de requête et ne doivent être échappées dans les données que si des schémas spécifiques le définissent comme un délimiteur. Le schéma HTTP n'utilise pas la virgule ou le point-virgule comme délimiteur dans les chaînes de requête, elles n'ont donc pas besoin d'être échappées. Que les navigateurs suivent cette norme est une autre affaire.

L'utilisation de CSV devrait bien fonctionner pour les données de chaîne. Il vous suffit de suivre les conventions CSV standard et de citer des données ou d'échapper les virgules avec des barres obliques inverses.

Quant à la RFC 2396, elle permet également d’utiliser des virgules sans écartement dans les chaînes de requête HTTP:

2.2. Caractères réservés

De nombreux URI incluent des composants constitués de, ou délimités par, de certains caractères spéciaux. Ces caractères sont appelés "réservés", car leur utilisation dans le composant URI est limitée à leur fonction réservée. Si les données d'un composant URI sont en conflit avec l'objectif réservé, les données en conflit doivent être évitées avant de former l'URI.

Étant donné que les virgules n'ont pas d'objet réservé dans le schéma HTTP, il n'est pas nécessaire de les échapper dans les données. La note du § 2.3 sur les caractères réservés étant ceux qui changent de sémantique lorsque le codage en pourcentage s'applique uniquement en général; les caractères peuvent être codés en pourcentage sans changer de sémantique pour des schémas spécifiques tout en restant réservés.

64
outis

Pour répondre aux critères de validité d'une chaîne de requête, j'ai vérifié quels caractères spéciaux étaient remplacés par chrome lors d'une requête:

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

Remarque: Cela ne signifie probablement pas que vous ne devriez pas échapper aux caractères qui n'ont pas été remplacés lorsque vous générez des URI pour les liens. Par exemple, il est souvent recommandé de ne pas utiliser ~ dans les URI en raison de problèmes de compatibilité, mais ce caractère est toujours valide.

Un autre exemple serait le signe plus qui est valide mais généralement traité comme un blanc codé lorsqu'un serveur le reçoit dans le cadre d'une requête. Ainsi, il devrait être encodé même s'il est valide lorsqu'il a pour but de représenter un plus et non un espace.

Donc, pour répondre à ce qui devrait être encodé: Caractères non valides et que vous voulez traiter littéralement mais qui ont une signification spéciale ou qui peuvent causer des problèmes au niveau du serveur.

18
user764754

Il suffit d'utiliser ?q=1+2+3

Je réponds ici à une quatrième question :) qui n'a pas été posée mais qui a commencé par: comment puis-je passer une liste de nombres séparés par des virgules? Il me semble que la meilleure approche consiste simplement à les passer séparés, où les espaces seront encodés sous forme de URL en +. Fonctionne très bien, tant que vous savez que les valeurs dans la liste ne contiennent aucun espace (quelque chose que les chiffres ont tendance à ne pas).

10
Nas Banov

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

est-ce une URL valide?

Oui. Le ; est réservé, mais pas par une RFC. Le contexte qui définit ce composant est la définition du application/x-www-form-urlencoded type de média, qui fait partie de la norme HTML (section 17.13.4.1 ). En particulier la note sournoise cachée dans la section B.2.2 :

Nous recommandons aux développeurs du serveur HTTP, et en particulier aux développeurs de CGI, de prendre en charge l'utilisation de ";" à la place de "&" pour épargner aux auteurs le problème d'échapper aux "&" caractères de cette manière.

Malheureusement, de nombreux frameworks de script côté serveur, notamment ASP.NET, ne prennent pas en charge cette utilisation.

6
bobince

Je voudrais noter que page.html?q=1&q=2&q=3 Est aussi une URL valide. C'est une manière tout à fait légitime d'exprimer un tableau dans une chaîne de requête. La technologie de votre serveur déterminera comment exactement cela est présenté.

En ASP classique, cochez Response.QueryString("q").Count puis utilisez Response.QueryString("q")(0) (et (1) et (2)).

Notez que vous avez également vu cela dans votre ASP.NET (je pense que ce n'était pas prévu, mais regardez):

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

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

Notez que le point-virgule est ignoré, vous avez donc a défini deux fois et vous obtenez sa valeur deux fois, séparées par une virgule. L'utilisation de toutes les esperluettes Default.aspx?a=1&a=2&b=1&a=3 Donnera a comme "1,2,3". Mais je suis sûr qu'il existe une méthode pour obtenir chaque élément individuel, au cas où les éléments eux-mêmes contiennent des virgules. Il s'agit simplement de la propriété par défaut de QueryString non indexé qui concatène les sous-valeurs avec des séparateurs de virgule.

1
ErikE

J'ai eu le même problème. L’URL qui faisait l’objet d’un lien hypertexte était une URL tierce et attendait une liste de paramètres au format page.html?q=1,2,3 SEULEMENT et l'URL page.html?q=1%2C2%2C3 n'a pas fonctionné. J'ai pu le faire fonctionner en utilisant javascript. Peut-être pas la meilleure approche mais peut vérifier la solution ici si cela aide quelqu'un.

1
slash