¿Pueden los bloques de ubicación nginx coincidir con una cadena de consulta de URL?

23

¿Pueden los bloques nginx coincidir con una cadena de consulta de URL?location

Por ejemplo, qué bloque de ubicación podría coincidir con la GETsolicitud HTTP

GET /git/sample-repository/info/refs?service=git-receive-pack HTTP/1.1
Derek Mahar
fuente
Supongo que "location / git / sample-repository / info / refs? Service = git-recibir-paquete" como nginx solo hace la comparación de cadenas.
JosefScript
Comparación de cadenas de la URL completa o solo la parte anterior al signo de interrogación ( ?)?
Derek Mahar
1
nginx.org/en/docs/http/…
JosefScript el
1
Algunas últimas aclaraciones cuando me topé con este problema: nginx.org/en/docs/http/request_processing.html establece claramente: "Tenga en cuenta que las ubicaciones de todos los tipos prueban solo una parte URI de la línea de solicitud sin argumentos. Esto se hace porque los argumentos en la cadena de consulta se puede dar de varias maneras "
Thomas Urban

Respuestas:

37

¿Pueden los bloques de ubicación nginx coincidir con una cadena de consulta de URL?

Respuesta corta : no.

Respuesta larga : hay una solución alternativa si solo tenemos un puñado de dichos bloques de ubicación.

Aquí hay una solución alternativa de muestra para 3 bloques de ubicación que deben coincidir con cadenas de consulta específicas:

server {
  #... common definitions such as server, root

  location / {
    error_page 418 = @queryone;
    error_page 419 = @querytwo;
    error_page 420 = @querythree;

    if ( $query_string = "service=git-receive-pack" ) { return 418; }
    if ( $args ~ "service=git-upload-pack" ) { return 419; }
    if ( $arg_somerandomfield = "somerandomvaluetomatch" ) { return 420; }

    # do the remaining stuff
    # ex: try_files $uri =404;

  }

  location @queryone {
    # do stuff when queryone matches
  }

  location @querytwo {
    # do stuff when querytwo matches
  }

  location @querythree {
    # do stuff when querythree matches
  }
}

Puede usar $ query_string, $ args o $ arg_fieldname. Todos harán el trabajo. Puede saber más sobre error_page en los documentos oficiales .

Advertencia: asegúrese de no utilizar los códigos HTTP estándar .

Pothi Kalimuthu
fuente
1
Enfoque interesante! ¿Puedo recomendar en $args ~ "service=git-send-pack"lugar de $args = "service=git-send-pack"? Este formulario acomoda múltiples parámetros de consulta.
Derek Mahar
1
stackoverflow.com/a/40313590/107158 ilustra el enfoque que seguí para manejar argumentos de cadena de consulta. Al igual que su respuesta, la mía usa ify $arg_fieldname, pero usa en rewritelugar de error_pagey location @name. Tenga en cuenta que en ese ejemplo, mis intentos de usar @nameel parámetro de reemplazorewrite no tuvieron éxito.
Derek Mahar
1
Por cierto, debería ser $args ~y $arg_somerandomfield =.
Derek Mahar
1
También se puede usar la mapfunción nginx para este propósito, que es más rápido.
Tero Kilkanen
1
@PothiKalimuthu, gracias por aclarar esto. Mientras tanto, lo que he hecho es reemplazar el queryparámetro por una ruta de URL como esta en feedback/{auth_key}lugar de /feedback?auth_key=abc. De esta manera no necesito usar if, puedo definir el patrón de ubicación usando regexy eso es todo.
WM
4

Sé que esta pregunta tiene más de un año, pero he pasado los últimos días destruyendo mi cerebro por un problema similar. Quería diferentes reglas de autenticación y manejo para repositorios públicos y privados, incluyendo empujar y tirar. Esto es lo que finalmente se me ocurrió, así que pensé en compartir. Sé que ifes una directiva complicada, pero esto parece funcionar bien para mí:

# pattern for all repos, public or private, followed by username and reponame
location ~ ^(?:\/(private))?\/([A-Za-z0-9]+)\/([A-Za-z0-9]+)\.git(\/.*)?$ {

    # if this is a pull request
    if ( $arg_service = "git-upload-pack" ) {

        # rewrite url with a prefix
        rewrite ^ /upload$uri;

    }

    # if this is a push request
    if ( $arg_service = "git-receive-pack" ) {

        # rewrite url with a prefix
        rewrite ^ /receive$uri;

    }

}

# for pulling public repos
location ~ ^\/upload(\/([A-Za-z0-9]+)\/([A-Za-z0-9]+)\.git(\/.*)?)$ {

    # auth_basic "git";
    # ^ if you want

    # ...
    # fastcgi_pass unix:/var/run/fcgiwrap.socket;
    # ...

}

# for pushing public repos
location ~ ^\/receive(\/([A-Za-z0-9]+)\/([A-Za-z0-9]+)\.git(\/.*)?)$ {

    # auth_basic "git";
    # ^ if you want

    # ...
    # fastcgi_pass unix:/var/run/fcgiwrap.socket;
    # ...

}

# for pulling private repos
location ~ ^\/upload\/private(\/([A-Za-z0-9]+)\/([A-Za-z0-9]+)\.git(\/.*)?)$ {

    # auth_basic "git";
    # ^ if you want

    # ...
    # fastcgi_pass unix:/var/run/fcgiwrap.socket;
    # ...

}

# for pushing private repos
location ~ ^\/receive\/private(\/([A-Za-z0-9]+)\/([A-Za-z0-9]+)\.git(\/.*)?)$ {

    # auth_basic "git";
    # ^ if you want

    # ...
    # fastcgi_pass unix:/var/run/fcgiwrap.socket;
    # ...

}
Jared Brandt
fuente