-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Upstream: fixed reinit request with gRPC and Early Hints. #750
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@@ -1986,6 +1986,10 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) | |||
"http proxy header done"); | |||
|
|||
if (r->upstream->headers_in.status_n == NGX_HTTP_EARLY_HINTS) { | |||
if (ngx_http_proxy_reinit_request(r) != NGX_OK) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we already process early hints separately, it's probably better to do the necessary part of ngx_http_proxy_reinit_request()
here instead of calling it.
if (u->headers_in.status_n == NGX_HTTP_EARLY_HINTS) { | ||
ctx->status = 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here there's no return, which means the entire block below will be executed for early hints, which seems wrong. However we still need to handle the end stream case for eary hints.
Here's my take: diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c
index d74b17708..4c95525b4 100644
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -1928,6 +1928,17 @@ ngx_http_grpc_process_header(ngx_http_request_t *r)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"grpc header done");
+ if (u->headers_in.status_n == NGX_HTTP_EARLY_HINTS) {
+ if (ctx->end_stream) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream prematurely closed stream");
+ return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+ }
+
+ ctx->status = 0;
+ return NGX_HTTP_UPSTREAM_EARLY_HINTS;
+ }
+
if (ctx->end_stream) {
u->headers_in.content_length_n = 0;
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index ff7460e44..8d5385c1d 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -1985,8 +1985,18 @@ ngx_http_proxy_process_header(ngx_http_request_t *r)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http proxy header done");
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
if (r->upstream->headers_in.status_n == NGX_HTTP_EARLY_HINTS) {
- return NGX_OK;
+ ctx->status.code = 0;
+ ctx->status.count = 0;
+ ctx->status.start = NULL;
+ ctx->status.end = NULL;
+
+ r->upstream->process_header =
+ ngx_http_proxy_process_status_line;
+ r->state = 0;
+ return NGX_HTTP_UPSTREAM_EARLY_HINTS;
}
/*
@@ -2036,8 +2046,6 @@ ngx_http_proxy_process_header(ngx_http_request_t *r)
* connections alive in case of r->header_only or X-Accel-Redirect
*/
- ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
-
if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
|| u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
|| ctx->head
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index d1bcdbbe0..de0f92a4f 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1123,7 +1123,7 @@ ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u)
return NGX_ERROR;
}
- if (rc == NGX_AGAIN) {
+ if (rc == NGX_AGAIN || rc == NGX_HTTP_UPSTREAM_EARLY_HINTS) {
rc = NGX_HTTP_UPSTREAM_INVALID_HEADER;
}
@@ -2533,9 +2533,7 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
continue;
}
- if (rc == NGX_OK
- && u->headers_in.status_n == NGX_HTTP_EARLY_HINTS)
- {
+ if (rc == NGX_HTTP_UPSTREAM_EARLY_HINTS) {
rc = ngx_http_upstream_process_early_hints(r, u);
if (rc == NGX_OK) {
@@ -2651,10 +2649,6 @@ ngx_http_upstream_process_early_hints(ngx_http_request_t *r,
}
}
- if (u->reinit_request(r) != NGX_OK) {
- return NGX_ERROR;
- }
-
ngx_http_clean_header(r);
ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index 7a47675eb..f3e9f7979 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -43,6 +43,7 @@
|NGX_HTTP_UPSTREAM_FT_HTTP_429)
#define NGX_HTTP_UPSTREAM_INVALID_HEADER 40
+#define NGX_HTTP_UPSTREAM_EARLY_HINTS 41
#define NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT 0x00000002 |
The gRPC module context has connection specific state, which can be lost after request reinitialization when it comes to processing early hints. The fix is to do only a portion of u->reinit_request() implementation required after processing early hints, now inlined in modules. Now NGX_HTTP_UPSTREAM_EARLY_HINTS is returned from u->process_header() for early hints. When reading a cached response, this code is mapped to NGX_HTTP_UPSTREAM_INVALID_HEADER to indicate invalid header format.
722a1b9
to
80276b6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks ok.
The gRPC module context has connection specific state, which can be lost
after request reinitialization when it comes to processing early hints.
The fix is to do only a portion of u->reinit_request() implementation
required after processing early hints, now inlined in modules.
Now NGX_HTTP_UPSTREAM_EARLY_HINTS is returned from u->process_header()
for early hints. When reading a cached response, this code is mapped
to NGX_HTTP_UPSTREAM_INVALID_HEADER to indicate invalid header format.