Mutilating the Query

19

Je sais que vous avez toujours pensé aux épreuves et aux tribulations de l'expérience des joies de la vie en tant que proxy Web. Honnêtement, qui ne l'a pas fait? Aujourd'hui, vous êtes chargé de réaliser cet objectif (au moins une partie de celui-ci). Le site Web X reçoit beaucoup de trafic quotidiennement et recherche un PaaS (il s'agit clairement de Proxy as a Service) en raison du grand nombre d'utilisateurs qui insistent pour transmettre des informations sensibles via des paramètres de requête (les utilisateurs sont stupides). Votre tâche consiste à supprimer tous les paramètres de requête sensibles de la demande avant de transmettre la demande à sa destination d'origine.

Contribution

  • Une URL HTTP absolue bien formée qui suit la grammaire URI de la section 3 de la RFC3986 .
    • Vous pouvez supposer qu'il n'y a pas de fragment
    • Exemple de format bref où quelque chose entre crochets indique facultatif: http[s]://[user:pass@]host.name.com[:port]/[?param1=value1&param2=value2...]
  • Une liste des paramètres de requête à supprimer.

Production

L'URL HTTP modifiée sans les paramètres définis dans la liste d'entrée.

Exemples

http://example.com/ [foo]
> http://example.com/

http://example.com/?foo=bar []
> http://example.com/?foo=bar

http://example.com/ []
> http://example.com/

http://example.com/?foo=1&bar=2&baz=3 [foo,baz]
> http://example.com/?bar=2

http://example.com/?foo=1&bar=2&baz=3 [foo,bar,baz]
> http://example.com/

http://example.com/?foo&bar=2&baz= [foo,baz]
> http://example.com/?bar=2

http://example.com/?abc=1&def=2&baz=foo [foo,bar]
> http://example.com/?abc=1&def=2&baz=foo

http://example.com/?foobar=baz [foo]
> http://example.com/?foobar=baz

http://foo:[email protected]:8080/?foo=1&bar=foo [foo]
> http://foo:[email protected]:8080/?bar=foo

Notation

Il s'agit de , donc la réponse la plus courte (en octets) l'emporte.

Poussée
la source
1
Puis-je obtenir l'URL et les paramètres de requête chacun sur des lignes distinctes?
seshoumara
1
Peut &apparaître ailleurs qu'entre les paramètres?
Riley
le mot de passe peut-il également contenir un ?? La commande doit-elle également être conservée telle quelle?
KarlKastor
@Riley No. Si &fait partie d'un paramètre de requête, il doit être correctement encodé comme%26
Poke
1
Apparemment, http://foo:&[email protected]:8080/?foo=1&bar=fooest autorisé par le RFC. Cela devrait casser un tas de solutions existantes. : D (La règle est que userinfo peut être développé comme non réservé ou pct-escape ou sous-délimités, et les sous-délimitations peuvent avoir &et =)
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Réponses:

6

GNU sed 98 96 88 80 77 74 69 59 54 (48 + 1 pour -r) 49

:;s,(.+)(=[^&]*[& ]|&)(.*)\1,\3 ,
t;s,[?&]? .*,,

La liste des paramètres à supprimer est séparée par des espaces.

$ echo 'http://example.com/?foo=1&bar=2&baz=3 foo bar baz' | sed -rf sed.txt
http://example.com/

$ echo 'http://example.com/?foo&bar=2&baz= foo baz' | sed -rf sed.txt
http://example.com/?bar=2

$ echo 'http://example.com/' | sed -rf sed.txt
http://example.com/
Riley
la source
Dans votre édition de code actuelle, plusieurs tests de la question de OP donnent une fin &ou un ?caractère dans l'URL résultante.
seshoumara
@seshoumara Je ne sais pas comment j'ai raté ça ... Heureusement, ce n'est qu'une différence de 1 octet.
Riley
Les versions de code à 96, 77 et 59 octets ne figurent pas dans votre historique des modifications. Le titre de l'édition 7 montrait 10 octets de moins par rapport à l'édition 6, mais le code n'avait pas été modifié. Je suis tatillonne cependant, super golf!
seshoumara
1
@seshoumara Je pense que cela a combiné certaines des modifications car elles étaient mineures (juste la suppression de quelques caractères).
Riley
@seshoumara Je suppose que cela les a en fait combinés car j'ai effectué plusieurs modifications à moins de 5 minutes les unes des autres.
Riley
5

JavaScript (ES6), 62 60 octets

f=
(s,a,u=new URL(s))=>a.map(e=>u.searchParams.delete(e))&&''+u
;
s.value=document.URL;
<div oninput=o.textContent=f(s.value,a.value.split`\n`)><input id=s><br><textarea id=a></textarea><pre id=o>

Edit: sauvé 2 octets grâce à @Shaggy.

Neil
la source
Vous pouvez économiser 5 octets en supprimant le .hrefà la fin.
Shaggy
@Shaggy Cela ne retournerait pas une chaîne ... Je supposais que ce n'était pas autorisé.
Neil
Cela dépend de la façon dont vous le sortez. Par exemple, si vous l' alertutilisez ou l'insérez dans un nœud (texte), comme vous l'avez fait, cela vous donnera la hrefpropriété de l'objet. Si vous le connectez à la console, cependant, cela vous donnera l'objet complet. Voir ce violon .
Shaggy
1
@Shaggy Ah, donc je peux certainement économiser 2 octets en le stringant, merci.
Neil
3

PHP, 90 octets

<?=trim(preg_replace("#(?<=\?|&)(".join("|",$_GET[r]).")(=.*)?(&|$)#U","",$_GET[u]),"?&");

-11 octets si? ou & est autorisé à la fin

Version précédente 140 octets

