[nginx] Reworked ngx_http_parse_status_line() to avoid data assu...
Maxim Dounin
mdounin at mdounin.ru
Mon Aug 18 00:30:23 UTC 2025
details: http://freenginx.org/hg/nginx/rev/62a1baf5d0b5
branches:
changeset: 9405:62a1baf5d0b5
user: Maxim Dounin <mdounin at mdounin.ru>
date: Mon Aug 18 03:18:55 2025 +0300
description:
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.
diffstat:
src/http/modules/ngx_http_proxy_module.c | 4 ---
src/http/modules/ngx_http_scgi_module.c | 15 +-----------
src/http/modules/ngx_http_uwsgi_module.c | 15 +-----------
src/http/ngx_http.h | 1 -
src/http/ngx_http_parse.c | 40 ++++++++++++++++++++++---------
5 files changed, 30 insertions(+), 45 deletions(-)
diffs (184 lines):
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 */
@@ -1797,6 +1815,7 @@ ngx_http_parse_status_line(ngx_http_requ
state = sw_almost_done;
break;
case LF:
+ status->end = p;
goto done;
default:
return NGX_ERROR;
@@ -1810,6 +1829,7 @@ ngx_http_parse_status_line(ngx_http_requ
state = sw_almost_done;
break;
case LF:
+ status->end = p;
goto done;
}
break;
@@ -1835,10 +1855,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