Mutilando la consulta

19

Sé que siempre has pensado en las pruebas y tribulaciones de experimentar las alegrías de la vida como un proxy web. Honestamente, ¿quién no? Hoy tienes la tarea de alcanzar este objetivo (al menos una parte de él). El sitio web X recibe mucho tráfico a diario y está buscando un PaaS (claramente esto se refiere a Proxy as a Service) debido a la gran cantidad de usuarios que insisten en pasar información confidencial a través de parámetros de consulta (los usuarios son tontos). Su tarea es eliminar todos los parámetros de consulta confidenciales de la solicitud antes de reenviar la solicitud a su destino original.

Entrada

  • Una URL HTTP absoluta bien formada que sigue la gramática de URI en RFC3986 Sección 3 .
    • Puedes asumir que no hay fragmento
    • Breve ejemplo de formato donde cualquier cosa entre corchetes denota opcional: http[s]://[user:pass@]host.name.com[:port]/[?param1=value1&param2=value2...]
  • Una lista de parámetros de consulta que se eliminarán.

Salida

La URL HTTP modificada sin los parámetros definidos en la lista de entrada.

Ejemplos

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

Puntuación

Este es el , por lo que gana la respuesta más corta (en bytes).

Dar un toque
fuente
1
¿Puedo obtener la URL y los parámetros de consulta en líneas separadas?
seshoumara
1
¿Puede &aparecer en cualquier otro lugar que no sea entre parámetros?
Riley
también puede, por ejemplo, la contraseña contener un ?? ¿También debe mantenerse la orden como estaba?
KarlKastor
@Riley No. Si &es parte de un parámetro de consulta, debe estar correctamente codificado como%26
Poke
1
Aparentemente, http://foo:&[email protected]:8080/?foo=1&bar=fooestá permitido por el RFC. Esto debería romper muchas de las soluciones existentes. : D (La regla es userinfo puede expandirse como sin reservas o pct-escape o subdelimitaciones, y los subdelimitaciones pueden tener &y =)
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Respuestas:

6

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

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

La lista de parámetros para eliminar están separados por espacios.

$ 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
fuente
En su edición de código actual, múltiples pruebas de la pregunta de OP dan un carácter final &o un ?carácter en la URL resultante.
seshoumara
@seshoumara No estoy seguro de cómo me perdí eso ... Por suerte, es solo una diferencia de 1 byte.
Riley
Las versiones de código de 96, 77 y 59 bytes no se encuentran en su historial de edición. El título de la edición 7 mostró 10 bytes menos en comparación con la edición 6, pero el código no había cambiado. Sin embargo, estoy jugando, ¡excelente golf!
seshoumara
1
@seshoumara Creo que combinó algunas de las ediciones porque eran menores (solo eliminando algunos caracteres).
Riley
@seshoumara Supongo que en realidad los combinó porque hice varias ediciones con 5 minutos de diferencia.
Riley
5

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>

Editar: Guardado 2 bytes gracias a @Shaggy.

Neil
fuente
Puede guardar 5 bytes soltando el .hrefal final.
Shaggy
@ Shaggy Eso no devolvería una cadena ... Supuse que no estaba permitido.
Neil
Depende de cómo lo produzca. Por ejemplo, si alertlo usa o lo inserta en un nodo (texto), como lo ha hecho, le dará la hrefpropiedad del objeto. Sin embargo, si lo registras en la consola, te dará el objeto completo. Ver este violín .
Shaggy
1
@ Shaggy Ah, por lo que definitivamente puedo guardar 2 bytes encadenándolo, gracias.
Neil
3

PHP, 90 bytes

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

-11 Bytes si? o & está permitido al final

Versión anterior 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
fuente
+2 bytes: las alternativas deben estar entre paréntesis o ^/ (.*|$)serán parte de la primera / última alternativa.
Tito
-2 bytes: eliminar .*. o reemplazar (=.*|$)con \b(-5).
Tito
Su expresión regular se verá como la #^foo|bar(=.*|$)#que es idéntica a #(^foo)|(bar=.*|bar$))#. Pero debería ser #(foo|bar)(=.*|$)#.
Tito
@Titus Tienes razón, es mi culpa
Jörg Hülsermann
¡bonito! No pensé en afirmaciones; Por eso me volví a caer array_map(y me sorprendió lo corto que puede resultar).
Tito
2

PHP, 120 110 bytes

con funciones preg_replace y array: (inspirado en Jörg )

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

guardar en archivo, llamar con php <scriptname> <uri> <parametername> <parametername> ...

con parse_str y 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);

corre con php -r <code> <uri> <parametername> <parametername> ...

Titus
fuente
parse_str? http_build_query? Estoy muy contento de ver a alguien trabajando con las herramientas adecuadas para el trabajo, incluso en el código de golf. Los errores que surgen debido a que URL / SQL query / regexp / HTML son "solo cadenas" son tan numerosos como fáciles de prevenir.
Daerdemandt
Quizás para más inspiración. Te tengo
Jörg Hülsermann
@ Lynn ¿No tienes nada mejor que hacer que acecharme?
Tito
2

Java 7, 127 bytes

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

Explicación

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

Ideona

Dar un toque
fuente
Esto falla para mí usando sus 4to, 5to, 6to y 9no ejemplos. Estoy usando Java 8, así que podría ser. Aunque probé el equivalente de C # y falló los mismos casos, así que no sé.
Yodle
1
No importa, estropeé la forma en que lo estaba probando.
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;}

Programa completo sin golf:

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

Probablemente no sea muy eficiente, pero creo que funciona.

Alternativamente, hay una solución de 173 bytes que utiliza el método @ Poke de Java. Sin embargo, requiere una importación para Regex, por lo que probablemente no pueda ser más corto.

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

Ruby, 146 140 127 119 116 113 bytes

edición 2: guardado 6 bytes usando $1, $2y $*, y 7 cambiando x.split("=")[0]a x[/\w+/]
edición 3: guardado 6 bytes usando en *lugar de .join, guardado 2 bytes de espacios innecesarios
edición 4: guardado 3 bytes reformulando en línea (cambió la expresión regular a equivalente $*[1][/([^?]*)\??(.*)/,1]y puso según lo asignado a)
editar 5: guardado 3 bytes usando en ($*[2].scan(r=/\w+/)&[x[r]])[0]lugar de$*[2].scan(r=/\w+/).include?(x[r])

Asumiendo la entrada al programa cuando lo ejecuta:

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

Explicación

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

Esto analiza la URL dada en la línea de comando y almacena las coincidencias en $1y $2. $*[1][/([^?]*)\??(.*)/,1]también devuelve la primera coincidencia para almacenar en el interior a, mientras que la segunda coincidencia se conoce como $2 dejar un punto a $ 1 y analizar ben una matriz de matrices ...

.reject { |x|

... rechazando todo eso ...

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

... tiene una cadena antes del '=' que se incluye en la lista de nombres dados por el segundo parámetro ... Esto funciona porque buscamos palabras (para obtener la lista) y luego la palabra antes del =, y vemos si esa palabra está en la lista con &. Dado que &devuelve una matriz vacía en "no encontrado" (el conjunto nulo), usamos el truco explicado a continuación para obtener nilsi no hay elementos en la matriz. de lo contrario, devolvemos una cadena, que cuenta como verdadera, que rechaza esa cadena.

}*"&"

... y une las cadenas restantes junto con '&'

En este punto, bes la cadena de consulta GET para la URL. Por lo tanto, solo necesitamos imprimirlo.

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

Esto usa un truco en rubí. b[0]será nilsi b es una matriz o cadena vacía. Entonces, si es verdad , (no nilo false), entonces hay al menos un elemento en la matriz, por lo que necesitamos poner a+"?"+bla URL correcta. de lo contrario, solo ponemosa , porque no hay parámetros para mostrar

Nota: esta respuesta asume que ? no puede aparecer en ninguna parte excepto para delimitar la URL de la consulta. (según lo que leí del RFC vinculado)

Además, esta es mi primera respuesta de golf: D

Nerketur Kamachi
fuente
2
Bienvenido a PPCG!
Acrolith
1

Pip , 46 bytes

Toma la URL de stdin y los parámetros de consulta para eliminarlos de los argumentos de la línea de comandos.

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

Pruébalo en línea!

Explicación:

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

PowerShell v3 +, 115 90 bytes

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

Toma la entrada $ncomo la URL y $zcomo una matriz literal de cadenas como los parámetros a eliminar. -splitEn la URL de entrada ?, almacena la primera mitad $ay la segunda en $b.

A continuación, $bse reformula haciendo un ciclo $z, realizando una expresión regular -replaceen cada palabra de consulta prohibida para eliminarlas. Luego, las salidas $a(sin modificar), más un /dependiendo de si $bexiste, más un ?dependiendo de si $xexiste, más `$ x.

AdmBorkBork
fuente
1

Pyth - 27 bytes

Kenny estaba en lo cierto cuando habló sobre el proceso de transformación y luego inversión, sin embargo, será muy difícil corregirlo.

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

Test Suite .

Maltysen
fuente
1

Retina , 44 48 bytes

Tachado 44 sigue siendo 44. Gracias a Martin por la solución.

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

/&
/?

Toma entrada como uri param1 param2. Pruébalo en línea!

Explicación

El primer reemplazo elimina los parámetros apropiados de la cadena de consulta. [?&](?>([^ =&+))[^ &]*coincide con un ?o &, un nombre de parámetro completo, y (opcionalmente) =y un valor, almacenando el nombre del parámetro en el grupo de captura 1. Luego (?=.* \1( |$))hay una búsqueda anticipada que verifica si ese nombre de parámetro aparece en la lista de parámetros para eliminar. Si un parámetro coincide con estas condiciones, se elimina (sustituye con un reemplazo vacío).

Las sustituciones no se superponen (gracias a la búsqueda anticipada) y proceden de izquierda a derecha. Al llegar al final de la URL, la .*rama coincide con la lista de parámetros para eliminar y también la elimina.

El segundo reemplazo solo se asegura de que la nueva cadena de consulta comience ?si se eliminó el primer parámetro.

DLosc
fuente
Creo que esto también elimina los parámetros si aparece un prefijo en la lista al final (por ejemplo, intente retina.tryitonline.net/… ). Una forma de solucionar esto es envolver el grupo 1 (?>...).
Martin Ender
@MartinEnder TIL sobre subexpresiones sin retroceso. ¡Gracias!
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;}

Sin golf:

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

Esta función pasa todas las pruebas.

acrolito
fuente
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('&?')

Una función con nombre. Toma entrada en el formato

D(<String>,<Array>)

y genera una cadena.

Repl.it con todos los casos de prueba!

R. Kap
fuente
0

PHP, no compitiendo

Diablos, PHP fue hecho para esto; ¿Por qué no usar la URL real?

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

Guardar en el archivo, llamar con la cadena de consulta deseada más &x[]=x&x[]=<exclude1>&x[]=<exclude2>&... .

Puede fallar el nombre de usuario y la contraseña (dependiendo de si su navegador los elimina o no).
Se producirá un error si la contraseña es 0.

Titus
fuente