8000 Upstream: proxy_early_hint and friends. · nginx/nginx@51872cb · GitHub
[go: up one dir, main page]

Skip to content

Commit 51872cb

Browse files
committed
Upstream: proxy_early_hint and friends.
The directives add early hints to be sent to the client prior to connecting to upstream.
1 parent b101c79 commit 51872cb

File tree

6 files changed

+161
-0
lines changed

6 files changed

+161
-0
lines changed

src/http/modules/ngx_http_grpc_module.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,13 @@ static ngx_command_t ngx_http_grpc_commands[] = {
297297
offsetof(ngx_http_grpc_loc_conf_t, upstream.intercept_errors),
298298
NULL },
299299

300+
{ ngx_string("grpc_early_hint"),
301+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
302+
ngx_http_upstream_early_hint_set_slot,
303+
NGX_HTTP_LOC_CONF_OFFSET,
304+
offsetof(ngx_http_grpc_loc_conf_t, upstream.early_hints),
305+
NULL },
306+
300307
{ ngx_string("grpc_buffer_size"),
301308
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
302309
ngx_conf_set_size_slot,
@@ -4391,6 +4398,8 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf)
43914398

43924399
conf->upstream.intercept_errors = NGX_CONF_UNSET;
43934400

4401+
conf->upstream.early_hints = NGX_CONF_UNSET_PTR;
4402+
43944403
#if (NGX_HTTP_SSL)
43954404
conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
43964405
conf->upstream.ssl_name = NGX_CONF_UNSET_PTR;
@@ -4481,6 +4490,9 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
44814490
ngx_conf_merge_value(conf->upstream.intercept_errors,
44824491
prev->upstream.intercept_errors, 0);
44834492

4493+
ngx_conf_merge_ptr_value(conf->upstream.early_hints,
4494+
prev->upstream.early_hints, NULL);
4495+
44844496
#if (NGX_HTTP_SSL)
44854497

44864498
if (ngx_http_grpc_merge_ssl(cf, conf, prev) != NGX_OK) {

src/http/modules/ngx_http_proxy_module.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,13 @@ static ngx_command_t ngx_http_proxy_commands[] = {
470470
offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_trailers),
471471
NULL },
472472

