Sergey Kandaurov
September 13, 2021 07:52AM
> On 13 Sep 2021, at 12:32, Tim Siebels <tim.siebels@iserv.eu> wrote:
>
> Hi everyone,
>
> We are experiencing an issue when using `fastcgi_request_buffering off;` in combination with chunked transfer-encoding. The application will not receive any body. Depending on the system, we *sometimes* receive a body. Enabling `fastcgi_request_buffering` fixes the issue. However, we would like not to enable this for every request.
>
> We are using Debian Bullseye [0]. Additionally, I was able to reproduce this issue using a self compiled 1.21.3 [1].
>
> We are using a very simple configuration [2], only disabling `fastcgi_request_buffering`. The application is using PHP over fastcgi [3].
>
> Furthermore, we log `$request_body` in a custom log file.
> Whenever this logfile contains the expected request body, the application receives the expected body. As far as I understand, this cannot work without buffering. I assume this to be an in-memory buffer. This goes in line with the body not being passed, when we increase the size. The implementation of `ngx_http_read_client_request_body` does have an optimization, if the entire body fits into header_in.
> `sleep`ing between chunks also removes the possibility that the body is passed to the application.
> We could not reproduce that the body is *sometimes* passed in a self-contained docker container or using a self-compiled version of nginx.
> These never work with fastcgi_request_buffering off. At least not, if the body is large enough.


>
> Apache had a bug that had a similar effect [4,5,6].
> Our understanding from these bugreports is, that the fastcgi protocol expects a defined content-length to be able to read the request body.

FastCGI is essentially a protocol with builtin chunked encoding,
see http://www.mit.edu/~yandros/doc/specs/fcgi-spec.html#S3.3.
Hence, the Content-Length header is rather complementary (like in HTTP/2),
e.g. it allows to communicate the message length knowledge in advance.

So, when nginx doesn't buffer request body, and it's not wholly present
in the request body memory buffers at the time of forming request headers,
in this case the length cannot be calculated for chunked body requests.
See also the description of $content_length: nginx.org/r/$content_length

> Our conclusion is, that nginx is supposed to buffer all request with a chunked transfer-encoding, when using fastcgi. Regardless of the fastcgi_request_buffering option. A comment on a older, unrelated, bugreport for nginx confirms this [7].
> Therefore, we expect this to be a supported use case.

When a client uses chunked transfer encoding, and nginx is configured
to pass requests to fastcgi with disabled fastcgi_request_buffering,
the intent is to pass request body chunks to backend (with conversion
to fastcgi records) as soon as they are received from a client.

>
> There are some bug reports out there experiencing similar issues [8,9].
>

Looks like they are suffering from the same sort of a problem.

> We tried to set `client_body_in_file_only` to `on` to be able to see the buffer files. However, these are never created with buffering off.
>

It is disabled in the unbuffered mode.

> error.log is empty.
>
> Can anyone help us how to debug this further?

For a start, you may want to examine what is actually passed to backend.

>
> Thanks,
> Tim
>
> [..]
> [2]
> user nginx;
> worker_processes auto;
> pid /run/nginx.pid;
>
> events {
> worker_connections 768;
> }
>
> http {
> access_log /var/log/nginx/access.log;
> error_log /var/log/nginx/error.log;
>
> fastcgi_request_buffering off;
>
> include /etc/nginx/sites-enabled/*;
> }
>
> [3]
> log_format postdata '"$request" $status $request_body ($request_length)';
>
> server {
> listen *:982;
>
> location /iserv/helloworld {
> root /usr/share/iserv/helloworld/public;
>
> access_log /var/log/nginx/postdata.log postdata;
>
> fastcgi_param QUERY_STRING $query_string;
> fastcgi_param REQUEST_METHOD $request_method;
> fastcgi_param CONTENT_TYPE $content_type;
> fastcgi_param CONTENT_LENGTH $content_length;

Looks like the backend is expecting to receive something
in the CONTENT_LENGTH header to read the request body.

The best solution is to teach your FastCGI backend how to receive
the request body without CONTENT_LENGTH.

>
> fastcgi_param SCRIPT_NAME $fastcgi_script_name;
> fastcgi_param REQUEST_URI $request_uri;
> fastcgi_param DOCUMENT_URI $document_uri;
> fastcgi_param DOCUMENT_ROOT $document_root;
>
> fastcgi_param SCRIPT_FILENAME $document_root/index.php$fastcgi_script_name;
>
> fastcgi_pass unix:/run/php/php-fpm.iserv-helloworld.sock;
> }
>
> }
>
> [4] https://bz.apache.org/bugzilla/show_bug.cgi?id=53332
> [5] https://bz.apache.org/bugzilla/show_bug.cgi?id=57087
> [6] https://bugs.php.net/bug.php?id=60826
> [7] https://trac.nginx.org/nginx/ticket/1344
> [8] https://trac.cyberduck.io/wiki/help/en/howto/mount/issues/fastcgi
> [9] https://github.com/nextcloud/server/issues/7995
> _______________________________________________
> nginx mailing list
> nginx@nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx

--
Sergey Kandaurov

_______________________________________________
nginx mailing list
nginx@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx
Subject Author Posted

No request body when using fastcgi and chunked transfer-encoding

Tim Siebels September 13, 2021 05:34AM

Re: No request body when using fastcgi and chunked transfer-encoding

Sergey Kandaurov September 13, 2021 07:52AM

Re: No request body when using fastcgi and chunked transfer-encoding

Tim Siebels September 13, 2021 11:58AM



Sorry, only registered users may post in this forum.

Click here to login

Online Users

Guests: 266
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready