Okaleczanie zapytania

19

Wiem, że zawsze myślałeś o próbach i udrękach związanych z doświadczaniem radości życia jako internetowy serwer proxy. Szczerze mówiąc, kto nie? Dziś masz za zadanie zrealizować ten cel (przynajmniej jego część). Witryna X codziennie dostaje duży ruch i szuka PaaS (wyraźnie odnosi się to do serwera proxy jako usługi) ze względu na dużą liczbę użytkowników, którzy nalegają na przekazywanie poufnych informacji za pomocą parametrów zapytań (użytkownicy są głupi). Twoim zadaniem jest usunięcie wszystkich wrażliwych parametrów zapytania z żądania przed przekazaniem żądania do pierwotnego miejsca docelowego.

Wejście

  • Dobrze sformułowany bezwzględny adres URL HTTP zgodny z gramatyką URI w RFC3986 sekcja 3 .
    • Możesz założyć, że nie ma fragmentu
    • Krótki przykład formatu, w którym cokolwiek w nawiasach kwadratowych oznacza opcjonalne: http[s]://[user:pass@]host.name.com[:port]/[?param1=value1&param2=value2...]
  • Lista parametrów zapytania do usunięcia.

Wynik

Zmodyfikowany adres URL HTTP bez parametrów zdefiniowanych na liście wejściowej.

Przykłady

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

Punktacja

To jest , więc wygrywa najkrótsza odpowiedź (w bajtach).

Szturchać
źródło
1
Czy mogę uzyskać adres URL i parametry zapytania w osobnych wierszach?
seshoumara,
1
Może &pojawić się gdziekolwiek poza parametrami?
Riley,
może również np. hasło zawierać ?? Czy zamówienie powinno być również zachowane?
KarlKastor,
@ Riley Nie. Jeśli &jest częścią parametru zapytania, należy go poprawnie zakodować jako%26
Poke
1
Najwyraźniej http://foo:&[email protected]:8080/?foo=1&bar=foojest dozwolony przez RFC. To powinno złamać wiele istniejących rozwiązań. : D (Reguła jest taka, że ​​informacja o użytkowniku może być rozwinięta jako niezarezerwowana lub ucieczka przed pct lub podpodwójki, a podpodzimie mogą mieć &i =)
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨dd

Odpowiedzi:

6

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

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

Lista parametrów do usunięcia jest oddzielona spacjami.

$ 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
źródło
W bieżącej edycji kodu wiele testów z pytania OP daje znak końcowy &lub ?znak w wynikowym adresie URL.
seshoumara,
@seshoumara Nie jestem pewien, jak mi tego brakowało ... Na szczęście to tylko różnica 1 bajtu.
Riley,
Wersje kodów 96, 77 i 59 bajtów nie znajdują się w historii edycji. Tytuł edycji 7 pokazał 10 bajtów mniej w porównaniu do edycji 6, ale kod nie został zmieniony. Nienawidzę, świetna gra w golfa!
seshoumara,
1
@seshoumara Wydaje mi się, że połączyłem niektóre zmiany, ponieważ były one niewielkie (wystarczyło usunąć kilka znaków).
Riley,
@seshoumara Wydaje mi się, że faktycznie połączył je, ponieważ dokonałem wielu zmian w ciągu 5 minut od siebie.
Riley,
5

JavaScript (ES6), 62 60 bajtów

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>

Edycja: Zapisano 2 bajty dzięki @Shaggy.

Neil
źródło
Możesz zapisać 5 bajtów, upuszczając .hrefna końcu.
Kudłaty
@Shaggy To nie zwróciłoby łańcucha ... Zakładałem, że to niedozwolone.
Neil,
To zależy od tego, jak to wyprowadzasz. Na przykład, jeśli alertgo użyjesz , lub wstaw go do węzła (tekstowego), tak jak masz, da ci hrefwłaściwość obiektu. Jeśli jednak zalogujesz się do konsoli, otrzymasz pełny obiekt. Zobacz to skrzypce .
Kudłaty
1
@ Shaggy Ah, dzięki czemu mogę zdecydowanie zaoszczędzić 2 bajty, zmieniając go, dzięki.
Neil,
3

PHP, 90 bajtów

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

-11 Bajtów, jeśli? lub & jest dozwolone na końcu

Poprzednia wersja 140 bajtów

