Die Abfrage verstümmeln

19

Ich weiß, Sie haben immer über die Strapazen nachgedacht, die es mit sich bringt, als Web-Proxy die Freuden des Lebens zu erleben. Ehrlich gesagt, wer hat das nicht? Heute haben Sie die Aufgabe, dieses Ziel zu erreichen (zumindest einen Teil davon). Website X erhält täglich viel Verkehr und sucht aufgrund der großen Anzahl von Benutzern, die darauf bestehen, vertrauliche Informationen über Abfrageparameter weiterzugeben (Benutzer sind albern), nach einem PaaS (dies bezieht sich eindeutig auf Proxy als Dienst). Ihre Aufgabe ist es, alle vertraulichen Abfrageparameter aus der Anforderung zu entfernen, bevor Sie die Anforderung an das ursprüngliche Ziel weiterleiten.

Eingang

  • Eine wohlgeformte absolute HTTP-URL, die der URI-Grammatik in RFC3986, Abschnitt 3 , folgt .
    • Sie können davon ausgehen, dass es kein Fragment gibt
    • Kurzes Formatbeispiel, in dem alles in eckigen Klammern als optional gekennzeichnet ist: http[s]://[user:pass@]host.name.com[:port]/[?param1=value1&param2=value2...]
  • Eine Liste der zu entfernenden Abfrageparameter.

Ausgabe

Die geänderte HTTP-URL ohne die in der Eingabeliste definierten Parameter.

Beispiele

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

Wertung

Das ist , also gewinnt die kürzeste Antwort (in Bytes).

Sack
quelle
1
Kann ich die URL und die Abfrageparameter jeweils in separaten Zeilen abrufen?
Seshoumara
1
Kann &irgendwo anders als zwischen Parametern erscheinen?
Riley
Kann zB das Passwort auch ein ?? Sollte die Bestellung auch so bleiben, wie sie war?
KarlKastor
@ Riley Nein. Wenn &es Teil eines Abfrageparameters ist, sollte er korrekt urlencodiert sein als%26
Poke
1
Anscheinend http://foo:&[email protected]:8080/?foo=1&bar=fooist das nach dem RFC erlaubt. Dies sollte einen Haufen bestehender Lösungen zerstören. : D (Die Regel ist, dass Benutzerinformationen als nicht reserviert oder pct-Escape oder Sub-Delims erweitert werden können und Sub-Delims haben können &und =)
n̴̖̋h̴̖̋ã̷͉h̷̭̿d̸̡̅ẗ̵̨́

Antworten:

6

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

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

Die Liste der zu entfernenden Parameter wird durch Leerzeichen getrennt.

$ 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
quelle
In Ihrer aktuellen Code-Bearbeitung geben mehrere Tests aus der Frage von OP einen Schluss &oder ein ?Zeichen in der resultierenden URL an.
Seshoumara
@seshoumara Ich bin nicht sicher, wie ich das verpasst habe ... Zum Glück ist es nur ein 1-Byte-Unterschied.
Riley
Die 96-, 77- und 59-Byte-Codeversionen wurden in Ihrem Bearbeitungsverlauf nicht gefunden. Der Titel von Edit 7 zeigte 10 Bytes weniger als Edit 6, aber der Code wurde nicht geändert. Ich bin zwar ein Trottel, tolles Golfen!
Seshoumara
1
@seshoumara Ich denke, es hat einige der Änderungen zusammengefasst, weil sie geringfügig waren (nur ein paar Zeichen löschen).
Riley
@seshoumara Ich denke, es hat sie tatsächlich kombiniert, weil ich innerhalb von 5 Minuten mehrere Änderungen vorgenommen habe.
Riley
5

JavaScript (ES6), 62 - 60 Byte

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>

Bearbeiten: 2 Bytes dank @Shaggy gespeichert.

Neil
quelle
Sie können 5 Bytes sparen, indem Sie das .hrefam Ende löschen .
Shaggy
@ Shaggy Das würde keinen String zurückgeben ... Ich nahm an, dass das nicht erlaubt war.
Neil
Es hängt davon ab, wie Sie es ausgeben. Wenn Sie alertes beispielsweise verwenden oder in einen (Text-) Knoten einfügen, erhalten Sie die hrefEigenschaft des Objekts. Wenn Sie es jedoch in der Konsole protokollieren, erhalten Sie das vollständige Objekt. Sehen Sie diese Geige .
Shaggy
1
@ Shaggy Ah, also kann ich definitiv 2 Bytes sparen, indem ich es stringiere, danke.
Neil
3

PHP, 90 Bytes

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

-11 Bytes wenn? oder & ist am Ende erlaubt

Vorherige Version 140 Bytes

