Hi,
We're experiencing a Warden compatibility issue upgrading a Grape app from 0.11.0 to 0.13.0.
When we attempt to access a URL which requires authentication we get this trace:
NoMethodError: undefined method `[]' for nil:NilClass
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-mount-0.8.3/lib/rack/mount/route_set.rb:154:in `block in call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-mount-0.8.3/lib/rack/mount/code_generation.rb:96:in `block in recognize'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-mount-0.8.3/lib/rack/mount/code_generation.rb:75:in `optimized_each'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-mount-0.8.3/lib/rack/mount/code_generation.rb:95:in `recognize'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-mount-0.8.3/lib/rack/mount/route_set.rb:141:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/grape-0.13.0/lib/grape/api.rb:114:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/grape-0.13.0/lib/grape/api.rb:44:in `call!'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/grape-0.13.0/lib/grape/api.rb:39:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/urlmap.rb:66:in `block in call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/urlmap.rb:50:in `each'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/urlmap.rb:50:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:653:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/honeybadger-2.1.1/lib/honeybadger/rack/metrics_reporter.rb:17:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/honeybadger-2.1.1/lib/honeybadger/rack/error_notifier.rb:33:in `block in call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/honeybadger-2.1.1/lib/honeybadger/config.rb:190:in `with_request'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/honeybadger-2.1.1/lib/honeybadger/rack/error_notifier.rb:30:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-ssl-enforcer-0.2.9/lib/rack/ssl-enforcer.rb:57:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/tempfile_reaper.rb:15:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/lint.rb:49:in `_call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/lint.rb:37:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/showexceptions.rb:24:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/commonlogger.rb:33:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:218:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/chunked.rb:54:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/content_length.rb:15:in `call'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/thin-1.6.3/lib/thin/connection.rb:86:in `block in pre_process'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/thin-1.6.3/lib/thin/connection.rb:84:in `catch'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/thin-1.6.3/lib/thin/connection.rb:84:in `pre_process'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/thin-1.6.3/lib/thin/connection.rb:53:in `process'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/thin-1.6.3/lib/thin/connection.rb:39:in `receive_data'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/eventmachine-1.0.7/lib/eventmachine.rb:187:in `run_machine'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/eventmachine-1.0.7/lib/eventmachine.rb:187:in `run'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/thin-1.6.3/lib/thin/backends/base.rb:73:in `start'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/thin-1.6.3/lib/thin/server.rb:162:in `start'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/handler/thin.rb:19:in `run'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/server.rb:286:in `start'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/server.rb:147:in `start'
/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/bin/rackup:4:in `<top (required)>'
/Users/matt/.rbenv/versions/2.2.2/bin/rackup:23:in `load'
/Users/matt/.rbenv/versions/2.2.2/bin/rackup:23:in `<main>'
After realising that the issue went away with authentication disabled, we did some debugging from within Warden which lead us to this code: https://github.com/hassox/warden/blob/74162f2bf896b377472b6621ed1f6b40046525f4/lib/warden/manager.rb#L27-L50
We found that with 0.11.0, running this code:
env['warden'] = Proxy.new(env, self)
@app.call(env)
at a breakpoint placed after line 30 of the above snippet, that a rack response body was returned:
=> [200,
{"Content-Type"=>"application/json", "Content-Length"=>"14"},
#<Rack::BodyProxy:0x007fd5fd1cf388
@block=
#<Proc:0x007fd5fd1cf2e8@/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activerecord-4.2.3/lib/active_record/connection_adapters/abstract/connection_pool.rb:654>,
@body=
#<Rack::BodyProxy:0x007fd5fd1cf5e0
@block=#<Proc:0x007fd5fd1cf518@/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/response.rb:82>,
@body=
#<Rack::Response:0x007fd5fd1cf9c8
@block=nil,
@body=["{\"hello\":\"hi\"}"],
@chunked=false,
@header={"Content-Type"=>"application/json", "Content-Length"=>"14"},
@length=14,
@status=200,
@writer=#<Proc:0x007fd5fd1cf798@/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/response.rb:30 (lambda)>>,
@closed=false>,
@closed=false>]
After escaping from this breakpoint, the request completes successfully.
Whereas with 0.13.0, we got the following return value:
=> #<Rack::Response:0x007fa522ba30a0
@block=nil,
@body=["{\"hello\":\"hi\"}"],
@chunked=false,
@header={"Content-Type"=>"application/json", "Content-Length"=>"14"},
@length=14,
@status=200,
@writer=#<Proc:0x007fa522ba2f38@/Users/matt/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/response.rb:30 (lambda)>>
and on continuation, we get the trace above.
It'd be great if you could explain whether or not this is intended behaviour, and if it is, what an appropriate workaround might be from our side.
Thanks in advance for your help (and thanks for Grape too! :smiley:).
This is because Grape no longer returns an array of status code, headers and bodies, but a Rack::Response. Check the top of https://github.com/ruby-grape/grape/blob/master/UPGRADING.md, there's quite a bit of detail.
It looks like something is trying to access the response with response[1] (probably trying to get the headers), whereas the response is an object. There's definitely a workaround where you can just call to_a in a middleware but it's possible that the calling code should change - it would be much faster than having to convert these things into an array.
I'll close this, but if you can't figure out how to fix it put up a project with a repro and I'll help you out.
Just to be clear this is NOT an issue with grape or indeed warden, it is a break caused by the update or RACK from 2.0.8 to 2.1.1. Nailing the version of rack down to 2.0.8 should resolve the issue until grape can catch up.
Most helpful comment
Just to be clear this is NOT an issue with grape or indeed warden, it is a break caused by the update or RACK from 2.0.8 to 2.1.1. Nailing the version of rack down to 2.0.8 should resolve the issue until grape can catch up.