[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