1

This is the code that works just fine:

require 'sinatra' post '/foo' do "Equals to #{params[:a]}!" end 

If I send POST request, it returns all right:

$ ruby foo.rb -p 8888 $ curl -X POST -H 'Content-Length: 5' --data 'a=444' http://localhost:8888/foo Equals to 444! 

Then, I modify the code, adding Rack::RewindableInput::Middleware because it's necessary for another case, where rewind was available in earlier versions of Rack:

require 'sinatra' use Rack::RewindableInput::Middleware post '/foo' do "Equals to #{params[:a]}!" end 

I'm getting this:

$ ruby foo.rb -p 8888 $ curl -X POST -H 'Content-Length: 5' --data 'a=444' http://localhost:8888/foo Equals to ! 

What am I doing wrong?

1 Answer 1

2

This appears to be an interaction between the RewindableInput middleware and the MethodOverride middleware, which Sinatra adds by default.

Sinatra adds any middleware you specify with use after its own default middleware, so incoming requests see MethodOverride first, and then RewindableInput.

MethodOverride will parse the input (thus consuming the IO) if the content type indicates it is form data, looking for the _method parameter. It puts all the data into a hash in the request env object so that it can be used later.

RewindableInput replaces the input object with a rewindable copy, but the input is now empty.

This wouldn’t be a problem, since the form data has already been parsed into a hash, but Rack only reuses this hash if the underlying IO object is the same. Since the input is now empty, re-parsing it produces no data.

A workaround is to swap the order of these two pieces of middleware. Use disable :method_override to prevent Sinatra adding it by itself, then add it after RewindableInput (alternatively you could just disable MethodOverride if you are not using it):

disable :method_override use Rack::RewindableInput::Middleware use Rack::MethodOverride 
Sign up to request clarification or add additional context in comments.

1 Comment

This works. By the way, using RewindableInput is only required in our app when starting the server withrackup. Starting with puma makes the app use a Puma::NullIO object for the response body which still responds to rewind.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.