From 6a69cc5e228a9a25ef51bd41461d27100f65f4f6 Mon Sep 17 00:00:00 2001 From: Phillip Huang Date: Tue, 2 Jun 2020 11:44:50 -0700 Subject: [PATCH] grpc-json: preserve request method in x-envoy-original-method header (#11126) Commit Message: grpc-json: preserve http request method in `x-envoy-original-method` header so that applications have access to it. Additional Description: The grpc-json transcoder currently forwards HTTP path to applications via "x-envoy-original-path" header. We would find it useful if it also forwarded the HTTP method. Risk Level: Low Testing: Updated grpc-json-transcoder unit tests Docs Changes: Added docs Release Notes: Added release notes Signed-off-by: Phillip Huang --- .../http/http_filters/grpc_json_transcoder_filter.rst | 9 +++++++++ docs/root/version_history/current.rst | 1 + source/common/http/headers.h | 1 + .../http/grpc_json_transcoder/json_transcoder_filter.cc | 1 + .../grpc_json_transcoder/json_transcoder_filter_test.cc | 9 +++++++++ 5 files changed, 21 insertions(+) diff --git a/docs/root/configuration/http/http_filters/grpc_json_transcoder_filter.rst b/docs/root/configuration/http/http_filters/grpc_json_transcoder_filter.rst index 3e01c544e819..1eb2fe082718 100644 --- a/docs/root/configuration/http/http_filters/grpc_json_transcoder_filter.rst +++ b/docs/root/configuration/http/http_filters/grpc_json_transcoder_filter.rst @@ -87,6 +87,15 @@ can be send by the gRPC server in the server streaming case. In this case, HTTP response header `Content-Type` will use the `content-type` from the first `google.api.HttpBody `. +Headers +-------- + +gRPC-JSON forwards the following headers to the gRPC server: + +* `x-envoy-original-path`, containing the value of the original path of HTTP request +* `x-envoy-original-method`, containing the value of the original method of HTTP request + + Sample Envoy configuration -------------------------- diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 4d1d89439fb9..286c9b8aa0c1 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -59,6 +59,7 @@ New Features * grpc: added support for Google gRPC :ref:`custom channel arguments `. * grpc-json: added support for streaming response using `google.api.HttpBody `_. +* grpc-json: send a `x-envoy-original-method` header to grpc services. * gzip filter: added option to set zlib's next output buffer size. * health checks: allow configuring health check transport sockets by specifying :ref:`transport socket match criteria `. * http: added :ref:`local_reply config ` to http_connection_manager to customize :ref:`local reply `. diff --git a/source/common/http/headers.h b/source/common/http/headers.h index 10b87e3da092..8c9abe61aa07 100644 --- a/source/common/http/headers.h +++ b/source/common/http/headers.h @@ -90,6 +90,7 @@ class HeaderValues { const LowerCaseString EnvoyMaxRetries{absl::StrCat(prefix(), "-max-retries")}; const LowerCaseString EnvoyNotForwarded{absl::StrCat(prefix(), "-not-forwarded")}; const LowerCaseString EnvoyOriginalDstHost{absl::StrCat(prefix(), "-original-dst-host")}; + const LowerCaseString EnvoyOriginalMethod{absl::StrCat(prefix(), "-original-method")}; const LowerCaseString EnvoyOriginalPath{absl::StrCat(prefix(), "-original-path")}; const LowerCaseString EnvoyOverloaded{absl::StrCat(prefix(), "-overloaded")}; const LowerCaseString EnvoyRateLimited{absl::StrCat(prefix(), "-ratelimited")}; diff --git a/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc b/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc index 526bf1ac8abe..8de5069993d4 100644 --- a/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc +++ b/source/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter.cc @@ -387,6 +387,7 @@ Http::FilterHeadersStatus JsonTranscoderFilter::decodeHeaders(Http::RequestHeade headers.removeContentLength(); headers.setReferenceContentType(Http::Headers::get().ContentTypeValues.Grpc); headers.setEnvoyOriginalPath(headers.getPathValue()); + headers.addReferenceKey(Http::Headers::get().EnvoyOriginalMethod, headers.getMethodValue()); headers.setPath("/" + method_->descriptor_->service()->full_name() + "/" + method_->descriptor_->name()); headers.setReferenceMethod(Http::Headers::get().MethodValues.Post); diff --git a/test/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter_test.cc b/test/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter_test.cc index e820cb04f273..87caa2275c8d 100644 --- a/test/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter_test.cc +++ b/test/extensions/filters/http/grpc_json_transcoder/json_transcoder_filter_test.cc @@ -388,6 +388,7 @@ TEST_F(GrpcJsonTranscoderFilterTest, TranscodingUnaryPost) { EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_.decodeHeaders(request_headers, false)); EXPECT_EQ("application/grpc", request_headers.get_("content-type")); EXPECT_EQ("/shelf", request_headers.get_("x-envoy-original-path")); + EXPECT_EQ("POST", request_headers.get_("x-envoy-original-method")); EXPECT_EQ("/bookstore.Bookstore/CreateShelf", request_headers.get_(":path")); EXPECT_EQ("trailers", request_headers.get_("te")); @@ -454,6 +455,7 @@ TEST_F(GrpcJsonTranscoderFilterTest, TranscodingUnaryPostWithPackageServiceMetho EXPECT_EQ("application/grpc", request_headers.get_("content-type")); EXPECT_EQ("/bookstore.Bookstore/CreateShelfWithPackageServiceAndMethod", request_headers.get_("x-envoy-original-path")); + EXPECT_EQ("POST", request_headers.get_("x-envoy-original-method")); EXPECT_EQ("/bookstore.Bookstore/CreateShelfWithPackageServiceAndMethod", request_headers.get_(":path")); EXPECT_EQ("trailers", request_headers.get_("te")); @@ -597,6 +599,7 @@ TEST_F(GrpcJsonTranscoderFilterSkipRecalculatingTest, TranscodingUnaryPostSkipRe EXPECT_EQ("application/grpc", request_headers.get_("content-type")); EXPECT_EQ("/shelf", request_headers.get_("x-envoy-original-path")); + EXPECT_EQ("POST", request_headers.get_("x-envoy-original-method")); EXPECT_EQ("/bookstore.Bookstore/CreateShelf", request_headers.get_(":path")); EXPECT_EQ("trailers", request_headers.get_("te")); @@ -674,6 +677,7 @@ TEST_F(GrpcJsonTranscoderFilterTest, TranscodingUnaryWithHttpBodyAsOutput) { EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_.decodeHeaders(request_headers, false)); EXPECT_EQ("application/grpc", request_headers.get_("content-type")); EXPECT_EQ("/index", request_headers.get_("x-envoy-original-path")); + EXPECT_EQ("GET", request_headers.get_("x-envoy-original-method")); EXPECT_EQ("/bookstore.Bookstore/GetIndex", request_headers.get_(":path")); EXPECT_EQ("trailers", request_headers.get_("te")); @@ -708,6 +712,7 @@ TEST_F(GrpcJsonTranscoderFilterTest, TranscodingUnaryWithHttpBodyAsOutputAndSpli EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_.decodeHeaders(request_headers, false)); EXPECT_EQ("application/grpc", request_headers.get_("content-type")); EXPECT_EQ("/index", request_headers.get_("x-envoy-original-path")); + EXPECT_EQ("GET", request_headers.get_("x-envoy-original-method")); EXPECT_EQ("/bookstore.Bookstore/GetIndex", request_headers.get_(":path")); EXPECT_EQ("trailers", request_headers.get_("te")); @@ -753,6 +758,7 @@ TEST_F(GrpcJsonTranscoderFilterTest, TranscodingUnaryPostWithHttpBody) { EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_.decodeHeaders(request_headers, false)); EXPECT_EQ("application/grpc", request_headers.get_("content-type")); EXPECT_EQ("/postBody?arg=hi", request_headers.get_("x-envoy-original-path")); + EXPECT_EQ("POST", request_headers.get_("x-envoy-original-method")); EXPECT_EQ("/bookstore.Bookstore/PostBody", request_headers.get_(":path")); EXPECT_EQ("trailers", request_headers.get_("te")); @@ -800,6 +806,7 @@ TEST_F(GrpcJsonTranscoderFilterTest, TranscodingStreamPostWithHttpBody) { EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_.decodeHeaders(request_headers, false)); EXPECT_EQ("application/grpc", request_headers.get_("content-type")); EXPECT_EQ("/streamBody?arg=hi", request_headers.get_("x-envoy-original-path")); + EXPECT_EQ("POST", request_headers.get_("x-envoy-original-method")); EXPECT_EQ("/bookstore.Bookstore/StreamBody", request_headers.get_(":path")); EXPECT_EQ("trailers", request_headers.get_("te")); @@ -855,6 +862,7 @@ TEST_F(GrpcJsonTranscoderFilterTest, TranscodingStreamWithHttpBodyAsOutput) { EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_.decodeHeaders(request_headers, false)); EXPECT_EQ("application/grpc", request_headers.get_("content-type")); EXPECT_EQ("/indexStream", request_headers.get_("x-envoy-original-path")); + EXPECT_EQ("GET", request_headers.get_("x-envoy-original-method")); EXPECT_EQ("/bookstore.Bookstore/GetIndexStream", request_headers.get_(":path")); EXPECT_EQ("trailers", request_headers.get_("te")); @@ -907,6 +915,7 @@ TEST_F(GrpcJsonTranscoderFilterTest, TranscodingStreamWithFragmentedHttpBody) { EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_.decodeHeaders(request_headers, false)); EXPECT_EQ("application/grpc", request_headers.get_("content-type")); EXPECT_EQ("/indexStream", request_headers.get_("x-envoy-original-path")); + EXPECT_EQ("GET", request_headers.get_("x-envoy-original-method")); EXPECT_EQ("/bookstore.Bookstore/GetIndexStream", request_headers.get_(":path")); EXPECT_EQ("trailers", request_headers.get_("te"));