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

Twirp::Service fails to rewind the rack.input #50

Closed
ajvondrak opened this issue Feb 22, 2020 · 4 comments
Closed

Twirp::Service fails to rewind the rack.input #50

ajvondrak opened this issue Feb 22, 2020 · 4 comments

Comments

@ajvondrak
Copy link

ajvondrak commented Feb 22, 2020

The Rack app attempts to route the request by reading in the POST body from Rack::Request#body and decoding it on this line: https://github.com/twitchtv/twirp-ruby/blob/c8520030b3e4eb584042b0a8db9ae606a3b6c6f4/lib/twirp/service.rb#L138

Underneath the hood, this is invoking IO#read on the rack.input stream, which forwards the stream to its end. When downstream middleware attempt to re-read from the input stream, they won't get back any data. For exactly this reason, Rack apps that handle the input stream should generally IO#rewind it once they're done reading.

Specifically, we saw this bug cause exceptions when the Honeycomb Rails middleware attempted to parse the HTTP parameters again. See:

@marioizquierdo
Copy link
Collaborator

Thanks for the report!

I understand this causes req.params to raise an exception, but only if a Twirp service is mounted as a Rack app inside a Rails app.

And this would be avoided if Twirp rewinds the request body after reading it:

body_str = rack_request.body.read
rack_request.body.rewind # so downstream middleware can read again
input = Encoding.decode(body_str, env[:input_class], content_type)

Do you know about any performance implications? Is this a common use case for Rack apps after reading a POST request body?

@ajvondrak
Copy link
Author

Do you know about any performance implications?

AFAIK, it just involves some pointer manipulation to seek the stream's position to the beginning. This looks to be the case in the source code:

I imagine it's O(1).

Is this a common use case for Rack apps after reading a POST request body?

Very common:

It's just generally regarded as necessary housekeeping (e.g., StackOverflow to the effect). Some pieces of code even preemptively rewind the stream before reading it. But not everyone does, so it's safest to rewind to "clean up after yourself". However, there are proposals to remove the #rewind requirement in future versions of Rack altogether: rack/rack#1148

@marioizquierdo
Copy link
Collaborator

marioizquierdo commented Apr 13, 2021

Sorry it took so long to get back to this issue 😅
@ajvondrak do you mind taking a look at the PR #65 ?

@ajvondrak
Copy link
Author

Sorry it took so long to get back to this issue 😅

Believe me, I know how it goes. 😂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants