web-dev-qa-db-fra.com

Le chemin d'URL avec un point d'interrogation codé entraîne une redirection incorrecte lorsqu'il est copié dans l'URL cible

J'ai un simple RewriteRule, ajoutant une chaîne à certaines URL:

RewriteRule  ^labels/([^/]+)/?$ /labels/$1/releases/ [R=301,L,NC]

Les liens sont basés sur des bases de données, et cela fonctionne très bien. Eh bien, à part l'un d'entre eux. Le nom contient ?! à la fin, disons label?!.

Les liens générés sont corrects, à savoir:

/labels/label%3F%21

Mais la redirection est appliquée deux fois et ne considère évidemment pas le point d'interrogation codé comme faisant partie de l'URL. Le lien résultant devrait être:

/labels/label%3F%21/releases/

Mais nous obtenons à la place:

/labels/label/releases/?!/releases/

Je peux voir que la règle est effectivement appliquée deux fois, mais je suis sûr que cela peut être facilement résolu si je surmonte mon premier problème: pourquoi les réécriteurs voient-ils le %2F codé comme un délimiteur de chaîne de requête? Comment puis-je atténuer ce cas?

Merci pour tout indice!

3
DJules

Vous avez besoin du drapeau B pour échapper à la référence arrière et le NE (noescape) pour empêcher le résultat substitution (c'est-à-dire le backreference) étant doublement codé. Par exemple:

RewriteRule ^labels/([^/]+)/?$ /labels/$1/releases/ [B,NE,R=301,L,NC]

Vous devrez vider le cache de votre navigateur, car le précédent (erroné) 301 aura été mis en cache.


Pourquoi les réécriteurs voient-ils le %2F codé comme un délimiteur de chaîne de requête?

Légère faute de frappe là je pense ... tu veux dire %3F. Oui, vous obtenez 2 redirections parce que ...

  • lorsque vous demandez /labels/label%3F%21, la RewriteRulemotif correspond au chemin d'URL décodé par%, c'est-à-dire. /labels/label?!. Selon votre règle, label?! est alors copié dans la substitution, ce qui entraîne une redirection vers /labels/label?!/releases/ (le ?! ne sera pas automatiquement recodé). Quel est un chemin URL de /labels/label et une chaîne de requête de !/releases/. C'est de là que vient la chaîne de requête.

  • Sur la demande redirigée, /labels/label correspond à votre RewriteRulemotif (la chaîne de requête est ignorée à ce stade). Cette fois, label est copié dans le substitution, pour devenir /labels/label/releases/. Et ensuite, la chaîne de requête de la demande est transmise à la substitution, pour aboutir à une seconde redirection vers /labels/label/releases/?!/releases/.

Le drapeau B échappe au motif capturé. par exemple. label?! est échappé pour devenir label%3F%21.

Et le drapeau NE empêche le % d’être codé comme %25 (c’est-à-dire qu’il s’agit d’un codage doublement codé de la référence arrière). par exemple. label%3F%21 serait sinon codé en tant que label%253F%2521.

De côté: mod_rewrite ne code pas automatiquement le premier? dans le substitution car il est supposé que cela lance la chaîne de requête. Cependant, les ? suivants seront automatiquement codés. par exemple. Étant donné RewriteRule ^foo$ /bar??? [R,L], une demande de /foo entraîne une redirection vers /bar?%3f%3f (notez que les deux deuxièmes ? sont codés en URL, mais le premier ne l'est pas).

2
MrWhite