status-line trailing SP is missing ?

Maxim Dounin mdounin at mdounin.ru
Tue Aug 29 04:33:23 UTC 2023


Hello!

On Mon, Aug 28, 2023 at 08:59:28PM +0400, Sergey Kandaurov wrote:

> 
> > On 26 Aug 2023, at 18:21, Jérémy Lal <kapouer at melix.org> wrote:
> > 
> > Hi,
> > 
> > https://bugs.debian.org/1050571
> > reports that the Status line doesn't always end with space, which seems contradictory to RFC9112 which states:
> > "A server MUST send the space that separates the status-code from the reason-phrase even when the reason-phrase is absent (i.e., the status-line would end with the space)."
> > 
> > Is it a documented nginx 1.24.0 behavior ?
> > 
> 
> Note that the response line with empty reason phrase
> is properly generated since nginx 1.5.6.
> The exception remains is proxying FastCGI responses
> as there is no distinguished response line in CGI syntax.
> 
> The reason is that Status is a CGI header field, and hence
> it is parsed by a generic routine that cuts trailing spaces.
> But it can have a trailing space per RFC 3875, section 6.3.3.
> So it needs a special treatment to preserve SP before empty reason
> phrase.  The below patch should help; although it doesn't look
> efficient and can be polished, I think this is quite enough for
> valid use cases.

I very much doubt that RFC 3875 properly defines whitespace 
handling, see my response to the original report.  In this 
particular case, it seems to define a header which cannot be 
correctly parsed if reason-phrase is empty.

> 
> # HG changeset patch
> # User Sergey Kandaurov <pluknet at nginx.com>
> # Date 1693238094 -14400
> #      Mon Aug 28 19:54:54 2023 +0400
> # Node ID f621c60dfa277774ab5fadb3c8b805957ca3f281
> # Parent  2880f60a80c3e2706151dc7b48dc1267e39c47a9
> FastCGI: preserved SP for empty Status header reason phrase.
> 
> diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
> --- a/src/http/modules/ngx_http_fastcgi_module.c
> +++ b/src/http/modules/ngx_http_fastcgi_module.c
> @@ -2048,7 +2048,25 @@ ngx_http_fastcgi_process_header(ngx_http
>                      }
>  
>                      u->headers_in.status_n = status;
> -                    u->headers_in.status_line = *status_line;
> +
> +                    if (status_line->len == 3) {
> +                        /* preserve SP for empty reason phrase */
> +
> +                        u->headers_in.status_line.data = ngx_pnalloc(r->pool,
> +                                                                     5);
> +                        if (u->headers_in.status_line.data == NULL) {
> +                            return NGX_ERROR;
> +                        }
> +
> +                        ngx_memcpy(u->headers_in.status_line.data,
> +                                   status_line->data, 3);
> +                        u->headers_in.status_line.data[3] = ' ';
> +                        u->headers_in.status_line.data[4] = '\0';
> +                        u->headers_in.status_line.len = 4;
> +
> +                    } else {
> +                        u->headers_in.status_line = *status_line;
> +                    }
>  
>                  } else if (u->headers_in.location) {
>                      u->headers_in.status_n = 302;

Do you think we really need this complexity here?  I tend to think 
that

    if (status_line->len > 3) {
        u->headers_in.status_line = *status_line;
    }

would be enough, so nginx will generate status line by itself for 
such headers.

The only downside I can see is that it will provide no way to 
actually generate a response with well-known status code, yet with 
an empty reason phrase.

(Also note that uwsgi and scgi modules needs to be patched 
similarly.)

> Alternatively, the reason-phrase value from FastCGI response 
> can be ignored, nginx will translate it with its own value:
> 
> # HG changeset patch
> # User Sergey Kandaurov <pluknet at nginx.com>
> # Date 1693241054 -14400
> #      Mon Aug 28 20:44:14 2023 +0400
> # Node ID f1a452cbd57ff4fba1caf3f36cb3624bd45411ea
> # Parent  2880f60a80c3e2706151dc7b48dc1267e39c47a9
> FastCGI: preserved SP for empty Status header reason phrase.
> 
> As per RFC 3875 sec 6.3.3, the status code is always followed by SP.
> The header is parsed by the common routine, and it can be challenging
> to properly translate empty reason phrase to HTTP/1.1 status line, as
> that would require an additional memory allocation.  For simplicity,
> the reason phrase is now ignored; the header filter will take care of
> it by inserting its own reason phrase for well known status codes.
> 
> diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
> --- a/src/http/modules/ngx_http_fastcgi_module.c
> +++ b/src/http/modules/ngx_http_fastcgi_module.c
> @@ -2048,7 +2048,6 @@ ngx_http_fastcgi_process_header(ngx_http
>                      }
>  
>                      u->headers_in.status_n = status;
> -                    u->headers_in.status_line = *status_line;
>  
>                  } else if (u->headers_in.location) {
>                      u->headers_in.status_n = 302;

I don't think it's a good idea, since this always drops the 
reason phrase provided by the upstream server.  It can contain 
some meaningful information which will be lost as a result, most 
notably for non-standard error codes.

-- 
Maxim Dounin
http://mdounin.ru/


More information about the nginx mailing list