[nginx] gRPC: special handling of the TE request header.
Maxim Dounin
mdounin at mdounin.ru
Sat Mar 17 20:08:28 UTC 2018
details: http://hg.nginx.org/nginx/rev/c693daca57f7
branches:
changeset: 7234:c693daca57f7
user: Maxim Dounin <mdounin at mdounin.ru>
date: Sat Mar 17 23:04:25 2018 +0300
description:
gRPC: special handling of the TE request header.
According to the gRPC protocol specification, the "TE" header is used
to detect incompatible proxies, and at least grpc-c server rejects
requests without "TE: trailers".
To preserve the logic, we have to pass "TE: trailers" to the backend if
and only if the original request contains "trailers" in the "TE" header.
Note that no other TE values are allowed in HTTP/2, so we have to remove
anything else.
diffstat:
src/http/modules/ngx_http_grpc_module.c | 69 ++++++++++++++++++++++++++++++++-
src/http/ngx_http_request.c | 4 +
src/http/ngx_http_request.h | 1 +
3 files changed, 72 insertions(+), 2 deletions(-)
diffs (135 lines):
diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -176,6 +176,10 @@ static void ngx_http_grpc_abort_request(
static void ngx_http_grpc_finalize_request(ngx_http_request_t *r,
ngx_int_t rc);
+static ngx_int_t ngx_http_grpc_internal_trailers_variable(
+ ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
+
+static ngx_int_t ngx_http_grpc_add_variables(ngx_conf_t *cf);
static void *ngx_http_grpc_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child);
@@ -419,7 +423,7 @@ static ngx_command_t ngx_http_grpc_comm
static ngx_http_module_t ngx_http_grpc_module_ctx = {
- NULL, /* preconfiguration */
+ ngx_http_grpc_add_variables, /* preconfiguration */
NULL, /* postconfiguration */
NULL, /* create main configuration */
@@ -463,10 +467,10 @@ static u_char ngx_http_grpc_connection_
static ngx_keyval_t ngx_http_grpc_headers[] = {
{ ngx_string("Content-Length"), ngx_string("$content_length") },
+ { ngx_string("TE"), ngx_string("$grpc_internal_trailers") },
{ ngx_string("Host"), ngx_string("") },
{ ngx_string("Connection"), ngx_string("") },
{ ngx_string("Transfer-Encoding"), ngx_string("") },
- { ngx_string("TE"), ngx_string("") },
{ ngx_string("Keep-Alive"), ngx_string("") },
{ ngx_string("Expect"), ngx_string("") },
{ ngx_string("Upgrade"), ngx_string("") },
@@ -486,6 +490,16 @@ static ngx_str_t ngx_http_grpc_hide_hea
};
+static ngx_http_variable_t ngx_http_grpc_vars[] = {
+
+ { ngx_string("grpc_internal_trailers"), NULL,
+ ngx_http_grpc_internal_trailers_variable, 0,
+ NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
+
+ ngx_http_null_variable
+};
+
+
static ngx_int_t
ngx_http_grpc_handler(ngx_http_request_t *r)
{
@@ -3996,6 +4010,57 @@ ngx_http_grpc_finalize_request(ngx_http_
}
+static ngx_int_t
+ngx_http_grpc_internal_trailers_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ ngx_table_elt_t *te;
+
+ te = r->headers_in.te;
+
+ if (te == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ if (ngx_strlcasestrn(te->value.data, te->value.data + te->value.len,
+ (u_char *) "trailers", 8 - 1)
+ == NULL)
+ {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+
+ v->data = (u_char *) "trailers";
+ v->len = sizeof("trailers") - 1;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_grpc_add_variables(ngx_conf_t *cf)
+{
+ ngx_http_variable_t *var, *v;
+
+ for (v = ngx_http_grpc_vars; v->name.len; v++) {
+ var = ngx_http_add_variable(cf, &v->name, v->flags);
+ if (var == NULL) {
+ return NGX_ERROR;
+ }
+
+ var->get_handler = v->get_handler;
+ var->data = v->data;
+ }
+
+ return NGX_OK;
+}
+
+
static void *
ngx_http_grpc_create_loc_conf(ngx_conf_t *cf)
{
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -132,6 +132,10 @@ ngx_http_header_t ngx_http_headers_in[]
offsetof(ngx_http_headers_in_t, transfer_encoding),
ngx_http_process_header_line },
+ { ngx_string("TE"),
+ offsetof(ngx_http_headers_in_t, te),
+ ngx_http_process_header_line },
+
{ ngx_string("Expect"),
offsetof(ngx_http_headers_in_t, expect),
ngx_http_process_unique_header_line },
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -197,6 +197,7 @@ typedef struct {
ngx_table_elt_t *if_range;
ngx_table_elt_t *transfer_encoding;
+ ngx_table_elt_t *te;
ngx_table_elt_t *expect;
ngx_table_elt_t *upgrade;
More information about the nginx-devel
mailing list