<?=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
quelle
+2 Bytes: Die Alternativen müssen in Klammern gesetzt werden, oder ^/ (.*|$)wird Teil der ersten / letzten Alternative.
Titus
-2 Bytes: entfernen .*. oder ersetzt (=.*|$)mit \b(-5).
Titus
Ihr regulärer Ausdruck sieht so aus #^foo|bar(=.*|$)#, als wäre er identisch mit #(^foo)|(bar=.*|bar$))#. Aber es sollte so sein #(foo|bar)(=.*|$)#.
Titus
@ Titus Du hast Recht, meine Schuld
Jörg Hülsermann
nett! An Behauptungen habe ich nicht gedacht; Deshalb bin ich auf zurückgefallen array_map(und ich war überrascht, wie kurz es werden kann).
Titus
2

PHP, 120 bis 110 Bytes

mit preg_replace und array Funktionen: (inspiriert von Jörg )

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

In Datei speichern, mit anrufen php <scriptname> <uri> <parametername> <parametername> ...

mit parse_str und http_build_query (120 Bytes):

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

renn mit php -r <code> <uri> <parametername> <parametername> ...

Titus
quelle
parse_str? http_build_query? Ich bin so froh, jemanden zu sehen, der mit den richtigen Werkzeugen für den Job arbeitet, sogar im Code-Golf. Fehler, die auftreten, weil URL / SQL-Abfrage / Regexp / HTML "nur Zeichenfolgen" sind, sind so zahlreich wie sie leicht vermeidbar sind.
Daerdemandt
Vielleicht für mehr Inspiration. Ich hab dich
Jörg Hülsermann
@Lynn Hast du nichts Besseres zu tun, als mich zu verfolgen?
Titus
2

Java 7, 127 Bytes

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

Erläuterung

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

Sack
quelle
Dies schlägt fehl, wenn ich das vierte, fünfte, sechste und neunte Beispiel verwende. Ich verwende jedoch Java 8, das könnte es also sein. Obwohl versucht, das C # -Äquivalent und es schlug fehl, die gleichen Fälle, so idunno.
Yodle
1
Egal, ich habe es durcheinander gebracht, wie ich es getestet habe.
Yodle
2

C #, 377 336 330 328 bytes (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;}

Ungolfed volles Programm:

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;
    }
}

Wahrscheinlich nicht sehr effizient, aber es funktioniert, denke ich.

Alternativ gibt es eine 173-Byte-Lösung mit der @ Poke-Methode von Java. Erfordert jedoch einen Import für Regex, kann also wahrscheinlich nicht kürzer sein.

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

Ruby, 146 140 127 119 116 113 Bytes

edit 2: speichere 6 Bytes mit $1, $2und $*und 7 durch Ändern x.split("=")[0]in x[/\w+/]
edit 3: speichere 6 Bytes mit *statt mit .join, speichere 2 Bytes aus unnötigen Leerzeichen
edit 4: speichere 3 Bytes durch Neuformulieren von Inline (Regex geändert in Äquivalent $*[1][/([^?]*)\??(.*)/,1]und Put wie zugewiesen a)
edit 5: speichere 3 Bytes mit ($*[2].scan(r=/\w+/)&[x[r]])[0]anstelle von$*[2].scan(r=/\w+/).include?(x[r])

Angenommen, Sie geben beim Ausführen des Programms Folgendes ein:

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

Erläuterung

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

Dadurch wird die in der Befehlszeile angegebene URL analysiert und die Übereinstimmungen in $1und gespeichert $2. $*[1][/([^?]*)\??(.*)/,1]gibt auch die erste Übereinstimmung zurück, die gespeichert werden soll a, während die zweite Übereinstimmung als $2 let a point to $ 1 bezeichnet wird und bin ein Array von Arrays zerlegt wird ...

.reject { |x|

... das alles ablehnen ...

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

... einen String vor dem '=' haben, der in der Liste der durch den zweiten Parameter angegebenen Namen enthalten ist ... Dies funktioniert, weil wir nach Wörtern suchen (um die Liste zu erhalten) und dann das Wort vor dem =abrufen und nachsehen, ob Dieses Wort ist in der Liste mit &. Da &bei "not found" (der Nullmenge) ein leeres Array zurückgegeben wird, verwenden wir den unten erläuterten Trick, um zu ermitteln, nilob das Array keine Elemente enthält. Andernfalls geben wir eine Zeichenfolge zurück, die als wahr gilt und die diese Zeichenfolge ablehnt.

}*"&"

... und verbinde die restlichen Strings mit '&'

An dieser Stelle bbefindet sich die GET-Abfragezeichenfolge für die URL. Daher müssen wir es nur drucken.

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

