summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRoman Arutyunyan <arut@nginx.com>2026-04-10 21:42:18 +0400
committerRoman Arutyunyan <arutyunyan.roman@gmail.com>2026-04-16 19:47:46 +0400
commitd7dd7e9ae4c2110f753cac02fd702eefef9fce16 (patch)
tree44568659b787f42cdf1c7cf802d3d53e6cc22af1
parent4e89ce224f0b3fe9c1d1bc42eca0a7afecdcafb6 (diff)
downloadnginx-d7dd7e9ae4c2110f753cac02fd702eefef9fce16.tar.gz
nginx-d7dd7e9ae4c2110f753cac02fd702eefef9fce16.tar.bz2
HTTP/3: optimize encoder stream memory usage
Previously, the encoder stream allocated each new inserted field in the connection pool. This memory was not freed until the end of the connection. Now a special insert buffer is used for all inserts.
-rw-r--r--src/http/v3/ngx_http_v3_parse.c30
-rw-r--r--src/http/v3/ngx_http_v3_parse.h1
-rw-r--r--src/http/v3/ngx_http_v3_table.c22
-rw-r--r--src/http/v3/ngx_http_v3_table.h2
4 files changed, 52 insertions, 3 deletions
diff --git a/src/http/v3/ngx_http_v3_parse.c b/src/http/v3/ngx_http_v3_parse.c
index bcbf0dbe1..1ba08c791 100644
--- a/src/http/v3/ngx_http_v3_parse.c
+++ b/src/http/v3/ngx_http_v3_parse.c
@@ -633,9 +633,23 @@ ngx_http_v3_parse_literal(ngx_connection_t *c, ngx_http_v3_parse_literal_t *st,
st->huffstate = 0;
}
- st->last = ngx_pnalloc(c->pool, n + 1);
- if (st->last == NULL) {
- return NGX_ERROR;
+ if (st->buf) {
+ if ((size_t) (st->buf->end - st->buf->last) < n + 1) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "not enough dynamic table capacity");
+
+ st->last = NULL;
+ return NGX_ERROR;
+ }
+
+ st->last = st->buf->last;
+ st->buf->last += n + 1;
+
+ } else {
+ st->last = ngx_pnalloc(c->pool, n + 1);
+ if (st->last == NULL) {
+ return NGX_ERROR;
+ }
}
st->value.data = st->last;
@@ -1486,6 +1500,11 @@ ngx_http_v3_parse_field_inr(ngx_connection_t *c,
ch = *b->pos;
+ st->literal.buf = ngx_http_v3_get_insert_buffer(c);
+ if (st->literal.buf == NULL) {
+ return NGX_ERROR;
+ }
+
st->dynamic = (ch & 0x40) ? 0 : 1;
st->state = sw_name_index;
@@ -1590,6 +1609,11 @@ ngx_http_v3_parse_field_iln(ngx_connection_t *c,
ch = *b->pos;
+ st->literal.buf = ngx_http_v3_get_insert_buffer(c);
+ if (st->literal.buf == NULL) {
+ return NGX_ERROR;
+ }
+
st->literal.huffman = (ch & 0x20) ? 1 : 0;
st->state = sw_name_len;
diff --git a/src/http/v3/ngx_http_v3_parse.h b/src/http/v3/ngx_http_v3_parse.h
index ba004db5d..c7e1e1ebb 100644
--- a/src/http/v3/ngx_http_v3_parse.h
+++ b/src/http/v3/ngx_http_v3_parse.h
@@ -51,6 +51,7 @@ typedef struct {
ngx_str_t value;
u_char *last;
u_char huffstate;
+ ngx_buf_t *buf;
} ngx_http_v3_parse_literal_t;
diff --git a/src/http/v3/ngx_http_v3_table.c b/src/http/v3/ngx_http_v3_table.c
index 428e7326b..3b0b7b309 100644
--- a/src/http/v3/ngx_http_v3_table.c
+++ b/src/http/v3/ngx_http_v3_table.c
@@ -155,6 +155,28 @@ static ngx_http_v3_field_t ngx_http_v3_static_table[] = {
};
+ngx_buf_t *
+ngx_http_v3_get_insert_buffer(ngx_connection_t *c)
+{
+ ngx_http_v3_session_t *h3c;
+ ngx_http_v3_dynamic_table_t *dt;
+
+ h3c = ngx_http_v3_get_session(c);
+ dt = &h3c->table;
+
+ if (dt->insert_buffer == NULL) {
+ dt->insert_buffer = ngx_create_temp_buf(c->pool, dt->capacity);
+ if (dt->insert_buffer == NULL) {
+ return NULL;
+ }
+ }
+
+ dt->insert_buffer->last = dt->insert_buffer->pos;
+
+ return dt->insert_buffer;
+}
+
+
ngx_int_t
ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
ngx_uint_t index, ngx_str_t *value)
diff --git a/src/http/v3/ngx_http_v3_table.h b/src/http/v3/ngx_http_v3_table.h
index 1c2fb17b9..6644723d1 100644
--- a/src/http/v3/ngx_http_v3_table.h
+++ b/src/http/v3/ngx_http_v3_table.h
@@ -29,11 +29,13 @@ typedef struct {
uint64_t insert_count;
uint64_t ack_insert_count;
ngx_event_t send_insert_count;
+ ngx_buf_t *insert_buffer;
} ngx_http_v3_dynamic_table_t;
void ngx_http_v3_inc_insert_count_handler(ngx_event_t *ev);
void ngx_http_v3_cleanup_table(ngx_http_v3_session_t *h3c);
+ngx_buf_t *ngx_http_v3_get_insert_buffer(ngx_connection_t *c);
ngx_int_t ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
ngx_uint_t index, ngx_str_t *value);
ngx_int_t ngx_http_v3_insert(ngx_connection_t *c, ngx_str_t *name,