-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
fix(grpc-web): response contains two trailer chunks #11988
fix(grpc-web): response contains two trailer chunks #11988
Conversation
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 have reviewed the test cases, LGTM
end | ||
|
||
if encoding == CONTENT_ENCODING_BASE64 then | ||
body = decode_base64(body) | ||
ngx.log(ngx.WARN, "DECODE BODY: ", body) |
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.
- why do we need warn log here?
- we can use core.log.warn instead
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.
Obviously here leaves out some unneeded code, which I will remove in another PR. 🫡
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 is probably code for testing and debugging.
-- n bytes: trailer | ||
trailer_buf = trailer_buf .. grpc_web_trailer | ||
|
||
return trailer_buf |
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.
return trailer_buf | |
return trailer_buf |
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.
Good catch
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 is a good first issue, hopefully someone from the community can fix this.
Description
This PR is intended to address the following issues:
The reason for this is easy to explain, the old code used
status
to assert whether the response body had finished.But this is unreliable, and it can go wrong in the following cases:
Since the response is chunked, the trailer chunk from upstream may not be fully included in the first response block, so the upstream_trailer_grpc_message variable is not available in the first body_filter, which causes APISIX to trigger the body_filter call a second time and incorrectly add a duplicate trailer block.
Based on the pseudo-code above, you'll see that when this happens, the
upstream_trailer_grpc_status
value is already available to us at the firstbody_filter
call, which causes the plugin code to send a trailer chunk.When the next upstream chunk is received,
body_filter
is called a second time, andupstream_trailer_grpc_status
still has the value it had before, so the plugin code sends the trailer block again.This results in multiple duplicate trailers and accidentally breaks the grpc-web js client in the browser.
This PR changes the end of the response asserted using the
status
value to use thengx.arg[2]
value, which will be the most reliable and trigger the code to send the trailer only on the last chunk.Checklist
The PR does have some compatibility changes, specifically:
405 Method not allowed
instead of400 Bad Request
, which will be more semantic and have no effect on any official client.This has no effect on users who are already using the plugin correctly, so while it may introduce some behavioral changes, it is not a BREAK CHANGE.
In addition to that, I've noticed some behavior that doesn't quite fit the protocol reference implementation; as a grpc-web proxy, the HTTP trailer chunk should be removed and instead be represented as an encoded response body chunk, which APISIX fails to handle correctly. However, since browsers don't care about trailer chunks, this doesn't seem to cause an error, and I'll see how I can work around it and possibly fix it later.