473+
{ ngx_string("proxy_early_hint"),
474+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
475+
ngx_http_upstream_early_hint_set_slot,
476+
NGX_HTTP_LOC_CONF_OFFSET,
477+
offsetof(ngx_http_proxy_loc_conf_t, upstream.early_hints),
478+
NULL },
479+
473480
{ ngx_string("proxy_buffer_size"),
474481
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
475482
ngx_conf_set_size_slot,
@@ -3609,6 +3616,8 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
36093616
conf->upstream.pass_request_body = NGX_CONF_UNSET;
36103617
conf->upstream.pass_trailers = NGX_CONF_UNSET;
36113618

3619+
conf->upstream.early_hints = NGX_CONF_UNSET_PTR;
3620+
36123621
#if (NGX_HTTP_CACHE)
36133622
conf->upstream.cache = NGX_CONF_UNSET;
36143623
conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
@@ -3957,6 +3966,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
39573966
ngx_conf_merge_value(conf->upstream.intercept_errors,
39583967
prev->upstream.intercept_errors, 0);
39593968

3969+
ngx_conf_merge_ptr_value(conf->upstream.early_hints,
3970+
prev->upstream.early_hints, NULL);
3971+
39603972
#if (NGX_HTTP_SSL)
39613973

39623974
if (ngx_http_proxy_merge_ssl(cf, conf, prev) != NGX_OK) {

src/http/modules/ngx_http_scgi_module.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,13 @@ static ngx_command_t ngx_http_scgi_commands[] = {
165165
offsetof(ngx_http_scgi_loc_conf_t, upstream.send_timeout),
166166
NULL },
167167

168+
{ ngx_string("scgi_early_hint"),
169+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
170+
ngx_http_upstream_early_hint_set_slot,
171+
NGX_HTTP_LOC_CONF_OFFSET,
172+
offsetof(ngx_http_scgi_loc_conf_t, upstream.early_hints),
173+
NULL },
174+
168175
{ ngx_string("scgi_buffer_size"),
169176
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
170177
ngx_conf_set_size_slot,
@@ -1325,6 +1332,8 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
13251332
conf->upstream.pass_request_headers = NGX_CONF_UNSET;
13261333
conf->upstream.pass_request_body = NGX_CONF_UNSET;
13271334

1335+
conf->upstream.early_hints = NGX_CONF_UNSET_PTR;
1336+
13281337
#if (NGX_HTTP_CACHE)
13291338
conf->upstream.cache = NGX_CONF_UNSET;
13301339
conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
@@ -1640,6 +1649,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
16401649
ngx_conf_merge_value(conf->upstream.intercept_errors,
16411650
prev->upstream.intercept_errors, 0);
16421651

1652+
ngx_conf_merge_ptr_value(conf->upstream.early_hints,
1653+
prev->upstream.early_hints, NULL);
1654+
16431655
hash.max_size = 512;
16441656
hash.bucket_size = ngx_align(64, ngx_cacheline_size);
16451657
hash.name = "scgi_hide_headers_hash";

src/http/modules/ngx_http_uwsgi_module.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,13 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
233233
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.send_timeout),
234234
NULL },
235235

236+
{ ngx_string("uwsgi_early_hint"),
237+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
238+
ngx_http_upstream_early_hint_set_slot,
239+
NGX_HTTP_LOC_CONF_OFFSET,
240+
offsetof(ngx_http_uwsgi_loc_conf_t, upstream.early_hints),
241+
NULL },
242+
236243
{ ngx_string("uwsgi_buffer_size"),
237244
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
238245
ngx_conf_set_size_slot,
@@ -1572,6 +1579,8 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
15721579
conf->upstream.pass_request_headers = NGX_CONF_UNSET;
15731580
conf->upstream.pass_request_body = NGX_CONF_UNSET;
15741581

1582+
conf->upstream.early_hints = NGX_CONF_UNSET_PTR;
1583+
15751584
#if (NGX_HTTP_CACHE)
15761585
conf->upstream.cache = NGX_CONF_UNSET;
15771586
conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
@@ -1900,6 +1909,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
19001909
ngx_conf_merge_value(conf->upstream.intercept_errors,
19011910
prev->upstream.intercept_errors, 0);
19021911

1912+
ngx_conf_merge_ptr_value(conf->upstream.early_hints,
1913+
prev->upstream.early_hints, NULL);
1914+
19031915
#if (NGX_HTTP_SSL)
19041916

19051917
if (ngx_http_uwsgi_merge_ssl(cf, conf, prev) != NGX_OK) {

src/http/ngx_http_upstream.c

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010
#include <ngx_http.h>
1111

1212

13+
typedef struct {
14+
ngx_str_t key;
15+
ngx_http_complex_value_t value;
16+
} ngx_http_upstream_early_hint_t;
17+
18+
1319
#if (NGX_HTTP_CACHE)
1420
static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r,
1521
ngx_http_upstream_t *u);
@@ -48,6 +54,8 @@ static void ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
4854
static void ngx_http_upstream_read_request_handler(ngx_http_request_t *r);
4955
static void ngx_http_upstream_process_header(ngx_http_request_t *r,
5056
ngx_http_upstream_t *u);
57+
static ngx_int_t ngx_http_upstream_send_early_hints(ngx_http_request_t *r,
58+
ngx_http_upstream_t *u);
5159
static ngx_int_t ngx_http_upstream_process_early_hints(ngx_http_request_t *r,
5260
ngx_http_upstream_t *u);
5361
static void ngx_http_upstream_early_hints_writer(ngx_http_request_t *r);
@@ -715,6 +723,11 @@ ngx_http_upstream_init_request(ngx_http_request_t *r)
715723
cln->data = r;
716724
u->cleanup = &cln->handler;
717725

726+
if (ngx_http_upstream_send_early_hints(r, u) != NGX_OK) {
727+
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
728+
return;
729+
}
730+
718731
if (u->resolved == NULL) {
719732

720733
uscf = u->conf->upstream;
@@ -2693,6 +2706,59 @@ ngx_http_upstream_process_early_hints(ngx_http_request_t *r,
26932706
}
26942707

26952708

2709+
static ngx_int_t
2710+
ngx_http_upstream_send_early_hints(ngx_http_request_t *r,
2711+
ngx_http_upstream_t *u)
2712+
{
2713+
ngx_str_t value;
2714+
ngx_uint_t i;
2715+
ngx_table_elt_t *t;
2716+
ngx_connection_t *c;
2717+
ngx_http_upstream_early_hint_t *eh;
2718+
2719+
if (u->conf->early_hints == NULL) {
2720+
return NGX_OK;
2721+
}
2722+
2723+
eh = u->conf->early_hints->elts;
2724+
for (i = 0; i < u->conf->early_hints->nelts; i++) {
2725+
2726+
if (ngx_http_complex_value(r, &eh[i].value, &value) != NGX_OK) {
2727+
return NGX_ERROR;
2728+
}
2729+
2730+
if (value.len) {
2731+
t = ngx_list_push(&r->headers_out.headers);
2732+
if (t == NULL) {
2733+
return NGX_ERROR;
2734+
}
2735+
2736+
t->key = eh[i].key;
2737+
t->value = value;
2738+
t->hash = 1;
2739+
}
2740+
}
2741+
2742+
c = r->connection;
2743+
2744+
if (ngx_http_send_early_hints(r) == NGX_ERROR) {
2745+
return NGX_ERROR;
2746+
}
2747+
2748+
if (c->buffered) {
2749+
if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
2750+
return NGX_ERROR;
2751+
}
2752+
2753+
r->write_event_handler = ngx_http_upstream_early_hints_writer;
2754+
}
2755+
2756+
ngx_http_clean_header(r);
2757+
2758+
return NGX_OK;
2759+
}
2760+
2761+
26962762
static void
26972763
ngx_http_upstream_early_hints_writer(ngx_http_request_t *r)
26982764
{
@@ -7084,6 +7150,50 @@ ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
70847150
}
70857151

70867152

7153+
char *
7154+
ngx_http_upstream_early_hint_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
7155+
void *conf)
7156+
{
7157+
char *p = conf;
7158+
7159+
ngx_str_t *value;
7160+
ngx_array_t **parray;
7161+
ngx_http_upstream_early_hint_t *eh;
7162+
ngx_http_compile_complex_value_t ccv;
7163+
7164+
parray = (ngx_array_t **) (p + cmd->offset);
7165+
7166+
if (*parray == NGX_CONF_UNSET_PTR) {
7167+
*parray = ngx_array_create(cf->pool, 1,
7168+
sizeof(ngx_http_upstream_early_hint_t));
7169+
if (*parray == NULL) {
7170+
return NGX_CONF_ERROR;
7171+
}
7172+
}
7173+
7174+
eh = ngx_array_push(*parray);
7175+
if (eh == NULL) {
7176+
return NGX_CONF_ERROR;
7177+
}
7178+
7179+
value = cf->args->elts;
7180+
7181+
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
7182+
7183+
ccv.cf = cf;
7184+
ccv.value = &value[2];
7185+
ccv.complex_value = &eh->value;
7186+
7187+
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
7188+
return NGX_CONF_ERROR;
7189+
}
7190+
7191+
eh->key = value[1];
7192+
7193+
return NGX_OK;
7194+
}
7195+
7196+
70877197
#if (NGX_HTTP_SSL)
70887198

70897199
ngx_int_t

src/http/ngx_http_upstream.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ typedef struct {
197197
ngx_hash_t hide_headers_hash;
198198
ngx_array_t *hide_headers;
199199
ngx_array_t *pass_headers;
200+
ngx_array_t *early_hints;
200201

201202
ngx_http_upstream_local_t *local;
202203
ngx_flag_t socket_keepalive;
@@ -439,6 +440,8 @@ char *ngx_http_upstream_param_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
439440
ngx_int_t ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
440441
ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
441442
ngx_str_t *default_hide_headers, ngx_hash_init_t *hash);
443+
char *ngx_http_upstream_early_hint_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
444+
void *conf);
442445
#if (NGX_HTTP_SSL)
443446
ngx_int_t ngx_http_upstream_merge_ssl_passwords(ngx_conf_t *cf,
444447
ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev);

0 commit comments

Comments
 (0)
0