0

The common solution to handling CORS requests is as follow:

location ... {
    add_header  Access-Control-Allow-Origin       ...;
    add_header  Access-Control-Allow-Credentials  ...;
    add_header  Access-Control-Allow-Headers      ...;
    add_header  Access-Control-Allow-Methods      ...;

    if ($request_method = 'OPTIONS') {
        add_header  Access-Control-Allow-Origin       ...;
        add_header  Access-Control-Allow-Credentials  ...;
        add_header  Access-Control-Allow-Headers      ...;
        add_header  Access-Control-Allow-Methods      ...;
        return 204;
    }
}

But if is evil. Is it safe to use it this way?

UPD By the way, from what I can see, the duplicate add_header's are not needed.

x-yuri
  • 16,722
  • 15
  • 114
  • 161
  • 1
    It’s OK. From the http://nginx.com/resources/wiki/start/topics/depth/ifisevil page cited: *“There are cases where you simply cannot avoid using an `if`, for example, if you need to test a variable which has no equivalent directive”* & has a when-it-can’t-be-avoided example that’s functionally identical to the case in the question: `if ($request_method = POST ) { return 405; }` So the answer is: You can’t avoid it for this case. That doesn’t make it “safe” as far as lacking the risk http://nginx.com/resources/wiki/start/topics/depth/ifisevil describes— but just that there’s no real alternative – sideshowbarker Jan 15 '21 at 23:28

1 Answers1

0

You don't need an if. Take several maps (outside of location or server block -> works only in http block).

map $request_method $one
{
    default '…';
    get '…';
    options '…';
    post '…';
}

map $request_method $two
{
    default '…';
    get '…';
    options '…';
    post '…';
}

map $request_method $three
{
    default '…';
    get '…';
    options '…';
    post '…';
}

map $request_method $four
{
    default '…';
    get '…';
    options '…';
    post '…';
}

Strings are matched ignoring the case. As long as it's not a normal regex.

The first parameter of the map is the input (in this case $request_method). Depending on the match, a new variable is created in the second parameter of the map (in this case $one, $two, $three, $four (which you can name as you wish)) with the matched '…' content.

more_set_headers 'Access-Control-Allow-Origin: $one';
more_set_headers 'Access-Control-Allow-Credentials: $two';
more_set_headers 'Access-Control-Allow-Headers: $three';
more_set_headers 'Access-Control-Allow-Methods: $four';

Untested.

qräbnö
  • 2,722
  • 27
  • 40
  • 1
    You're forgetting the `return` statement. And why `more_set_headers`? – x-yuri Jan 16 '21 at 20:26
  • Oops, right. Because I always use it - it is more intelligent. But are you sure that you need `return 204` at all? For example, if I query with `curl -I`, no content is sent with it. I checked with Wireshark. – qräbnö Jan 16 '21 at 21:19
  • Not exactly need, the network etiquette obliges :) If seriously, you might be right, or not. It's hard to confirm. You can check if this (response `200` for `OPTIONS` requests) causes no issues in the common browsers. But you can't be 100% sure it works for everyone. Most likely you can find some user agent if you look hard enough for which it doesn't. And by the way I don't understand what kind of requests you were making, and what that proves. – x-yuri Jan 17 '21 at 09:41
  • You are right. `curl -I` only queries the headers (`HEAD`). Better would be `curl -i -X OPTIONS https://www.google.com/`. However, I only get a 405 Not Allowed. – qräbnö Jan 17 '21 at 10:36