Dies verwendet einen Trick in Rubin. b[0]wird sein, nilwenn b ein leeres Array oder eine leere Zeichenfolge ist. Also, wenn es wahr ist , (nicht niloder false), dann gibt es mindestens ein Element im Array, also müssen wir a+"?"+bfür die richtige URL setzen. Ansonsten setzen wir einfach a, weil es keine Parameter gibt, die angezeigt werden könnten

Hinweis: Bei dieser Antwort wird davon ausgegangen, dass ? sie nur zur Begrenzung der URL in der Abfrage angezeigt wird. (Nach dem, was ich aus dem verlinkten RFC gelesen habe)

Auch dies ist meine erste Golfantwort: D

Nerketur Kamachi
quelle
2
Willkommen bei PPCG!
Acrolith
1

Pip , 46 Bytes

Übernimmt die URL von stdin und die Abfrageparameter zum Entfernen aus Befehlszeilenargumenten.

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

Probieren Sie es online!

Erläuterung:

 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
quelle
1

PowerShell v3 +, 115 bis 90 Byte

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

Nimmt Eingaben $nals URL und $zals literales Array von Zeichenfolgen als zu entfernende Parameter. -splitIst die Eingabe-URL aktiviert ?, werden die erste Hälfte in $aund die zweite in gespeichert $b.

Als nächstes $bwird $zeine neue Formulierung erstellt , indem -replacefür jedes gesperrte Abfragewort eine Schleife durchlaufen wird , um sie zu entfernen. Dann werden Ausgaben $a(unverändert) plus a in /Abhängigkeit davon, ob $bvorhanden, plus a in ?Abhängigkeit davon, ob $xvorhanden, plus `$ x ausgegeben.

AdmBorkBork
quelle
1

Pyth - 27 Bytes

Kenny hatte Recht, als er über das eingebaute Umwandeln und anschließende Invertieren sprach. Es wird jedoch sehr schwierig sein, dies zu korrigieren.

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

Test Suite .

Maltysen
quelle
1

Retina , 44 48 Bytes

Die durchgestrichene 44 ist immer noch 44. Vielen Dank an Martin für die Korrektur.

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

/&
/?

Nimmt Eingaben wie uri param1 param2. Probieren Sie es online!

Erläuterung

Die erste Ersetzung löscht die entsprechenden Parameter aus der Abfragezeichenfolge. [?&](?>([^ =&+))[^ &]*Entspricht einem ?oder &, einem vollständigen Parameternamen und (optional) =einem Wert, der den Parameternamen in Erfassungsgruppe 1 speichert. Anschließend (?=.* \1( |$))wird in einem Lookahead überprüft, ob dieser Parametername in der Liste der zu löschenden Parameter enthalten ist. Wenn ein Parameter diesen Bedingungen entspricht, wird er entfernt (durch eine leere Ersetzung ersetzt).

Die Ersetzungen überlappen sich nicht (dank des Lookaheads) und werden von links nach rechts fortgesetzt. Am Ende der URL .*stimmt der Zweig mit der Liste der zu löschenden Parameter überein und entfernt sie ebenfalls.

Die zweite Ersetzung stellt nur sicher, dass die neue Abfragezeichenfolge mit beginnt, ?wenn der erste Parameter gelöscht wurde.

DLosc
quelle
Ich denke, dies entfernt auch Parameter, wenn ein Präfix von ihnen in der Liste am Ende erscheint (zB versuchen Sie retina.tryitonline.net/… . ). Eine Möglichkeit, dies zu beheben, besteht darin, Gruppe 1 einzuwickeln (?>...).
Martin Ender
@MartinEnder TIL zu Unterausdrücken ohne Backtracking. Vielen Dank!
DLosc
0

Java 7, 203 Bytes

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;}

Ungolfed:

  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;
  }

Diese Funktion besteht alle Tests.

Akrolith
quelle
0

Python, 75 81 112 Bytes:

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

Eine benannte Funktion. Übernimmt Eingaben im Format

D(<String>,<Array>)

und gibt einen String aus.

Repl.it Mit allen Testfällen!

R. Kap
quelle
0

PHP, nicht im Wettbewerb

Heck, PHP wurde dafür gemacht; Warum nicht die aktuelle URL verwenden?

<?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);

In Datei speichern, mit der gewünschten Abfragezeichenfolge plus aufrufen &x[]=x&x[]=<exclude1>&x[]=<exclude2>&... .

Kann bei Benutzernamen und Passwort fehlschlagen (abhängig davon, ob Ihr Browser sie entfernt oder nicht).
Wird fehlschlagen, wenn das Passwort ist 0.

Titus
quelle