﻿id	summary	reporter	owner	description	type	status	priority	milestone	component	version	resolution	keywords	cc	uname	nginx_version
907	OPTIONS request timeout in Firefox (but only in a somewhat complicated situation)	Pyry Hakulinen		"We noticed that CORS preflight OPTIONS requests don't work in the following scenario:

1) have a HTTP/2 enabled frontend
2) proxy_pass from frontend to backend
3) Use upstream keepalive (and the OPTIONS request needs to go through already open connection)
4) Use https:// upstream
5) Client needs to be Firefox (tested with 44.0.2 on Ubuntu 15.10, but it's not limited to Linux)

Everything works fine if we disable anything from the above list, it's just this combination that reliably fails to work. Debug logs are attached to the ticket (includes initial request to get the backend upstream keepalive connection going).

Steps to reproduce (tested on Ubuntu 14.04, but should be quite general):

1) Download nginx-1.9.11 & openssl-1.0.2f

2) Compile: {{{./configure --with-ipv6 --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-openssl=../openssl-1.0.2f --with-debug && make && make install}}}

3) Make some self signed certificates:
{{{cd /usr/local/nginx/conf;for i in api frontend backend;do openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout $i.example.com.key -out $i.example.com.cert -subj /CN=$i.example.com;done}}}

4) Configure /usr/local/nginx/conf/nginx.conf
{{{
worker_processes  1;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;

    keepalive_timeout  65;

    upstream _backend {
        server 127.0.0.8:8888;
        keepalive 32;
    }

    server {
        listen 443 http2 ssl;

        server_name frontend.example.com;

        ssl_certificate frontend.example.com.cert;
        ssl_certificate_key frontend.example.com.key;
    }

    server {
        listen 443 http2 ssl;

        server_name api.example.com;

        ssl_certificate api.example.com.cert;
        ssl_certificate_key api.example.com.key;

        location / {
            proxy_pass https://_backend;
            proxy_http_version 1.1;
            proxy_set_header Connection """";
        }
    }

    server {
        listen 127.0.0.8:8888 ssl;

        server_name backend.example.com;

        ssl_certificate backend.example.com.cert;
        ssl_certificate_key backend.example.com.key;

        root html/backend;
    }
}
}}}
5) Add testing file to /usr/local/nginx/html/cors.html
{{{
<html>
<head>
</head>
<body>
Sending CORS preflight options request. Error: <span id=""error""></span>
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/');
xhr.setRequestHeader('X-Foo', 'bar'); // This will trigger a preflight OPTIONS request
xhr.onerror = function() {
  document.getElementById(""error"").innerHTML = ""xhr failed"";
};
xhr.send();       
</script>
</body>
}}}
6) Add hosts file entries for api.example.com and frontend.example.com
7) Launch Firefox
8) Navigate to https://api.example.com/ and https://frontend.example.com/ and accept the self-signed certificates
9) Restart nginx (to make sure we are in a clean state)
10) Navigate to https://frontend.example.com/cors.html and page should (quickly) show: ""Sending CORS preflight options request. Error: xhr failed"" (this means everything is working)
11) Reload the page, and it will just show ""Sending CORS preflight options request. Error: "" (this means that the OPTIONS request is somehow stuck in nginx)
12) Eventually nginx disconnects the upstream connection and tries again, this time the request will work."	defect	closed	minor		nginx-core	1.9.x	fixed	http2		Linux somehost.fi 3.11.0-12-generic #19-Ubuntu SMP Wed Oct 9 16:20:46 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux	"nginx version: nginx/1.9.11
built by gcc 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
built with OpenSSL 1.0.2f  28 Jan 2016
TLS SNI support enabled
configure arguments: --with-ipv6 --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-openssl=../openssl-1.0.2f --with-debug"
