Skip to content
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

transport: return http-status when grpc-status is missing #4606

Closed
wants to merge 6 commits into from

Conversation

JNProtzman
Copy link
Contributor

@JNProtzman JNProtzman commented Jul 21, 2021

This (hopefully) addresses @dfawley's comment.

RELEASE NOTES: n/a

@@ -1318,7 +1318,8 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream)
return
}
rawStatusCode = codes.Code(uint32(code))
rsc := codes.Code(uint32(code))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't ParseInt above be ParseUint?

And then we need a bounds check on this as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I adjusted this to ParseUint. What kind of bounds check should I do?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, nevermind the bounds checks. If we were to add a new status code, I believe we'd want to allow it to be propagated by a gRPC proxy without requiring recompilation of the proxy. So any unsigned value is fine here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK great. I think this is ready for re-review then!

@@ -1366,7 +1367,9 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
if !isGRPC || httpStatusErr != "" {
var code = codes.Internal // when header does not include HTTP status, return INTERNAL

if httpStatusCode != nil {
if rawStatusCode != nil {
code = *rawStatusCode
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So now here is the big question: what if rawStatusCode is OK?

If you read the spec literally, we should ignore the HTTP status in this case. This appears to be what the other languages do as well, so I suppose we should do that, even though to me it appears to be covering up errors in the system. (@ejona86 @markdroth FYI)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you mentioned - this results in potentially covering up an error. Here's an example in tests in this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this part of the change is right. A missing content-type error should continue to take priority over a grpc-status of OK (though that's admittedly a gray area and also unlikely to happen). We should still use that precedence, but only change it so we take grpc-status over http-status if everything higher priority is okay.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a stab at this. I'm not 100% sure it's what you meant but I think it is. If we receive a grpc-status but have encountered another error, we'll take the http-status over the grpc-status. Otherwise, we'll default to the http-status.

Comment on lines 1444 to 1448
if rawStatusCode == nil {
rsc := codes.Unknown
rawStatusCode = &rsc
}
statusGen = status.New(*rawStatusCode, grpcMessage)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do this the other way around to avoid an allocation (even if it hopefully doesn't escape the stack):

if statusGen == nil {
	rsc := codes.Unknown
	if rawStatusCode != nil {
		rsc = *rawStatusCode
	}
	statusGen = status.New(rsc, grpcMessage)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@dfawley dfawley assigned JNProtzman and unassigned dfawley Jul 21, 2021
@dfawley
Copy link
Member

dfawley commented Aug 18, 2021

Friendly ping on this PR as well - my comment 7d ago is hidden in a thread above, so I also wanted to make sure it's more obvious that this PR isn't blocked on me.

@JNProtzman
Copy link
Contributor Author

I know the tests are failing but it seems like those might be unrelated. @dfawley, I think this is ready for your review again.

@github-actions
Copy link

This PR is labeled as requiring an update from the reporter, and no update has been received after 6 days. If no update is provided in the next 7 days, this issue will be automatically closed.

@@ -2090,7 +2090,7 @@ func (s) TestClientDecodeHeaderStatusErr(t *testing.T) {
metaHeaderFrame: &http2.MetaHeadersFrame{
Fields: []hpack.HeaderField{
{Name: "content-type", Value: "application/grpc"},
{Name: "grpc-status", Value: "0"},
{Name: "grpc-status", Value: "14"},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is a grpc-status, then there should be a grpc-message to go along with it, or we should use the empty string like we do normally -- we should not be using the generated "unexpected HTTP status code" error message. At least, that's what it seems like it should be doing, though it's not mentioned in our docs. Does that seem right to you, @ejona86 / @markdroth?

Maybe set this error code to a different number and change the wantStatus code, so it is clear that's the source of the error, not the 504->Unavailable conversion?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say a grpc-message should go along with it from a "we don't hate ourselves" perspective. If there isn't a message, I wouldn't use an empty string; I'd leave the header missing. I wouldn't suggest a useless message like "UNAVAILABLE"; again, I'd prefer just not having it.

But that's a bit neither here nor there. In this case, there is a grpc-status, so you should use that and the grpc-message if it isn't present. I don't think this test is correct: the status shouldn't have a status description.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd leave the header missing

This is client-side. If the header is missing, the client would use "" as the message string presented to the user. (We have to give them some string, since it's returned as a string value; we can't use nil.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, then yeah, empty string seems appropriate for your API. Java's API lets the description (which we call grpc-message) be null. Makes sense that you wouldn't have such a distinction in Go.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping @JNProtzman, I think this is the last issue: to not use the generated http error message along with the grpc-status header value in the status returned to the user.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dfawley sorry for the delay here. I'm currently in Iceland and have plans to travel through Europe until Nov. 1st. I won't be able to pick this up until then... sorry!

@dfawley
Copy link
Member

dfawley commented Nov 17, 2021

Ping @JNProtzman - hope all is well. Have you returned, and are you able to pick this PR up again?

@github-actions
Copy link

This PR is labeled as requiring an update from the reporter, and no update has been received after 6 days. If no update is provided in the next 7 days, this issue will be automatically closed.

@github-actions github-actions bot added the stale label Nov 23, 2021
@github-actions github-actions bot closed this Nov 30, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants