-
Notifications
You must be signed in to change notification settings - Fork 5.5k
grpc-web: Fix 503 handling for gRPC Web text #14516
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
Changes from 11 commits
317752b
4145f68
396c9a9
b857daf
e110772
ec65cf2
dd02ff5
bef8120
363ba32
1711700
f1e27c2
ce1f186
d61e397
1aa30bb
531f8eb
277ddac
151e3d5
8e4f6a3
e0c3a00
fcc89d1
d1ee48f
cf4f00e
df52573
9404841
bc5630c
8becf15
ae9aab9
3cbab78
041096c
27070e0
7436613
1b8837d
8c19be2
fb46631
14293ce
291590a
1f63bcd
a50f51d
9beda45
28564b2
b3642be
6e1efc7
8fc318a
ba3441c
4a153d7
4889c28
d7aad6f
fff111c
239f071
9cc0f61
9d1e41f
50c3530
8bec999
3329e0f
38b7882
2e71971
c8d0bac
190879b
c394503
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,9 @@ | |
| #include "common/common/assert.h" | ||
| #include "common/common/base64.h" | ||
| #include "common/common/empty_string.h" | ||
| #include "common/common/enum_to_int.h" | ||
| #include "common/common/utility.h" | ||
| #include "common/grpc/common.h" | ||
| #include "common/grpc/context_impl.h" | ||
| #include "common/http/headers.h" | ||
| #include "common/http/utility.h" | ||
|
|
@@ -54,6 +56,22 @@ bool GrpcWebFilter::isGrpcWebRequest(const Http::RequestHeaderMap& headers) { | |
| return false; | ||
| } | ||
|
|
||
| bool GrpcWebFilter::hasGrpcWebContentType(const Http::RequestOrResponseHeaderMap& headers) const { | ||
| const Http::HeaderEntry* content_type = headers.ContentType(); | ||
| if (content_type != nullptr) { | ||
| return gRpcWebContentTypes().count(content_type->value().getStringView()) > 0; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://tools.ietf.org/html/rfc2616#section-3.7 According to the grpc spec, https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ping?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry I missed this, I'll fix this.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alyssawilk If we consider only grpc-web (and grpc-web+proto) here, should the filter "Continue" on grpc-web-text (and grpc-web-text+proto)?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh sorry, this was less about web vs web-text and more about +proto vs +thrift. I think we should support anything that's legit grpc-web and proto encoding but not grpc-web which is thrift encoded. Though maybe @lizan has thoughts here? Also if you agree let's fix the function name to indicate it's not all grpc-web but proto encoded grpc web.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name is updated. |
||
| } | ||
|
dio marked this conversation as resolved.
|
||
| return false; | ||
| } | ||
|
|
||
| // Valid response headers contain gRPC or gRPC-Web response headers. | ||
| bool GrpcWebFilter::isValidResponseHeaders(Http::ResponseHeaderMap& headers, | ||
| bool end_stream) const { | ||
| return Grpc::Common::isGrpcResponseHeaders(headers, end_stream) || | ||
| (Http::Utility::getResponseStatus(headers) == enumToInt(Http::Code::OK) && | ||
| hasGrpcWebContentType(headers)); | ||
| } | ||
|
|
||
| // Implements StreamDecoderFilter. | ||
| // TODO(fengli): Implements the subtypes of gRPC-Web content-type other than proto, like +json, etc. | ||
| Http::FilterHeadersStatus GrpcWebFilter::decodeHeaders(Http::RequestHeaderMap& headers, bool) { | ||
|
|
@@ -143,7 +161,8 @@ Http::FilterDataStatus GrpcWebFilter::decodeData(Buffer::Instance& data, bool en | |
| } | ||
|
|
||
| // Implements StreamEncoderFilter. | ||
| Http::FilterHeadersStatus GrpcWebFilter::encodeHeaders(Http::ResponseHeaderMap& headers, bool) { | ||
| Http::FilterHeadersStatus GrpcWebFilter::encodeHeaders(Http::ResponseHeaderMap& headers, | ||
| bool end_stream) { | ||
| if (!is_grpc_web_request_) { | ||
| return Http::FilterHeadersStatus::Continue; | ||
| } | ||
|
|
@@ -156,14 +175,44 @@ Http::FilterHeadersStatus GrpcWebFilter::encodeHeaders(Http::ResponseHeaderMap& | |
| } else { | ||
| headers.setReferenceContentType(Http::Headers::get().ContentTypeValues.GrpcWebProto); | ||
| } | ||
| return Http::FilterHeadersStatus::Continue; | ||
|
|
||
| if (end_stream || isValidResponseHeaders(headers, end_stream)) { | ||
| return Http::FilterHeadersStatus::Continue; | ||
| } | ||
|
|
||
| ENVOY_LOG(debug, "received invalid response headers since the upstream response or local reply " | ||
|
dio marked this conversation as resolved.
Outdated
|
||
| "is not a gRPC or gRPC-Web response"); | ||
| response_headers_ = &headers; | ||
| return Http::FilterHeadersStatus::StopIteration; | ||
| } | ||
|
|
||
| Http::FilterDataStatus GrpcWebFilter::encodeData(Buffer::Instance& data, bool) { | ||
| Http::FilterDataStatus GrpcWebFilter::encodeData(Buffer::Instance& data, bool end_stream) { | ||
| if (!is_grpc_web_request_) { | ||
| return Http::FilterDataStatus::Continue; | ||
| } | ||
|
|
||
| // When the upstream response (this is also relevant for local reply, since gRPC-Web request is | ||
| // not a gRPC request which makes the local reply's is_grpc_request set to false) is not a gRPC | ||
| // response, we set the "grpc-message" header with the upstream body content. | ||
| if (response_headers_ != nullptr) { | ||
|
dio marked this conversation as resolved.
Outdated
|
||
| if (!end_stream) { | ||
| return Http::FilterDataStatus::StopIterationAndBuffer; | ||
|
dio marked this conversation as resolved.
|
||
| } | ||
|
|
||
| constexpr uint64_t max_grpc_message_length = 1024; | ||
| // Take the last frame as the grpc-message value, but the size of it is limited by | ||
| // max_grpc_message_length. | ||
| const auto message = | ||
| Http::Utility::PercentEncoding::encode(data.toString().substr(0, max_grpc_message_length)); | ||
|
dio marked this conversation as resolved.
Outdated
|
||
| data.drain(data.length()); | ||
|
|
||
| response_headers_->setGrpcStatus(Grpc::Utility::httpToGrpcStatus( | ||
| enumToInt(Http::Utility::getResponseStatus(*response_headers_)))); | ||
| response_headers_->setGrpcMessage(message); | ||
| response_headers_->setContentLength(0); | ||
| return Http::FilterDataStatus::Continue; | ||
| } | ||
|
|
||
| if (!is_text_response_) { | ||
| // No additional transcoding required if gRPC-Web client asked for binary response. | ||
| return Http::FilterDataStatus::Continue; | ||
|
|
||
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.
unit tests, please!
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.
Added: 27070e0.