Изуродовать запрос


19

Я знаю, что вы всегда думали об испытаниях и невзгодах переживания радостей жизни в качестве веб-прокси. Честно говоря, у кого нет? Сегодня вам поручено реализовать эту цель (по крайней мере, ее часть). Сайт X ежедневно получает большой трафик и ищет PaaS (очевидно, это относится к Proxy как услуге) из-за большого количества пользователей, которые настаивают на передаче конфиденциальной информации через параметры запроса (пользователи глупы). Ваша задача состоит в том, чтобы удалить все и все важные параметры запроса из запроса, прежде чем перенаправить запрос в его исходное место назначения.

вход

  • Правильно сформированный абсолютный URL-адрес HTTP, который следует грамматике URI в Разделе 3 RFC3986 .
    • Вы можете предположить, что нет фрагмента
    • Краткий пример формата, где все в квадратных скобках обозначает необязательный: http[s]://[user:pass@]host.name.com[:port]/[?param1=value1&param2=value2...]
  • Список параметров запроса для удаления.

Выход

Измененный URL-адрес HTTP без параметров, определенных в списке ввода.

Примеры

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:foo@foo.com:8080/?foo=1&bar=foo [foo]
> http://foo:foo@foo.com:8080/?bar=foo

счет

Это , поэтому выигрывает самый короткий ответ (в байтах).


1
Могу ли я получить URL и параметры запроса по отдельности?
Сешумара

1
Может &появиться где-нибудь, кроме между параметрами?
Райли

также может, например, пароль содержать ?? Также должен ли порядок быть таким же, как был?
КарлКастор

@Riley Нет. Если &это часть параметра запроса, он должен быть правильно закодирован как%26
Poke

1
Видимо, http://foo:&foo=x@foo.com:8080/?foo=1&bar=fooэто разрешено RFC. Это должно сломать кучу существующих решений. : D (Правило userinfo может быть расширено как незарезервированное или pct-escape или вложенные разделы, и вложенные разделы могут иметь &и =)
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Ответы:


6

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

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

Список удаляемых параметров разделен пробелами.

$ 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/

В текущем редактировании кода несколько тестов из вопроса OP дают конечный &или ?символ в результирующем URL.
Сешумара

@seshoumara Я не уверен, как я это пропустил ... К счастью, разница всего в 1 байт.
Райли

Версии 96, 77 и 59-байтовых кодов не найдены в вашей истории редактирования. Название Edit 7 показало на 10 байт меньше по сравнению с Edit 6, но код не был изменен. Хотя я придираюсь, отличный гольф!
Сешумара

1
@seshoumara Я думаю, что это объединило некоторые из правок, потому что они были незначительными (просто удалив несколько символов).
Райли

@seshoumara Я полагаю, это действительно объединило их, потому что я сделал несколько правок в течение 5 минут друг от друга.
Райли

5

JavaScript (ES6), 62 60 байт

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>

Редактировать: 2 байта сохранены благодаря @Shaggy.


Вы можете сохранить 5 байтов, опустив .hrefв конце.
Лохматый

@ Shaggy Это не вернет строку ... Я предполагал, что это не разрешено.
Нил

Это зависит от того, как вы выводите его. Например, если вы alertэто или используете, вставляете его в (текстовый) узел, как у вас, это даст вам hrefсвойство объекта. Если вы войдете в консоль, он даст вам полный объект. Посмотри на эту скрипку .
Лохматый

1
@ Shaggy Ах, так что я определенно могу сэкономить 2 байта, строковые, спасибо.
Нил

3

PHP, 90 байт

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

-11 байт если? или & допускается в конце

Предыдущая версия 140 байт

<?=substr($u=$_GET[u],0,strpos($u,"?")+!!$j=join("&",preg_grep("#^(".join("|",$_GET[r]).")(=|$)#",explode("&",parse_url($u)[query]),1))).$j;

+2 байта: альтернативы должны быть заключены в скобки, или ^/ (.*|$)будут частью первой / последней альтернативы.
Тит

-2 байта: удалить .*. или заменить (=.*|$)на \b(-5).
Тит

Ваше регулярное выражение будет выглядеть так #^foo|bar(=.*|$)#же, как и #(^foo)|(bar=.*|bar$))#. Но так и должно быть #(foo|bar)(=.*|$)#.
Тит

@ Титус Ты прав, моя вина
Йорг Хюльсерманн

красивый! Я не думал об утверждениях; Вот почему я отступил array_map(и я был удивлен, насколько коротким может оказаться).
Тит

2

PHP, 120 110 байт

с функциями preg_replace и array: (вдохновлено Йоргом )

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

сохранить в файл, позвонить с php <scriptname> <uri> <parametername> <parametername> ...

с parse_str и http_build_query (120 байт):

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

бежать с php -r <code> <uri> <parametername> <parametername> ...


parse_str? http_build_query? Я так рад, что кто-то работает, используя правильные инструменты для работы, даже в гольф-коде. Ошибки, возникающие из-за того, что URL / SQL-запрос / регулярное выражение / HTML являются «просто строками», настолько многочисленны, насколько их легко предотвратить.
Daerdemandt

Может быть, для большего вдохновения. Я получил тебя
Йорг Хюльсерманн

@ Линн, у тебя нет ничего лучше, чем преследовать меня?
Тит

2

Java 7, 127 байт

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

объяснение

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


Для меня это не помогает, используя ваши 4-й, 5-й, 6-й и 9-й примеры oO Я использую Java 8, хотя, так что это может быть. Хотя попробовал эквивалент C # и он потерпел неудачу в тех же случаях, так что идунно.
Йодль

1
Неважно, испортил способ, которым я проверял это.
Йодль

2

C #, 377 336 330 328 байтов (173 альт)

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

Развёрнутая полная программа:

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

Вероятно, не очень эффективно, но я думаю, что это работает.

Кроме того, существует 173-байтовое решение с использованием метода @ Poke из Java. Требуется импорт для Regex, поэтому, вероятно, не может быть короче.

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

2

Рубин, 146 140 127 119 116 113 байтов

изменить 2: сохранить 6 байтов, используя $1, $2и $*, и 7, изменив x.split("=")[0]для x[/\w+/]
редактирования 3: сохранить 6 байтов, используя *вместо .join, сохраненные 2 байта из ненужных пробелов.
редактировать 4: сохранить 3 байта, переформулировав inline (изменив регулярное выражение на эквивалентное $*[1][/([^?]*)\??(.*)/,1]и поместив как назначено a)
редактировать 5: сохранено 3 байта с использованием ($*[2].scan(r=/\w+/)&[x[r]])[0]вместо$*[2].scan(r=/\w+/).include?(x[r])

Предполагая ввод в программу при ее запуске:

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

объяснение

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

Это анализирует URL-адрес, указанный в командной строке, и сохраняет совпадения в $1и $2. $*[1][/([^?]*)\??(.*)/,1]также возвращает первое совпадение для хранения внутри a, в то время как второе совпадение называется разрешением $2 точки до $ 1 и анализом bмассива массивов ...

.reject { |x|

... отвергая все это ...

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

... иметь строку перед '=', которая включена в список имен, заданный вторым параметром ... Это работает, потому что мы сканируем слова (чтобы получить список), затем получаем слово перед =, и видим, это слово в списке с &. Поскольку &возвращает пустой массив для «not found» (нулевой набор), мы используем прием, описанный ниже, чтобы получить, nilесли в массиве нет элементов. в противном случае мы возвращаем строку, которая считается истинной, которая отклоняет эту строку.

}*"&"

... и соединить оставшиеся строки вместе с '&'

На данный момент bэто строка запроса GET для URL. Таким образом, нам просто нужно распечатать его.

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

Это использует трюк в рубине. b[0]будет, nilесли b пустой массив или строка. Так что если это правда , (не nilили false), то в массиве есть хотя бы один элемент, поэтому нам нужно указать a+"?"+bправильный URL. в противном случае мы просто помещаем a, потому что нет параметров для отображения

Примечание. В этом ответе предполагается, что он ? не может появляться нигде, кроме как для разграничения URL-адреса из запроса (согласно тому, что я прочитал из связанного RFC)

Кроме того, это мой первый ответ гольф: D


2
Добро пожаловать в PPCG!
Акролит

1

Пип , 46 байт

Принимает URL из stdin и параметры запроса для удаления из аргументов командной строки.

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

Попробуйте онлайн!

Объяснение:

 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)

1

PowerShell v3 +, 115 90 байт

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

Принимает входные данные $nкак URL и $zкак буквенный массив строк в качестве параметров для удаления. -splits входной URL включен ?, первая половина сохраняется, $aа вторая - в $b.

Далее, $bпереформулируется путем выполнения цикла $z, выполняя регулярные выражения -replaceдля каждого забаненного слова запроса, чтобы удалить их. Затем выходные данные $a(неизмененные), плюс a в /зависимости от того, $bсуществует ли , плюс a в ?зависимости от того, $xсуществует ли , плюс `$ x.


1

Pyth - 27 байт

Кенни был прав, когда говорил о встроенном преобразовании, а затем об обратном, однако это будет очень трудно исправить.

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

Тестовый пакет .


1

Retina , 44 48 байт

Вычеркнутый 44 - все еще 44. Спасибо Мартину за исправление.

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

/&
/?

Принимает участие как uri param1 param2. Попробуйте онлайн!

объяснение

Первая замена удаляет соответствующие параметры из строки запроса. [?&](?>([^ =&+))[^ &]*Соответствует ?или &, полному имени параметра и (необязательно) =и значению, сохраняя имя параметра в группе захвата 1. Затем (?=.* \1( |$))выполняется предварительный просмотр, который проверяет, появляется ли это имя параметра в списке параметров для удаления. Если параметр соответствует этим условиям, он удаляется (заменяется пустой заменой).

Замены не перекрываются (благодаря прогнозу) и продолжаются слева направо. По достижении конца URL .*ветвь сопоставляет список параметров для удаления и удаляет его.

Вторая замена просто гарантирует, что новая строка запроса начинается, ?если первый параметр был удален.


Я думаю, что это также удаляет параметры, если их префикс появляется в конце списка (например, попробуйте retina.tryitonline.net/… ). Один из способов исправить это - обернуть группу 1 в (?>...).
Мартин Эндер

@MartinEnder TIL о невыраженных подвыражениях. Благодарность!
DLosc

0

Java 7, 203 байта

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

Эта функция проходит все тесты.



0

PHP, не конкурирующий

Черт, PHP был создан для этого; почему бы не использовать реальный 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);

Сохраните в файл, позвоните с нужной вам строкой запроса плюс &x[]=x&x[]=<exclude1>&x[]=<exclude2>&....

Может произойти сбой при вводе имени пользователя и пароля (в зависимости от того, удаляет их браузер или нет).
Будет ошибкой , если пароль 0.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.