2

(The situation that caused the question is pretty defined and not abstract. But I know applicable to it workarounds thus I dropped details in order to get general pipeline that answers to this question.)

Problem description: Imagine that you have one location NGINX block and you want to have possibility to response in this block in different ways depending on requests' HTTP method. But NGINX does not support syntax like location /:POST {...}, some more complex way is needed.

I tried to find the answer to this question and all my findings can be classificated into these groups:

Group 1: if ($request_method ...) inside location

But If is Evil .

As for me, the pure if way does not work without copying directives into if clause from external "common" space. Moreover, all copied directives are not approved to be inside by NGINX's developers.

Only return and rewrite is approved to be inside if but it is not enough.

Group 2: limit_except

This way is applicable if you want to restrict some methods for a location. But it does not allow distinguishing behavior for each HTTP method group for the same location.

Group 3: lets map everything

Many if cases can be replaced by one/two/... proper map block(s). $request_method can also be mapped but what if it is not enough or pretty just map several times? How, for example, to proxy_pass requests with one HTTP method and perform try_files for requests with the same location and another HTTP method without if? (Not my situation, just example of two incompatible directives not allowed in if). How to avoid 10+ maps that can be needed for even one conditioning.

Group 4: proxying to different upstream blocks

This way is quite complex and looks like a overkill. Moreover, if you need something else than just proxying (for endpoint selection map is enough) you have to create a new virtual host. Also pieces of the implementation are located far apart.

Nick Vee
  • 621
  • 2
  • 7
  • 17
  • I don't see a main question in the text. I don't understand. Can you please elaborte on the question in the title? – qräbnö Mar 06 '21 at 13:21
  • @qräbnö I added the description. Does it fulfil your request? – Nick Vee Mar 06 '21 at 14:59
  • This is the problem I faced in [Nginx fully open cors with basic authentication without if](https://stackoverflow.com/questions/72158566/nginx-fully-open-cors-with-basic-authentication-without-if) and solved it, too. – chx May 10 '22 at 07:12

1 Answers1

1

While I was writing the question I came up with the idea of error pages and named locations. However, the question has been submitted as a possibility to gather more solutions+opinions and help somebody.

Own idea 1: Error pages and named locations

return allows returning a error code without explicit redirection. But with providing a non-standard error code own error handler that just extend the functionality can be defined.

Sometimes ago I found this technique as a solution of the "duplicated in-location directives" problem (the directives were placed at the error handler and the locations return the error code of the handler in addition to different directives of the locations).

Usage example:

map $request_method $handler_code {
    GET 598;
    POST 599;
    default 405;  # Method Not Allowed
}

server {
    ...
    error_page 598 = @get_handler;
    location @get_handler {
        # only GET routine
    }
    error_page 599 = @post_handler;
    location @post_handler {
        # only POST routine
    }

    location / {
        ... # Common routine
        return $handler_code;
        ...
    }
    ...
}
Nick Vee
  • 621
  • 2
  • 7
  • 17
  • `nginx: [emerg] invalid return code "$handler_code" in /etc/nginx/conf.d/app.conf:17` – chx May 10 '22 at 04:14
  • Sorry for the late answer. It looks like NGINX was thinking that `$handler_code` is a string. Basing on this, I recommend check the following: 1) Do not put quotes around `$handler_code` ; 2) Check that `$handler_code` is written correctly in the `map` definition and that this `map` definition is located higher than `$handler_code` call. – Nick Vee Jun 05 '22 at 15:29