Пом'якшення запиту


19

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

Вхідні дані

  • Добре сформована абсолютна 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-адреси та параметри запиту в окремих рядках?
seshoumara

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

також може, наприклад, пароль містити ?? Чи слід дотримуватися порядку, як було?
КарлКастор

@Riley Ні. Якщо &є частиною параметра запиту, він повинен бути правильно зашифрований як%26
Poke

1
Мабуть, http://foo:&foo=x@foo.com:8080/?foo=1&bar=fooце дозволено RFC. Це повинно зламати купу існуючих рішень. : D (Правило: інформація про користувачів може бути розширена як незарезервована або pct-escape або sub-delims, а sub-delims може мати &і =)
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/

У вашому поточному редагуванні коду декілька тестів із запитання про ОП дають кінцевий &або ?символьний характер у отриманій URL-адресі.
seshoumara

@seshoumara Я не впевнений, як я пропустив це ... На щастя, це лише різниця в 1 байті.
Райлі

Версії коду 96, 77 та 59 байтів у вашій історії редагування не знайдено. Заголовок редагування 7 показав на 10 байт менше порівняно з редагуванням 6, але код не змінено. Я все-таки заїдаю, чудовий гольф!
seshoumara

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)(=.*|$)#.
Тит

@Titus Ви праві, я винен
Йорг Хюльсерманн,

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

2

PHP, 120 110 байт

з функціями preg_replace та масиву: (надихнув Йорг )

<?=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 запит / regexp / HTML, є "просто рядками" стільки ж, скільки їх легко запобігти.
Daerdemandt

Можливо, для більше натхнення. Я отримав Тебе
Йорг Гюльсерманн,

@Lynn Чи не маєш ти нічого кращого зробити, ніж переслідувати мене?
Тит

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

Ідеон


Це не допомагає мені, використовуючи ваші 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 байта переформулювання інлайн (змінено регулярного виразу еквівалентні $*[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]

... мати рядок перед '=', що входить до списку імен, заданих другим параметром ... Це працює, тому що ми скануємо слова (щоб отримати список), потім отримаємо слово перед =, і побачимо, чи це слово в списку с &. Оскільки &повертає порожній масив на "не знайдено" (нульовий набір), ми використовуємо трюк, пояснений нижче, щоб отриматиnil якщо в масиві немає елементів. в іншому випадку ми повертаємо рядок, який рахується як truthy, який відкидає цей рядок.

}*"&"

... і приєднайтесь до решти рядків разом із "&"

На даний момент 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(немодифіковані), плюс /залежно від того, чи $bіснує, плюс ?залежно від того, чи $xіснує, плюс `$ x.


1

Pyth - 27 байт

Кенні мав рацію, коли говорив про вбудоване, яке потрібно перетворити, а потім перевернути, правда це буде дуже важко.

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

Тестовий сюїт .


1

Сітківка , 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;}

Безголівки:

  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.