diff -Nru uwsgi-2.0.28/debian/changelog uwsgi-2.0.28/debian/changelog --- uwsgi-2.0.28/debian/changelog 2025-03-02 20:27:35.000000000 +0100 +++ uwsgi-2.0.28/debian/changelog 2026-10-02 15:41:35.000000000 +0200 @@ -1,3 +1,11 @@ +uwsgi (2.0.28-9+deb13u1) unstable; urgency=medium + + * With TLS and slow Transfer-Encoding: chunked mode, uwsgi was returning a + 500 error. Add a patch to fix this (Closes: #1149707): + - 2050_Fix_Transfer-Encoding_chunked_brokenness_over_TLS.patch. + + -- Thomas Goirand Fri, 02 Oct 2026 15:41:35 +0200 + uwsgi (2.0.28-9) unstable; urgency=medium [ Alexandre Rossi ] diff -Nru uwsgi-2.0.28/debian/patches/2050_Fix_Transfer-Encoding_chunked_brokenness_over_TLS.patch uwsgi-2.0.28/debian/patches/2050_Fix_Transfer-Encoding_chunked_brokenness_over_TLS.patch --- uwsgi-2.0.28/debian/patches/2050_Fix_Transfer-Encoding_chunked_brokenness_over_TLS.patch 1970-01-01 01:00:00.000000000 +0100 +++ uwsgi-2.0.28/debian/patches/2050_Fix_Transfer-Encoding_chunked_brokenness_over_TLS.patch 2026-10-02 15:41:35.000000000 +0200 @@ -0,0 +1,51 @@ +Description: Retry the read after wait_read_hook in uwsgi_chunked_input_recv + It took me years to understand why OpenStack Glance wouldn't work over + uwsgi, and I finally found out. The issue is in uwsgi itself. + . + After uwsgi.wait_read_hook() reports the socket as readable, + uwsgi_chunked_input_recv() performed exactly one proto_read_body() and + returned -1 on ANY failure (including EAGAIN), aborting the chunked + input with "unable to receive chunked part". This works reasonably + well without TLS. + . + With TLS, POLLIN only means "some TLS bytes arrived"; OpenSSL routinely + consumes a partial record (split across TCP segments) and returns + SSL_ERROR_WANT_READ right after POLLIN. A single failed post-wait read + then aborted the request, so any Transfer-Encoding: chunked request + whose body does not arrive in one burst failed fast with an HTTP 500, + while the client was still sending the body. + . + This can be reproduced with a client that streams a large body in chunks + with pauses in between, or generates the body on the fly (e.g. piped + from another process), and works fine as soon as the whole body is + available at once. This description matches 100% what OpenStack Nova + and Glance are doing when doing a backup. + . + To fix this, this patch loops back to the read/wait cycle on EAGAIN + instead: EOF (rlen == 0). Hard errors still abort, while a partial + read now waits for the rest of the data. +Author: Thomas Goirand +Date: Fri, 2 Oct 2026 15:29:49 +0200 +Forwarded: https://github.com/unbit/uwsgi/pull/2781 +Bug-Debian: https://bugs.debian.org/1149707 +Last-Update: 2026-10-02 + +diff --git a/core/chunked.c b/core/chunked.c +index fe693aad4..1b4af07a3 100644 +--- a/core/chunked.c ++++ b/core/chunked.c +@@ -42,7 +42,13 @@ static ssize_t uwsgi_chunked_input_recv(struct wsgi_request *wsgi_req, int timeo + if (ret > 0) { + rlen = wsgi_req->socket->proto_read_body(wsgi_req, wsgi_req->chunked_input_buf->buf + wsgi_req->chunked_input_buf->pos, wsgi_req->chunked_input_buf->len - wsgi_req->chunked_input_buf->pos); + if (rlen > 0) return rlen; +- if (rlen <= 0) return -1; ++ if (rlen == 0) return -1; ++ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) { ++ // partial read, i.e. split TLS record or TCP segmentation, wait for the rest ++ continue; ++ } ++ uwsgi_error("uwsgi_chunked_input_recv()"); ++ return -1; + } + if (ret < 0) { + uwsgi_error("uwsgi_chunked_input_recv()"); diff -Nru uwsgi-2.0.28/debian/patches/series uwsgi-2.0.28/debian/patches/series --- uwsgi-2.0.28/debian/patches/series 2025-03-02 20:14:37.000000000 +0100 +++ uwsgi-2.0.28/debian/patches/series 2026-10-02 15:41:35.000000000 +0200 @@ -13,3 +13,4 @@ 1017_python3-compat.patch 2001_ensure_verbose_build.patch 2002_rename_py_plugins.patch +2050_Fix_Transfer-Encoding_chunked_brokenness_over_TLS.patch