[Question]
  [
I know you've always thought about the trials and tribulations of experiencing the joys of life as a web proxy. Honestly, who hasn't? Today you're tasked with realizing this goal (at least a part of it). Website X gets a lot of traffic on the daily and is looking for a PaaS (clearly this refers to Proxy as a Service) because of the large number of users who insist on passing sensitive information via query parameters (users are silly). Your task is to remove any and all sensitive query parameters from the request before forwarding the request through to its original destination.
## Input
* A well-formed absolute HTTP URL that follows the URI grammar in [RFC3986 Section 3](https://www.ietf.org/rfc/rfc3986.txt).
	+ You can assume there is no fragment
	+ Brief format example where anything in square brackets denotes optional: `http[s]://[user:pass@]host.name.com[:port]/[?param1=value1&param2=value2...]`
* A list of query parameters to be removed.
## Output
The modified HTTP URL without the parameters defined in the input list.
## Examples
```
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]](/cdn-cgi/l/email-protection):8080/?foo=1&bar=foo [foo]
> http://foo:[[email protected]](/cdn-cgi/l/email-protection):8080/?bar=foo
```
## Scoring
This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), so the shortest answer (in bytes) wins.
  
[Answer]
# GNU sed 98 96 88 80 77 74 69 59 54 (48 + 1 for -r) 49
```
:;s,(.+)(=[^&]*[& ]|&)(.*)\1,\3 ,
t;s,[?&]? .*,,
```
The list of parameters to remove are separated by spaces. 
```
$ 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/
```
[Answer]
## JavaScript (ES6), ~~62~~ 60 bytes
```
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: Saved 2 bytes thanks to @Shaggy.
[Answer]
# PHP, 90 Bytes
```
<?=trim(preg_replace("#(?<=\?|&)(".join("|",$_GET[r]).")(=.*)?(&|$)#U","",$_GET[u]),"?&");
```
-11 Bytes if ? or & is allowed at the end
Previous Version 140 Bytes
```
<?=substr($u=$_GET[u],0,strpos($u,"?")+!!$j=join("&",preg_grep("#^(".join("|",$_GET[r]).")(=|$)#",explode("&",parse_url($u)[query]),1))).$j;
```
[Answer]
# PHP, ~~120~~ 110 bytes
with preg\_replace and array functions: (inspired by [Jörg](https://codegolf.stackexchange.com/q/93815#93815))
```
<?=preg_replace(array_map(function($s){return"#(\\?|&)$s(=.*)?(&|$)#U";},array_slice($argv,2)),"\1",$argv[1]);
```
save to file, call with `php <scriptname> <uri> <parametername> <parametername> ...`
with parse\_str and 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);
```
run with `php -r <code> <uri> <parametername> <parametername> ...`
[Answer]
# Java 7, 127 bytes
```
String a(String a,String[]b){for(String c:b)a=a.replaceAll("(?<=[?&])"+c+"(=[^&]*)?(&|$)","");return a.replaceAll("[?&]$","");}
```
## Explanation
```
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](https://ideone.com/AQ9mnE)
[Answer]
# 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 full program:
```
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;
    }
}
```
Probably not very efficient, but it works I think.
Alternatively, there is a 173 byte solution using @Poke's method from Java. Requires an import for Regex though, so probably can't be shorter.
```
using System.Text.RegularExpressions;string m(string a,string[]b){foreach(var c in b)a=Regex.Replace(a,$"(?<=[?&]){c}(=[^&]*)?(&|$)","");return Regex.Replace(a,"[?&]$","");}
```
[Answer]
# Ruby, ~~146 140 127 119 116~~ 113 bytes
edit 2: saved 6 bytes by using `$1`, `$2`, and `$*`, and 7 by changing `x.split("=")[0]` to `x[/\w+/]`  
edit 3: saved 6 bytes by using `*` instead of `.join`, saved 2 bytes from unnecessary spaces  
edit 4: saved 3 bytes by reformulating inline (changed regex to equivalent `$*[1][/([^?]*)\??(.*)/,1]` and put as assigned to `a`)  
edit 5: saved 3 bytes by using `($*[2].scan(r=/\w+/)&[x[r]])[0]` instead of `$*[2].scan(r=/\w+/).include?(x[r])`
Assuming input to the program when running it:
```
a,b=$*[1][/([^?]*)\??(.*)/,1],$2.split("&").reject{|x|($*[2].scan(r=/\w+/)&[x[r]])[0]}*"&"
puts(b[0] ?a+"?"+b: a)
```
## Explanation
```
a,b=$*[1][/([^?]*)\??(.*)/,1],$2.split("&")
```
This parses the URL given on the command line, and stores the matches into `$1` and `$2`. `$*[1][/([^?]*)\??(.*)/,1]` also returns the first match to store inside `a`, while the second match is referred to as `$2`
let a point to $1, and parse `b` into an array of arrays...
```
.reject { |x|
```
...rejecting all that...
```
    ($*[2].scan(r=/\w+/)&[x[r]])[0]
```
...have a string before the '=' that is included in the list of names given by the second parameter...
This works because we scan for words (to get the list) then get the word before the `=`, and see if that word is in the list with `&`. Since `&` returns an empty array on "not found" (the null set), we use the trick explained below to get `nil` if there are no elements in the array. otherwise we return a string, which counts as truthy, which rejects that string.
```
}*"&"
```
...and join the remaining strings together with '&'
At this point, `b` is the GET query string for the URL. Thus, we just need to print it.
```
puts(b[0] ?a+"?"+b: a)
```
This uses a trick in ruby. `b[0]` will be `nil` if b is an empty array or string. So if its *truthy*, (not `nil` or `false`), then there's at least one element in the array, so we need to puts `a+"?"+b` for the correct URL. otherwise, we just puts `a`, because there are no parameters to show
Note: this answer assumes that `?` *cannot* appear anywhere except to delimit the URL from the query. (according to what I read from the linked RFC)
Also, this is my first golf answer :D
[Answer]
## [Pip](http://github.com/dloscutoff/pip), 46 bytes
Takes the URL from stdin and the query parameters for removal from command-line args.
```
YgqR`\?.+`{s:J_@`^[^=]+`NIyFI@>a^'&[s&'?sJ'&]}
```
[Try it online!](http://pip.tryitonline.net/#code=WWdxUmBcPy4rYHtzOkpfQGBeW149XStgTkl5RklAPmFeJyZbcyYnP3NKJyZdfQ&input=aHR0cDovL2V4YW1wbGUuY29tLz9mb289MSZiYXI9MiZiYXo9Mw&args=Zm9v+YmF6)
Explanation:
```
 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)
```
[Answer]
## PowerShell v3+, ~~115~~ 90 bytes
```
param($n,$z)$a,$b=$n-split'\?';($z|%{$b=$b-replace"(^|&)$_(=[^&]*)?(&|$)"});$a+"?"*!!$b+$b
```
Takes input `$n` as the URL and `$z` as a literal array of strings as the parameters to remove. `-split`s the input URL on `?`, stores the first half into `$a` and the second into `$b`.
Next, `$b` is re-formulated by taking a loop through `$z`, performing a regex `-replace` on each banned query word to remove them. Then, outputs `$a` (unmodified), plus a `/` depending upon whether `$b` exists, plus a `?` depending upon whether `$x` exists, plus `$x.
[Answer]
# Pyth - 27 bytes
Kenny was right when he talked about the builtin to transform and then invert, it'll be very hard to right, though.
```
.sjK\?mj\&f!}hcT\=Qcd\&czKK
```
[Test Suite](http://pyth.herokuapp.com/?code=.sjK%5C%3Fmj%5C%26f%21%7DhcT%5C%3DQcd%5C%26czKK&test_suite=1&test_suite_input=%5B%22foo%22%5D%0Ahttp%3A%2F%2Fexample.com%2F%0A%5B%5D%0Ahttp%3A%2F%2Fexample.com%2F%3Ffoo%3Dbar%0A%5B%5D%0Ahttp%3A%2F%2Fexample.com%2F%0A%5B%22foo%22%2C+%22baz%22%5D%0Ahttp%3A%2F%2Fexample.com%2F%3Ffoo%3D1%26bar%3D2%26baz%3D3%0A%5B%22foo%22%2C+%22bar%22%2C+%22baz%22%5D%0Ahttp%3A%2F%2Fexample.com%2F%3Ffoo%3D1%26bar%3D2%26baz%3D3%0A%5B%22foo%22%2C+%22baz%22%5D%0Ahttp%3A%2F%2Fexample.com%2F%3Ffoo%26bar%3D2%26baz%3D%0A%5B%22foo%22%2C+%22bar%22%5D%0Ahttp%3A%2F%2Fexample.com%2F%3Fabc%3D1%26def%3D2%26baz%3Dfoo%0A%5B%22foo%22%5D%0Ahttp%3A%2F%2Fexample.com%2F%3Ffoobar%3Dbaz%0A%5B%22foo%22%5D%0Ahttp%3A%2F%2Ffoo%3Afoo%40foo.com%3A8080%2F%3Ffoo%3D1%26bar%3Dfoo&debug=0&input_size=2).
[Answer]
## [Retina](https://github.com/m-ender/retina), ~~44~~ 48 bytes
*Crossed-out 44 is still 44. Thanks to Martin for the fix.*
```
[?&](?>([^ =&]+))[^ &]*(?=.* \1( |$))| .*
/&
/?
```
Takes input like `uri param1 param2`. [Try it online!](http://retina.tryitonline.net/#code=Wz8mXSg_PihbXiA9Jl0rKSlbXiAmXSooPz0uKiBcMSggfCQpKXwgLioKCi8mCi8_&input=aHR0cDovL2V4YW1wbGUuY29tLz9mb28mYmFyPTImYmF6PSZ-fn5-PTQgZm9vIGJhIGJheiB-fn5-)
### Explanation
The first replacement deletes the appropriate parameters from the query string. `[?&](?>([^ =&+))[^ &]*` matches a `?` or `&`, a full parameter name, and (optionally) `=` and a value, storing the parameter name in capture group 1. Then `(?=.* \1( |$))` is a lookahead that checks whether that parameter name appears in the list of parameters to delete. If a parameter matches these conditions, it is removed (substituted with an empty replacement).
Substitutions are non-overlapping (thanks to the lookahead) and proceed from left to right. On reaching the end of the URL, the  `.*` branch matches the list of parameters to delete and removes it as well.
The second replacement just makes sure the new query string starts with `?` if the first parameter was deleted.
[Answer]
# 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;
  }
```
This function passes all of the tests.
[Answer]
# 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('&?')
```
A named function. Takes input in the format
```
D(<String>,<Array>)
```
and outputs a string.
[Repl.it With All Test Cases!](https://www.repl.it/DeIw/1)
[Answer]
# PHP, not competing
Heck, PHP was made for this; why not use the actual 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);
```
Save to file, call with your wanted query string plus `&x[]=x&x[]=<exclude1>&x[]=<exclude2>&...`.
May fail on username and password (depending on wether your browser removes them or not).  
*Will* fail if password is `0`.
]