[PATCH 08 of 12] Reworked ngx_http_parse_status_line() to avoid data assumptions
Maxim Dounin
mdounin at mdounin.ru
Fri Aug 8 20:09:03 UTC 2025
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1754683258 -10800
# Fri Aug 08 23:00:58 2025 +0300
# Node ID 9c5a58441dc9fd62280681e7f92b74b4e69e5104
# Parent 081c23342274d57259786c115dd55c08eb03ac9e
Reworked ngx_http_parse_status_line() to avoid data assumptions.
With this change, ngx_http_parse_status_line() does not assume anything
about ngx_http_status_t initial values, and does not need it to be cleared
on allocation or during reinitialization. Further, status->count is
no longer used at all, separate states are used instead.
Additionally, status digits parsing now does not permit spaces between
digits, which previously were allowed, yet resulted in incorrect status
line sent to the client.
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -1628,10 +1628,6 @@ ngx_http_proxy_reinit_request(ngx_http_r
return NGX_OK;
}
- ctx->status.code = 0;
- ctx->status.count = 0;
- ctx->status.start = NULL;
- ctx->status.end = NULL;
ctx->chunked.state = 0;
r->upstream->process_header = ngx_http_proxy_process_status_line;
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -489,7 +489,7 @@ ngx_http_scgi_handler(ngx_http_request_t
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
- status = ngx_pcalloc(r->pool, sizeof(ngx_http_status_t));
+ status = ngx_palloc(r->pool, sizeof(ngx_http_status_t));
if (status == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
@@ -985,19 +985,6 @@ ngx_http_scgi_create_request(ngx_http_re
static ngx_int_t
ngx_http_scgi_reinit_request(ngx_http_request_t *r)
{
- ngx_http_status_t *status;
-
- status = ngx_http_get_module_ctx(r, ngx_http_scgi_module);
-
- if (status == NULL) {
- return NGX_OK;
- }
-
- status->code = 0;
- status->count = 0;
- status->start = NULL;
- status->end = NULL;
-
r->upstream->process_header = ngx_http_scgi_process_status_line;
r->state = 0;
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -657,7 +657,7 @@ ngx_http_uwsgi_handler(ngx_http_request_
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
- status = ngx_pcalloc(r->pool, sizeof(ngx_http_status_t));
+ status = ngx_palloc(r->pool, sizeof(ngx_http_status_t));
if (status == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
@@ -1214,19 +1214,6 @@ ngx_http_uwsgi_create_request(ngx_http_r
static ngx_int_t
ngx_http_uwsgi_reinit_request(ngx_http_request_t *r)
{
- ngx_http_status_t *status;
-
- status = ngx_http_get_module_ctx(r, ngx_http_uwsgi_module);
-
- if (status == NULL) {
- return NGX_OK;
- }
-
- status->code = 0;
- status->count = 0;
- status->start = NULL;
- status->end = NULL;
-
r->upstream->process_header = ngx_http_uwsgi_process_status_line;
r->state = 0;
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -72,7 +72,6 @@ struct ngx_http_chunked_s {
typedef struct {
ngx_uint_t http_version;
ngx_uint_t code;
- ngx_uint_t count;
u_char *start;
u_char *end;
} ngx_http_status_t;
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -1645,7 +1645,9 @@ ngx_http_parse_status_line(ngx_http_requ
sw_major_digit,
sw_first_minor_digit,
sw_minor_digit,
- sw_status,
+ sw_first_status_digit,
+ sw_second_status_digit,
+ sw_third_status_digit,
sw_space_after_status,
sw_status_text,
sw_almost_done
@@ -1750,7 +1752,7 @@ ngx_http_parse_status_line(ngx_http_requ
/* the minor HTTP version or the end of the request line */
case sw_minor_digit:
if (ch == ' ') {
- state = sw_status;
+ state = sw_first_status_digit;
break;
}
@@ -1765,8 +1767,8 @@ ngx_http_parse_status_line(ngx_http_requ
r->http_minor = r->http_minor * 10 + (ch - '0');
break;
- /* HTTP status code */
- case sw_status:
+ /* the first digit of HTTP status code */
+ case sw_first_status_digit:
if (ch == ' ') {
break;
}
@@ -1775,13 +1777,29 @@ ngx_http_parse_status_line(ngx_http_requ
return NGX_ERROR;
}
+ status->code = ch - '0';
+ status->start = p;
+ state = sw_second_status_digit;
+ break;
+
+ /* the second digit of HTTP status code */
+ case sw_second_status_digit:
+ if (ch < '0' || ch > '9') {
+ return NGX_ERROR;
+ }
+
status->code = status->code * 10 + (ch - '0');
-
- if (++status->count == 3) {
- state = sw_space_after_status;
- status->start = p - 2;
+ state = sw_third_status_digit;
+ break;
+
+ /* the third digit of HTTP status code */
+ case sw_third_status_digit:
+ if (ch < '0' || ch > '9') {
+ return NGX_ERROR;
}
+ status->code = status->code * 10 + (ch - '0');
+ state = sw_space_after_status;
break;
/* space or end of line */
@@ -1810,6 +1828,7 @@ ngx_http_parse_status_line(ngx_http_requ
state = sw_almost_done;
break;
case LF:
+ status->end = p;
goto done;
}
break;
@@ -1835,10 +1854,6 @@ done:
b->pos = p + 1;
- if (status->end == NULL) {
- status->end = p;
- }
-
status->http_version = r->http_major * 1000 + r->http_minor;
r->state = sw_start;
More information about the nginx-devel
mailing list