Czy bloki lokalizacji nginx mogą pasować do ciągu zapytania adresu URL?

23

Czy bloki nginx mogą pasować do ciągu zapytania URL?location

Na przykład, jaki blok lokalizacji może pasować do GETżądania HTTP

GET /git/sample-repository/info/refs?service=git-receive-pack HTTP/1.1
Derek Mahar
źródło
Domyślam się, że „location / git / sample-repository / info / refs? Service = git-receive-pack”, ponieważ nginx po prostu porównuje ciąg znaków.
JosefScript,
Porównanie ciągów całego adresu URL lub tylko części przed znakiem zapytania ( ?)?
Derek Mahar
1
Ostatnie wyjaśnienie, gdy sam natknąłem się na ten problem: nginx.org/en/docs/http/request_processing.html wyraźnie stwierdza: „Pamiętaj, że lokalizacje wszystkich typów testują tylko część URI wiersza żądania bez argumentów. Dzieje się tak, ponieważ argumenty w ciągu zapytania można podać na kilka sposobów ”
Thomas Urban

Odpowiedzi:

37

Czy bloki lokalizacji nginx mogą pasować do ciągu zapytania adresu URL?

Krótka odpowiedź : nie

Długa odpowiedź : istnieje obejście, jeśli mamy tylko kilka takich bloków lokalizacji.

Oto przykładowe obejście dla 3 bloków lokalizacji, które muszą pasować do określonych ciągów zapytań:

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

Możesz użyć $ query_string, $ args lub $ arg_fieldname. Wszyscy wykonają robotę. Możesz dowiedzieć się więcej o error_page w oficjalnych dokumentach .

Ostrzeżenie: nie używaj standardowych kodów HTTP .

Pothi Kalimuthu
źródło
1
Ciekawe podejście! Czy mogę polecić $args ~ "service=git-send-pack"zamiast $args = "service=git-send-pack"? Ten formularz obsługuje wiele parametrów zapytania.
Derek Mahar
1
stackoverflow.com/a/40313590/107158 ilustruje podejście, które zastosowałem do obsługi argumentów ciągu zapytania. Podobnie jak twoja odpowiedź, moje używa ifi $arg_fieldname, ale używa rewritezamiast error_pagei location @name. Zauważ, że w tym przykładzie, moje próby używając @namedo zastępczego parametru rewritebyły nieudane.
Derek Mahar
1
Nawiasem mówiąc, powinno być $args ~i $arg_somerandomfield =.
Derek Mahar
1
W maptym celu można również użyć funkcji nginx , która jest szybsza.
Tero Kilkanen
1
@PothiKalimuthu, dzięki za wyjaśnienie tego. Tymczasem zrobiłem tymczasem zastąpienie queryparametru ścieżką URL taką jak ta feedback/{auth_key}zamiast /feedback?auth_key=abc. W ten sposób nie muszę używać if, mogę zdefiniować wzór lokalizacji za pomocą regexi to wszystko.
WM
4

Wiem, że to pytanie ma ponad rok, ale ostatnie kilka dni spędziłem na niszczeniu mózgu przez podobny problem. Chciałem różnych zasad uwierzytelniania i obsługi publicznych i prywatnych repozytoriów, w tym wypychania i wyciągania. To w końcu wymyśliłem, więc pomyślałem, że podzielę się. Wiem, że ifjest to trudna dyrektywa, ale wydaje mi się, że to działa dobrze:

# 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
źródło