Opened 10 months ago

Last modified 10 months ago

#2604 new defect

Errors handling when streaming

Reported by: inbox.artembokhan.com@… Owned by:
Priority: minor Milestone:
Component: documentation Version: 1.25.x
Keywords: Cc:
uname -a: 5.14.0-162.23.1.el9_1.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Apr 11 19:09:37 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.25.3
built by gcc 11.3.1 20221121 (Red Hat 11.3.1-4) (GCC)
built with OpenSSL 3.0.7 1 Nov 2022
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/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-http_v3_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='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64-v2 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'

Description (last modified by inbox.artembokhan.com@…)

Hello!

I have an application which streams data using http1.1 and chunked transfer-encoding.

nginx is used as http1.1/http2 proxy. http1.1 is used to communicate with an upstream with proxy_buffering off.

When application aborts streaming the expected behavior is to get an error on client's side.

That works well with http1.1

$ curl --http1.1 -i localhost:8083
HTTP/1.1 200 OK
Server: nginx/1.25.3
Date: Wed, 14 Feb 2024 17:25:56 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive

Random Line 1: 2y1a0XrIc5
Random Line 2: KwIrtX5B5h
[...]
Random Line 442: FDo6cv5f4h
Random Line 443:curl: (18) transfer closed with outstanding read data remaining

but works randomly with http2. Curl may hang, exit with zero code or with error

$ curl --http2-prior-knowledge -i localhost:8082
HTTP/2 200
server: nginx/1.25.3
date: Wed, 14 Feb 2024 17:28:12 GMT
content-type: text/plain; charset=utf-8

Random Line 1: 9L02Z5qokm
Random Line 2: gR8emalzhl
[...]
Random Line 441: CbmbnKY2EC
Random Line 442: JsiYbH9Bwp
curl: (92) HTTP/2 stream 0 was not closed cleanly: INTERNAL_ERROR (err 2)

Also tested with haproxy 2.9.4 which works stable

~$ curl --http2-prior-knowledge -i localhost:8081
HTTP/2 200
date: Wed, 14 Feb 2024 17:30:54 GMT
content-type: text/plain; charset=utf-8

Random Line 1: CclkQfagoE
Random Line 2: 9TPlR0U51t
[...]
Random Line 441: JRMeZwNvoW
Random Line 442: 6m0PZcOe8C
curl: (92) HTTP/2 stream 0 was not closed cleanly: CANCEL (err 8)

Earlier versions of haproxy have issues too.

Please fix if possible

Change History (2)

comment:1 by inbox.artembokhan.com@…, 10 months ago

Description: modified (diff)

comment:2 by Roman Arutyunyan, 10 months ago

NGINX resets http/2 stream with:

  • NO_ERROR (0x0) if response was fully sent
  • PROTOCOL_ERROR (0x01) in case of timeout
  • INTERNAL_ERROR (0x2) in all other cases

So yes, aborting connection by upstream falls under the third case. The code that does this knows nothing about the upstream (and if it's proxying at all) so it acts accordingly. So far I don't see enough reasons for a different behavior. RFC 9113 does not provide details about the CANCEL (0x08) code other than in response to a pushed stream, which is not the case here.

Note: See TracTickets for help on using tickets.