-
Notifications
You must be signed in to change notification settings - Fork 4.6k
client transport : ignore http status for gRPC mode #8548
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
base: master
Are you sure you want to change the base?
client transport : ignore http status for gRPC mode #8548
Conversation
Fixes grpc#8486 When a gRPC response is received with content type application/grpc, we then do not expect any information in the http status and the status information needs to be conveyed by gRPC status only. In case of missing gRPC status, we will throw an Internal error instead of Unknown in accordance with https://grpc.io/docs/guides/status-codes/ Changes : - Ignore http status in case of content type application/grpc - Change the default rawStatusCode to return Internal for missing grpc status RELEASE NOTES: * client : Ignore http status for gRPC mode and return Internal error for missing grpc status
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #8548 +/- ##
==========================================
- Coverage 81.64% 80.77% -0.88%
==========================================
Files 413 413
Lines 40621 40754 +133
==========================================
- Hits 33167 32920 -247
- Misses 5991 6202 +211
- Partials 1463 1632 +169
🚀 New features to boost your workflow:
|
In the grpc-go repo, we use the assignee to indicate who the review is pending on (author or reviewer). We ignore the reviewer status (the yellow pending re-review dot). Assigning to myself. |
For the PR title, we add the name of the Go package (e.g. |
internal/transport/transport_test.go
Outdated
if test.wantStatusEndStream != nil { | ||
want = test.wantStatusEndStream | ||
} |
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.
I think we should explicitly wantStatusEndStream
for all the tests which have non nil
values. In table-driven tests, it's fine to duplicate parameters across test cases, even if most share the same value. This practice keeps the tests declarative and simplifies the logic, often to just an equality or diff comparison.
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.
Done, added duplicate parameters
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.
Thanks, we should be able to remove this if
block now, right?
e1f6dbc
to
f123124
Compare
…rpc-content-type-8486
f123124
to
b4cce55
Compare
internal/transport/http2_client.go
Outdated
//if not a gRPC response - evaluate entire http status and process close stream / response | ||
//for 200 -> Unknown, else decode the error |
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.
style: Please use complete sentences for comments. Also leave a after //
. See https://google.github.io/styleguide/go/decisions#comment-sentences
// headerError is set if an error is encountered while parsing the headers | ||
headerError string | ||
headerError string | ||
receivedHTTPStatus string |
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.
nit: We can omit the received
prefix int the variable name, shortening it to httpStatus
since it doesn't effect readability.
internal/transport/http2_client.go
Outdated
statusCode := int(c) | ||
if statusCode >= 100 && statusCode < 200 { | ||
//In case of informational headers return | ||
//For trailers, since we are already in gRPC mode, we will ignore all http statuses and not enter this block |
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.
It looks like the check for the endStream
flag was removed.
grpc-go/internal/transport/http2_client.go
Lines 1521 to 1528 in 8420f3f
if statusCode >= 100 && statusCode < 200 { | |
if endStream { | |
se := status.New(codes.Internal, fmt.Sprintf( | |
"protocol error: informational header with status code %d must not have END_STREAM set", statusCode)) | |
t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream) | |
} | |
return | |
} |
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.
I was confused if endstream can come when it is not a gRPC response - @dfawley confirmed that sometimes only one header comes in the response which is set with end stream and it is possible that it may not be gRPC in which case we still need to throw an error if it is informational header. I have added this code back.
case "200": | ||
grpcErrorCode = codes.Unknown |
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.
Is this explicit check required? Since 200 isn't present in the HTTPStatusConvTab
map, I think it may be omitted.
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.
The idea is when no error information can be derived from http status since it is 200, we can simply return Unknown code.
internal/transport/http2_client.go
Outdated
if httpStatusErr != "" { | ||
errs = append(errs, httpStatusErr) | ||
} | ||
|
||
if contentTypeErr != "" { | ||
errs = append(errs, contentTypeErr) | ||
} | ||
// Verify the HTTP response is a 200. |
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.
This comment doesn't seem to be accurate. Should we remove it now?
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.
removed it. Not sure why it was present.
internal/transport/transport_test.go
Outdated
if test.wantStatusEndStream != nil { | ||
want = test.wantStatusEndStream | ||
} |
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.
Thanks, we should be able to remove this if
block now, right?
internal/transport/transport_test.go
Outdated
metaHeaderFrame: &http2.MetaHeadersFrame{ | ||
Fields: []hpack.HeaderField{ | ||
{Name: ":status", Value: "100"}, | ||
}, | ||
}, | ||
httpFlags: http2.FlagHeadersEndStream, |
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.
I think the test was correct before these changes. This test was recently added to fix a bug: #8485
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.
Agreed. Reverted it back.
@@ -103,10 +103,9 @@ func (s) TestHTTPHeaderFrameErrorHandlingInitialHeader(t *testing.T) { | |||
errCode codes.Code | |||
}{ | |||
{ | |||
name: "missing gRPC status", | |||
name: "missing gRPC content type", |
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.
In my opinion, a better fix for this test would be to change the assertion to Ok
instead, keeping the test params the same. codes.Ok
has the zero value for the integer type, so it can be omitted, see https://google.github.io/styleguide/go/decisions#zero-value-fields
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.
there is a test for missing gRPC status already. The expected outcome will not be Ok, it would be an Internal error since gRPC content type is mandated to have the status.
name: "malformed grpc-status-details-bin field with status 200", | ||
name: "malformed grpc-status-details-bin field with status 404 and no content type", |
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.
I think we should keep this test for malformed grpc-status-details-bin
and add a new test for the 404 and no content type
case if necessary. This would ensure we have coverage for the existing scenario.
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.
The status 200 or 404 is immaterial in case of content type being application/grpc, the previous test already caters to that and we are finally checking the malformed grpc-status-details-bin field which we were not doing earlier. Hence, expected outcome code in the previous test is no longer Unimplemented (due to 404), the malformed grpc-status-details-bin now results in an Internal error code.
Fixes #8486
When a gRPC response is received with content type application/grpc, we then do not expect any information in the http status and the status information needs to be conveyed by gRPC status only.
In case of missing gRPC status, we will throw an Internal error instead of Unknown in accordance with https://grpc.io/docs/guides/status-codes/
RELEASE NOTES: