Opened 21 months ago
Closed 20 months ago
#2457 closed defect (duplicate)
Nginx changes HTTP 413 Payload Too Large response status to HTTP 502 Bad Gateway response status
Reported by: | Tobias Riemenschneider | Owned by: | |
---|---|---|---|
Priority: | major | Milestone: | |
Component: | nginx-core | Version: | 1.23.x |
Keywords: | Cc: | ||
uname -a: | Linux 38dbd7b91b9f 5.10.102.1-microsoft-standard-WSL2 #1 SMP Wed Mar 2 00:30:59 UTC 2022 x86_64 GNU/Linux | ||
nginx -V: |
nginx version: nginx/1.23.3
built by gcc 10.2.1 20210110 (Debian 10.2.1-6) built with OpenSSL 1.1.1n 15 Mar 2022 TLS SNI support enabled configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -ffile-prefix-map=/data/builder/debuild/nginx-1.23.3/debian/debuild-base/nginx-1.23.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' |
Description
I am running a Vert.x core HTTP server behind a Nginx load balancer and limiting the body size via a BodyHandler
in the Vert.x core HTTP server.
When hitting the body limit, the Vert.x core HTTP responds with HTTP 413 Payload Too Large
response status. In most of the cases, Nginx simply passes this response to the client. But sometimes Nginx responds with HTTP 502 Bad Gateway
response status.
After enabling request and network activity logging and checking the Nginx error log I found that in these cases Nginx changes HTTP 413 Payload Too Large
response status to HTTP 502 Bad Gateway
response status due to an error
2022/10/28 21:08:12 [error] 9072#9072: *3583678 upstream prematurely closed connection while reading response header from upstream, client: 172.156.0.99, server: management.datahub5.stage.c8y.io, request: "POST /service/datahub/scheduler/gettriggerstatus HTTP/1.1", upstream: "http://172.156.0.197:8303/service/datahub/scheduler/gettriggerstatus", host: "cdh-testing2.datahub5.stage.c8y.io:443"
I had a look at the implementation of BodyHandlerImpl
in Vert.x and it looks like the 413 Payload Too Large
response status is already sent when the request contains HTTP Content-Length
header and the set value is larger than the configured body limit.
Nginx is able to handle that situation most of the time but sometimes the mentioned error is logged and the response status is changes as described. It looks like Nginx is still reading the response while the Vert.x core HTTP server already closed the connection.
I created a reproducer for that issue. You can find it in the public GitHub repository riemenschneider/VertxWebIssue2295. Just clone the repo and run gradlew cleanTest test
. The test uses port 9090 for the Vert.x HttpServer and port 9091 for the Nginx loadbalancer. If you want to run the test using other ports you can configure it via system properties (gradlew cleanTest test -DHTTP_SERVER_PORT=9096 -DLOADBALANCER_PORT=9097 -DLOG_ACTIVITY=true
). Beware of turning log activity on since I had to play around with 1MB payloads! (For more details see README.md of the repository containing the reproducer.)
The Nginx loadbalancer is running in Docker and is configured via
events { } http { server { listen 0.0.0.0:9091; location / { proxy_pass http://backend; } } upstream backend { server host.docker.internal:9090; } client_max_body_size 10M; }
Interestingly, I was not able to deterministically reproduce the issue in this reproducer although we can reproduce it deterministically in our product test suite. Therefore, I repeat the test several times which leads to a reproduction in nearly every test run.
Change History (2)
comment:1 by , 21 months ago
comment:2 by , 20 months ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
This looks like a missing lingering close on the backend server side, so RST is sent to nginx if sending request body to the backend happens to hit the already closed socket (see #1673, #1211, #1037 for detailed explanations), and this prevents nginx from getting any response. Does your backend server implements lingering close?