<?=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
źródło
+2 bajty: alternatywy muszą być nawiasowane, lub ^/ (.*|$)będą częścią pierwszej / ostatniej alternatywy.
Tytus
-2 bajty: usuń .*. lub zastąpienia (=.*|$)w \b(-5).
Tytus
Twoje wyrażenie regularne będzie wyglądało tak #^foo|bar(=.*|$)#samo jak #(^foo)|(bar=.*|bar$))#. Ale tak powinno być #(foo|bar)(=.*|$)#.
Tytus
@Titus Masz rację, moja wina
Jörg Hülsermann
ładny! Nie myślałem o twierdzeniach; dlatego wróciłem array_map(i byłem zaskoczony, jak krótki może się okazać).
Tytus
2

PHP, 120 110 bajtów

z preg_replace i funkcjami tablicowymi: (zainspirowany Jörg )

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

zapisz do pliku, zadzwoń za pomocą php <scriptname> <uri> <parametername> <parametername> ...

z parse_str i http_build_query (120 bajtów):

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

Biegnij z php -r <code> <uri> <parametername> <parametername> ...

Tytus
źródło
parse_str? http_build_query? Tak się cieszę, że ktoś pracuje przy użyciu odpowiednich narzędzi do pracy, nawet w golfa kodowym. Błędy, które pojawiają się, ponieważ URL / zapytanie SQL / regexp / HTML są „tylko łańcuchami”, są tak liczne, że można ich łatwo zapobiec.
Daerdemandt,
Może po więcej inspiracji. Mam cię
Jörg Hülsermann
@ Lynn Nie masz nic lepszego do roboty niż prześladowanie mnie?
Tytus
2

Java 7, 127 bajtów

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

Wyjaśnienie

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

Szturchać
źródło
Nie udaje mi się to przy użyciu twojego czwartego, piątego, szóstego i dziewiątego przykładu oO Używam jednak Java 8, więc to może być to. Chociaż wypróbowałem równoważnik C # i nie udało się w tych samych przypadkach, więc nie wiem.
Yodle,
1
Nieważne, popsułem sposób, w jaki testowałem.
Yodle,
2

C # 377 336 330 328 bajtów (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;}

Pełny program bez golfa:

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

Prawdopodobnie niezbyt wydajny, ale myślę, że działa.

Alternatywnie, istnieje 173 bajtowe rozwiązanie wykorzystujące metodę @ Poke z Javy. Wymaga jednak importu Regex, więc prawdopodobnie nie może być krótszy.

using System.Text.RegularExpressions;string m(string a,string[]b){foreach(var c in b)a=Regex.Replace(a,$"(?<=[?&]){c}(=[^&]*)?(&|$)","");return Regex.Replace(a,"[?&]$","");}
Jodła
źródło
2

Ruby, 146 140 127 119 116 113 bajtów

edycja 2: zapisano 6 bajtów za pomocą $1, $2i $*oraz 7, przechodząc x.split("=")[0]do x[/\w+/]
edycji 3: zapisano 6 bajtów za pomocą *zamiast.join , zapisano 2 bajty z niepotrzebnych spacji
edytuj 4: zapisano 3 bajty przez przeformułowanie inline (zmieniono wyrażenie regularne na ekwiwalent $*[1][/([^?]*)\??(.*)/,1]i wstawiono przypisane do a)
edytuj 5: zapisano 3 bajty za pomocą ($*[2].scan(r=/\w+/)&[x[r]])[0]zamiast$*[2].scan(r=/\w+/).include?(x[r])

Zakładając wejście do programu podczas jego uruchamiania:

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

Wyjaśnienie

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

To analizuje adres URL podany w wierszu poleceń i przechowuje dopasowania w $1i $2. $*[1][/([^?]*)\??(.*)/,1]zwraca również pierwsze dopasowanie do zapisania w środku a, podczas gdy drugie dopasowanie jest określane jako $2 pozwól punktowi na 1 $ i parsujb w tablicy tablic ...

.reject { |x|

... odrzucając to wszystko ...

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

... mają ciąg przed „=”, który jest zawarty na liście nazw podanych przez drugi parametr ... Działa to, ponieważ wyszukujemy słowa (w celu uzyskania listy), a następnie dostajemy słowo przed =i sprawdzamy, czy to słowo jest na liście z &. Ponieważ &zwraca pustą tablicę przy „nie znaleziono” (zestaw zerowy), używamy sztuczki opisanej poniżej, aby uzyskaćnil jeśli w tablicy nie ma żadnych elementów. w przeciwnym razie zwracamy ciąg znaków, który liczy się jako prawdziwy, co odrzuca ten ciąg.

}*"&"

... i dołącz pozostałe ciągi razem z „&”

