Upstream keepalive connections do not properly handle early error responses
|Reported by:||Roman Borschel||Owned by:|
|uname -a:||Darwin yoda.local 13.4.0 Darwin Kernel Version 13.4.0: Sun Aug 17 19:50:11 PDT 2014; root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64|
nginx version: nginx/1.7.7
built by clang 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
TLS SNI support enabled
configure arguments: --prefix=/usr/local/Cellar/nginx/1.7.7 --with-http_ssl_module --with-pcre --with-ipv6 --sbin-path=/usr/local/Cellar/nginx/1.7.7/bin/nginx --with-cc-opt='-I/usr/local/Cellar/pcre/8.36/include -I/usr/local/Cellar/openssl/1.0.1j/include' --with-ld-opt='-L/usr/local/Cellar/pcre/8.36/lib -L/usr/local/Cellar/openssl/1.0.1j/lib' --conf-path=/usr/local/etc/nginx/nginx.conf --pid-path=/usr/local/var/run/nginx.pid --lock-path=/usr/local/var/run/nginx.lock --http-client-body-temp-path=/usr/local/var/run/nginx/client_body_temp --http-proxy-temp-path=/usr/local/var/run/nginx/proxy_temp --http-fastcgi-temp-path=/usr/local/var/run/nginx/fastcgi_temp --http-uwsgi-temp-path=/usr/local/var/run/nginx/uwsgi_temp --http-scgi-temp-path=/usr/local/var/run/nginx/scgi_temp --http-log-path=/usr/local/var/log/nginx/access.log --error-log-path=/usr/local/var/log/nginx/error.log --with-http_gzip_static_module
When using upstream keepalive connections and the upstream server sends an error response while nginx is still transmitting the request body (of a request with a Content-Length header), nginx eventually stops transmitting the body (which may be before the full body has been transmitted) but continue to reuse the connection for further requests. This in turn causes the next request on that connection to get "stuck" since the upstream server is seeing it as just more data for the prior request.
A more detailed, recent discussion and description of the problem on the mailing list where the bug was already confirmed:
A prior discussion:
This behaviour is in violation of RFC2616, section 8.2.2:
The desired (and correct) behaviour would be one of the following:
- Continue sending the full request body (thus leaving the decision of whether to abort early to the client).
- Close the upstream connection.
- Depending on whether a Content-Length is present or whether chunked transfer encoding is used, either close the connection or send a zero-length chunk and an empty trailer to mark the end of the request.