<?=substr($u=$_GET[u],0,strpos($u,"?")+!!$j=join("&",preg_grep("#^(".join("|",$_GET[r]).")(=|$)#",explode("&",parse_url($u)[query]),1))).$j;
Jörg Hülsermann
la source
+2 octets: les alternatives doivent être entre parenthèses, ou ^/ (.*|$)fera partie de la première / dernière alternative.
Titus
-2 octets: supprimer .*. ou remplacez (=.*|$)par \b(-5).
Titus
Votre expression rationnelle ressemblera à celle #^foo|bar(=.*|$)#qui est identique à #(^foo)|(bar=.*|bar$))#. Mais ça devrait l'être #(foo|bar)(=.*|$)#.
Titus
@Titus Vous avez raison de ma faute
Jörg Hülsermann
agréable! Je n'ai pas pensé aux affirmations; c'est pourquoi je suis retombé array_map(et j'ai été surpris de voir à quel point cela peut se révéler).
Titus
2

PHP, 120 110 octets

avec les fonctions preg_replace et array: (inspiré par Jörg )

<?=preg_replace(array_map(function($s){return"#(\\?|&)$s(=.*)?(&|$)#U";},array_slice($argv,2)),"\1",$argv[1]);

enregistrer dans un fichier, appeler avec php <scriptname> <uri> <parametername> <parametername> ...

avec parse_str et http_build_query (120 octets):

parse_str(end($u=explode('?',$argv[1])),$a);for($i=$argc;$i-->1;)unset($a[$argv[$i]]);echo"$u[0]?".http_build_query($a);

courir avec php -r <code> <uri> <parametername> <parametername> ...

Titus
la source
parse_str? http_build_query? Je suis tellement heureux de voir quelqu'un travailler avec les bons outils pour le travail, même dans le golf de code. Les bogues qui surviennent parce que les requêtes URL / SQL / regexp / HTML ne sont "que des chaînes" sont aussi nombreux qu'ils sont facilement évitables.
Daerdemandt
Peut-être pour plus d'inspiration. Je t'ai eu
Jörg Hülsermann
@Lynn Tu n'as rien de mieux à faire que de me traquer?
Titus
2

Java 7, 127 octets

String a(String a,String[]b){for(String c:b)a=a.replaceAll("(?<=[?&])"+c+"(=[^&]*)?(&|$)","");return a.replaceAll("[?&]$","");}

Explication

String sanitize(String url, String[] params) {
    for (String param : params) {
        // please don't modify function parameters in real code
        url=url.replaceAll("(?<=[?&])" // Look for a leading ? or & but don't consume it
            + param                    // Consume the key of the query param (assuming key=value syntax)
            + "(=[^&]*)?"              // Consume the value of the query param if it exists
            + "(&|$)","");             // Consume the trailing & unless we're at the end of the url and replace with nothing
    }
    url = url.replaceAll("[?&]$",""); // If we remove all of the params then we'll have a trailing ? which needs to be removed
                                      // If we remove the last param only then we could have a trailing & which also needs to be removed
                                      // We will only run into one of these scenarios
    return url;
}

Ideone

Poussée
la source
Cela échoue pour moi en utilisant vos 4e, 5e, 6e et 9e exemples oO J'utilise Java 8, donc ça pourrait être ça. Bien essayé l'équivalent C # et il a échoué les mêmes cas, donc idunno.
Yodle
1
Peu importe, j'ai gâché la façon dont je le testais.
Yodle
2

C #, 377 336 330 328 octets (173 alt)

string n(string u,string[]r){var s=u.Split('?');if(s.Length<2)return u;var a=s[1].Contains("&")?s[1].Split('&'):new string[]{s[1]};int B=a.Length,i=0,C=i,c=B;for(;i<B;i++)foreach(var R in r)if(R==a[i].Split('=')[0]){a[i]="";c--;}var t=s[0];t+=c>0?"?":"";for(i=0;i<a.Length;i++)if(a[i]!=""){t+=a[i];C++;if(C!=c)t+="&";}return t;}

Programme complet non golfé:

using System;
class a
{
    static void Main()
    {
        string input = Console.ReadLine();
        string url = input.Split(' ')[0];
        string r = input.Split(' ')[1];
        r = r.Replace("[", "").Replace("]","");
        string[] remove = r.Split(',');
        a b = new a();
        Console.WriteLine(b.n(url, remove));
    }
    string n(string u,string[]r)
    {
        var s=u.Split('?');
        if(s.Length<2)return u;
        var a=s[1].Contains("&")?s[1].Split('&'):new string[]{s[1]};
        int B=a.Length,i=0,C=i,c=B;
        for(;i<B;i++)
            foreach(var R in r)
                if(R==a[i].Split('=')[0])
                {
                    a[i]="";
                    c--;
                }
        var t=s[0];
        t+=c>0?"?":"";
        for(i=0;i<a.Length;i++)
            if(a[i]!="")
            {
                t+=a[i];
                C++;
                if (C!=c)t+="&";
            }
        return t;
    }
}

Probablement pas très efficace, mais ça marche je pense.

Alternativement, il existe une solution de 173 octets utilisant la méthode @ Poke de Java. Nécessite une importation pour Regex, donc ne peut probablement pas être plus court.

using System.Text.RegularExpressions;string m(string a,string[]b){foreach(var c in b)a=Regex.Replace(a,$"(?<=[?&]){c}(=[^&]*)?(&|$)","");return Regex.Replace(a,"[?&]$","");}
Yodle
la source
2

Rubis, 146 140 127 119 119 116 113 octets

edit 2: enregistré 6 octets en utilisant $1, $2, et $*, et 7 en changeant x.split("=")[0]pour x[/\w+/]
modifier 3: enregistré 6 octets en utilisant à la *place de .join, économisé 2 octets à partir d' espaces inutiles
modifier 4: enregistré 3 octets en reformulant ligne (regex changé en équivalent $*[1][/([^?]*)\??(.*)/,1]et mis comme assigné à a)
modifier 5: enregistré 3 octets en utilisant ($*[2].scan(r=/\w+/)&[x[r]])[0]au lieu de$*[2].scan(r=/\w+/).include?(x[r])

En supposant une entrée dans le programme lors de son exécution:

a,b=$*[1][/([^?]*)\??(.*)/,1],$2.split("&").reject{|x|($*[2].scan(r=/\w+/)&[x[r]])[0]}*"&"
puts(b[0] ?a+"?"+b: a)

Explication

a,b=$*[1][/([^?]*)\??(.*)/,1],$2.split("&")

Cela analyse l'URL indiquée sur la ligne de commande et stocke les correspondances dans $1et $2. $*[1][/([^?]*)\??(.*)/,1]renvoie également la première correspondance à stocker à l'intérieur a, tandis que la deuxième correspondance est appelée $2 laisser un point à 1 $ et analyser bdans un tableau de tableaux ...

.reject { |x|

... rejetant tout cela ...

    ($*[2].scan(r=/\w+/)&[x[r]])[0]

... avoir une chaîne avant le '=' qui est incluse dans la liste des noms donnée par le deuxième paramètre ... Cela fonctionne parce que nous recherchons des mots (pour obtenir la liste) puis obtenons le mot avant le =, et voyons si ce mot est dans la liste avec &. Puisque &renvoie un tableau vide sur "non trouvé" (l'ensemble nul), nous utilisons l'astuce expliquée ci-dessous pour savoir nils'il n'y a aucun élément dans le tableau. sinon, nous renvoyons une chaîne, qui compte comme véridique, qui rejette cette chaîne.

}*"&"

... et joignez les chaînes restantes avec '&'

À ce stade, best la chaîne de requête GET pour l'URL. Il suffit donc de l'imprimer.

puts(b[0] ?a+"?"+b: a)

Cela utilise une astuce en rubis. b[0]sera nilsi b est un tableau ou une chaîne vide. Donc, si c'est vrai , (pas nilou false), alors il y a au moins un élément dans le tableau, nous devons donc mettre a+"?"+bl'URL correcte. sinon, on met juste a, car il n'y a pas de paramètres à afficher

Remarque: cette réponse suppose qu'il ? ne peut apparaître nulle part, sauf pour délimiter l'URL de la requête. (selon ce que j'ai lu du RFC lié)

Aussi, ceci est ma première réponse de golf: D

Nerketur Kamachi
la source
2
Bienvenue chez PPCG!
acrolith
1

Pip , 46 octets

Prend l'URL de stdin et les paramètres de requête à supprimer des arguments de ligne de commande.

YgqR`\?.+`{s:J_@`^[^=]+`NIyFI@>a^'&[s&'?sJ'&]}

Essayez-le en ligne!

Explication:

 g               Local variable containing list of cmdline args
Y                Yank into global variable y so it's available inside the function
  q              Grab a line of stdin
   R`\?.+`{...}  Do a regex replace of everything from ? on, using a callback function:

s:J_@`^[^=]+`NIyFI@>a^'&[s&'?sJ'&]
                  @>a^'&            All but 1st char of match, split on &
                FI                  Filter on this function:
   _@`^[^=]+`                         Regex match: run of non = from beginning of string
                                      @ returns a list (here, of one item), so...
  J                                   Join to get a scalar
             NIy                      True if match not in y; false if in y
s:                                  Assign the filtered list to s
                        [        ]  Return a list containing:
                         s&'?       ? if s is nonempty, [] otherwise
                             sJ'&   s joined on &
                                    When used as a replacement, a list is first stringified
                                    (which, in the absence of flags, means concatenated)
DLosc
la source
1

PowerShell v3 +, 115 90 octets

param($n,$z)$a,$b=$n-split'\?';($z|%{$b=$b-replace"(^|&)$_(=[^&]*)?(&|$)"});$a+"?"*!!$b+$b

Prend l'entrée $ncomme URL et $zcomme un tableau littéral de chaînes comme paramètres à supprimer. -splits l'URL d'entrée ?, stocke la première moitié dans $aet la seconde dans $b.

Ensuite, $best reformulé en effectuant une boucle $z, en effectuant une expression régulière -replacesur chaque mot de requête interdit pour les supprimer. Ensuite, les sorties $a(non modifiées), plus un /selon qu'il $bexiste, plus un ?selon qu'il $xexiste, plus `$ x.

AdmBorkBork
la source
1

Pyth - 27 octets

Kenny avait raison quand il a parlé de l'intégration pour transformer puis inverser, il sera très difficile de redresser, cependant.

.sjK\?mj\&f!}hcT\=Qcd\&czKK

Suite de tests .

Maltysen
la source
1

Rétine , 44 48 octets

Barré 44 est toujours 44. Merci à Martin pour le correctif.

[?&](?>([^ =&]+))[^ &]*(?=.* \1( |$))| .*

/&
/?

Prend l'entrée comme uri param1 param2.Essayez-le en ligne!

Explication

Le premier remplacement supprime les paramètres appropriés de la chaîne de requête. [?&](?>([^ =&+))[^ &]*correspond à un ?ou à &un nom de paramètre complet et (éventuellement) =et à une valeur, stockant le nom du paramètre dans le groupe de capture 1. Puis(?=.* \1( |$)) un indicateur de recherche vérifie si ce nom de paramètre apparaît dans la liste des paramètres à supprimer. Si un paramètre correspond à ces conditions, il est supprimé (remplacé par un remplacement vide).

Les substitutions ne se chevauchent pas (grâce à l'anticipation) et se déroulent de gauche à droite. À la fin de l'URL, la .*branche correspond à la liste des paramètres à supprimer et la supprime également.

Le deuxième remplacement s'assure simplement que la nouvelle chaîne de requête commence par ?si le premier paramètre a été supprimé.

DLosc
la source
Je pense que cela supprime également les paramètres si un préfixe d'entre eux apparaît dans la liste à la fin (par exemple, essayez retina.tryitonline.net/… ). Une façon de résoudre ce problème consiste à envelopper le groupe 1 po (?>...).
Martin Ender
@MartinEnder TIL sur les sous-expressions sans retour arrière. Merci!
DLosc
0

Java 7, 203 octets

String f(String u,List p)throws Exception{String[]g=u.split("\\?",2);String s="";if(g.length>1)for(String q:g[1].split("&")){if(p.indexOf(q.split("=")[0])<0){s+=s.isEmpty()?"?":"&";s+=q;}}return g[0]+s;}

Non golfé:

  String f(String u, List p) throws Exception {
    String[] g = u.split("\\?", 2);
    String s = "";
    if (g.length > 1) for (String q : g[1].split("&")) {
      if (p.indexOf(q.split("=")[0]) < 0) {
        s += s.isEmpty() ? "?" : "&";
        s += q;
      }
    }
    return g[0] + s;
  }

Cette fonction réussit tous les tests.

acrolithe
la source
0

Python, 75 81 112 octets:

def Z(A,S):import re;F=A.rindex('/');print A[:F]+re.sub('|'.join(i+'(=\d?|&)&?'for i in S),'',A[F:]).strip('&?')

Une fonction nommée. Prend entrée au format

D(<String>,<Array>)

et sort une chaîne.

Repl.it avec tous les cas de test!

R. Kap
la source
0

PHP, pas en compétition

Heck, PHP a été fait pour cela; pourquoi ne pas utiliser l'URL réelle?

<?foreach($_GET[x]as$w)unset($_GET[$w]);
echo http,s[$_SERVER[SERVER_PORT]-443],"://",
$u=$_SERVER[PHP_AUTH_USER],($p=$_SERVER[PHP_AUTH_PW])?":$p":"","@"[!$u&!$p],
"$_SERVER[HTTP_HOST]$_SERVER[SCRIPT_NAME]?",http_build_query($_GET);

Enregistrer dans un fichier, appeler avec la chaîne de requête souhaitée plus &x[]=x&x[]=<exclude1>&x[]=<exclude2>&... .

Peut échouer sur le nom d'utilisateur et le mot de passe (selon que votre navigateur les supprime ou non).
Est-ce que l' échec si le mot de passe est 0.

Titus
la source