W tym momencie bjest ciąg zapytania GET dla adresu URL. Dlatego musimy go tylko wydrukować.

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

To używa sztuczki w rubinie. b[0]będzie, niljeśli b jest pustą tablicą lub łańcuchem. Więc jeśli to prawda , (nie nillub false), to w tablicy jest co najmniej jeden element, więc musimy wstawića+"?"+b poprawny adres URL. w przeciwnym razie po prostu stawiamya , ponieważ nie ma parametrów do wyświetlenia

Uwaga: ta odpowiedź zakłada, że ? nie może nigdzie pojawić poza ograniczeniem adresu URL z zapytania. (zgodnie z tym, co przeczytałem z połączonego RFC)

To także moja pierwsza odpowiedź na golfa: D

Nerketur Kamachi
źródło
2
Witamy w PPCG!
acrolith
1

Pip , 46 bajtów

Pobiera adres URL ze standardowego wejścia i parametry zapytania w celu usunięcia z argumentów wiersza polecenia.

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

Wypróbuj online!

Wyjaśnienie:

 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
źródło
1

PowerShell v3 +, 115 90 bajtów

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

Pobiera dane wejściowe $njako adres URL i $zjako dosłowną tablicę ciągów jako parametry do usunięcia. -splits wejściowy adres URL włączony ?, przechowuje pierwszą połowę w, $aa drugą w $b.

Następnie $bsformułowano ponownie $z, przeprowadzając pętlę , wykonując wyrażenie regularne -replacedla każdego zbanowanego słowa zapytania, aby je usunąć. Następnie wyjścia $a(niezmodyfikowane) plus plus w /zależności od tego $b, czy istnieje, plus plus w ?zależności od tego $x, czy istnieje, plus `$ x.

AdmBorkBork
źródło
1

Pyth - 27 bajtów

Kenny miał rację, kiedy mówił o wbudowanej transformacji, a następnie odwróceniu, jednak bardzo trudno będzie to naprawić.

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

Pakiet testowy .

Maltysen
źródło
1

Siatkówka , 44 48 bajtów

Przekreślony 44 to wciąż 44. Dzięki Martin za poprawkę.

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

/&
/?

Przyjmuje dane wejściowe jak uri param1 param2. Wypróbuj online!

Wyjaśnienie

Pierwsza zamiana usuwa odpowiednie parametry z ciągu zapytania. [?&](?>([^ =&+))[^ &]*dopasowuje a ?lub &pełną nazwę parametru i (opcjonalnie)= i wartość, przechowywanie nazwę parametru w grupie przechwytywania 1. Następnie (?=.* \1( |$))jest uprzedzona, że sprawdza, czy nazwa parametru, który pojawia się na liście parametrów usunąć. Jeśli parametr spełnia te warunki, jest usuwany (zastępowany pustym zamiennikiem).

Podstawienia nie nakładają się (dzięki lookahead) i przechodzą od lewej do prawej. Po osiągnięciu końca adresu URL plik .* gałąź dopasowuje listę parametrów do usunięcia, a także ją usuwa.

Druga zamiana tylko upewnia się, że nowy ciąg zapytania zaczyna się od, ?jeśli pierwszy parametr został usunięty.

DLosc
źródło
Myślę, że to usuwa również parametry, jeśli ich prefiks pojawia się na liście na końcu (np. Spróbuj retina.tryitonline.net/... ). Jednym ze sposobów rozwiązania tego problemu jest zawinięcie grupy 1 (?>...).
Martin Ender
@MartinEnder TIL o podwyrażeniach niezwiązanych z powrotem. Dzięki!
DLosc
0

Java 7, 203 bajty

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

Nie golfowany:

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

Ta funkcja przechodzi wszystkie testy.

acrolith
źródło
0

Python, 75 81 112 bajtów:

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

Nazwana funkcja. Pobiera dane wejściowe w formacie

D(<String>,<Array>)

i wyprowadza ciąg.

Zamień na wszystkie przypadki testowe!

R. Kap
źródło
0

PHP, nie konkuruje

Do cholery, PHP zostało do tego stworzone; dlaczego nie użyć rzeczywistego adresu URL?

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

Zapisz do pliku, zadzwoń z poszukiwanym ciągiem zapytania plus &x[]=x&x[]=<exclude1>&x[]=<exclude2>&....

Może się nie powieść nazwa użytkownika i hasło (w zależności od tego, czy przeglądarka je usuwa, czy nie).
Nie powiedzie się, jeśli hasło jest 0.

Tytus
źródło