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

Session store @env is nil with Rails 7 #244

Open
Tracked by #12077
chadlwilson opened this issue Oct 8, 2023 · 5 comments
Open
Tracked by #12077

Session store @env is nil with Rails 7 #244

chadlwilson opened this issue Oct 8, 2023 · 5 comments

Comments

@chadlwilson
Copy link
Contributor

chadlwilson commented Oct 8, 2023

I don't really have any deep experience with Rack or JRuby Rack - so please excuse the question if it speaks to ignorance.

After upgrading a JRuby-on-Rails application from Rails 6.1.7.6 to 7.0.8 I get the following stack traces when accessing any rails pages/controllers.

NoMethodError in StagesController#overview 
undefined method `[]' for nil:NilClass (around line/#86)
      def get_servlet_session(env, create = false)
        servlet_session = env[ENV_SERVLET_SESSION_KEY] # <--- line 86
        invalid = false
        begin
          if servlet_session.nil? ||

coming from

servlet_session = store.get_servlet_session(@env)

I'm not quite sure how the @env ends up nil, but there seems to be some Rails-version-coupled stuff here.

if defined?(::Rack::Session::Abstract::SessionHash) # Rack 1.3+
# as of rails 3.1.x the rack session hash implementation is used
# rather than the custom rails AbstractStore::SessionHash class
class SessionHash < ::Rack::Session::Abstract::SessionHash; end
# 1.5.0 removed SessionHash http://github.com/rack/rack/commit/83a270d64820
OptionsHash = if defined?(::Rack::Session::Abstract::OptionsHash)
::Rack::Session::Abstract::OptionsHash
else nil
end
elsif defined?(ActionDispatch::Session::AbstractStore) # Rails 3.0
require 'active_support/core_ext/hash' # non-loaded SessionHash dependency
class SessionHash < ActionDispatch::Session::AbstractStore::SessionHash; end
OptionsHash = ActionDispatch::Session::AbstractStore::OptionsHash
else # a fallback for (old) Rails 2.3
class SessionHash < ActionController::Session::AbstractStore::SessionHash; end
OptionsHash = ActionController::Session::AbstractStore::OptionsHash
end
SessionHash.class_eval do
# Allows direct delegation to servlet session methods when session is active
def method_missing(method, *args, &block)
servlet_session = store.get_servlet_session(@env)
if servlet_session && servlet_session.respond_to?(method)
servlet_session.send(method, *args, &block)
else
super
end
end
private
def store
@store ||= defined?(@store) ? @store : @by # Rack 1.5 renamed @by
end
end

Does anyone know what might have changed that could perhaps break rack or jruby-rack to point me in the right direction? Something to do with autoloading?

uri:classloader:/jruby/rack/session_store.rb:86:in `get_servlet_session'
uri:classloader:/jruby/rack/session_store.rb:45:in `method_missing'
actionpack (7.0.8) lib/action_dispatch/middleware/flash.rb:63:in `commit_flash'
actionpack (7.0.8) lib/action_controller/metal.rb:189:in `dispatch'
actionpack (7.0.8) lib/action_controller/metal.rb:251:in `dispatch'
actionpack (7.0.8) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
actionpack (7.0.8) lib/action_dispatch/routing/route_set.rb:32:in `serve'
actionpack (7.0.8) lib/action_dispatch/journey/router.rb:50:in `block in serve'
org/jruby/RubyArray.java:1989:in `each'
actionpack (7.0.8) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (7.0.8) lib/action_dispatch/routing/route_set.rb:852:in `call'
rack (2.2.8) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.8) lib/rack/etag.rb:27:in `call'
rack (2.2.8) lib/rack/conditional_get.rb:27:in `call'
rack (2.2.8) lib/rack/head.rb:12:in `call'
actionpack (7.0.8) lib/action_dispatch/http/permissions_policy.rb:38:in `call'
actionpack (7.0.8) lib/action_dispatch/http/content_security_policy.rb:36:in `call'
uri:classloader:/jruby/rack/session_store.rb:79:in `context'
rack (2.2.8) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/cookies.rb:704:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (7.0.8) lib/active_support/callbacks.rb:99:in `run_callbacks'
actionpack (7.0.8) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/debug_exceptions.rb:28:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/show_exceptions.rb:29:in `call'
railties (7.0.8) lib/rails/rack/logger.rb:40:in `call_app'
railties (7.0.8) lib/rails/rack/logger.rb:27:in `call'
sprockets-rails (3.4.2) lib/sprockets/rails/quiet_assets.rb:13:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/remote_ip.rb:93:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/request_id.rb:26:in `call'
rack (2.2.8) lib/rack/method_override.rb:24:in `call'
rack (2.2.8) lib/rack/runtime.rb:22:in `call'
activesupport (7.0.8) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/server_timing.rb:61:in `block in call'
actionpack (7.0.8) lib/action_dispatch/middleware/server_timing.rb:26:in `collect_events'
actionpack (7.0.8) lib/action_dispatch/middleware/server_timing.rb:60:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/static.rb:23:in `call'
rack (2.2.8) lib/rack/sendfile.rb:110:in `call'
actionpack (7.0.8) lib/action_dispatch/middleware/host_authorization.rb:138:in `call'
railties (7.0.8) lib/rails/engine.rb:530:in `call'
uri:classloader:/rack/handler/servlet.rb:22:in `call' 
@kares
Copy link
Member

kares commented Oct 9, 2023

Thanks for the report Chad, it seems JRuby-Rack's (servlet) session store isn't compatible with Rack 2.2.
Honestly, I wasn't even aware that it worked with Rails 6.x given the project has not had much maintenance for a while.

In the mean-time you could switch to simply using the Rails default (cookie) session store..

@chadlwilson
Copy link
Contributor Author

chadlwilson commented Oct 9, 2023

We've had it working with Rack 2.2 (somehow) via Rails 5.2, 6.0 and 6.1 for some time so not sure what changed about Rails 7 that broke this.

There's also this that might be related 😅 https://github.com/gocd/gocd/blob/c4888b585a239dd32b32a532d0de0b286c62c687/server/src/main/webapp/WEB-INF/rails/config/initializers/session_store.rb#L18

So perhaps it worked in a very limited set of circumstances/usages/hacks. Almost all auth and session 'stuff' for our app is handled in Java-land prior to getting to the RackServlet, upon which Rails is only used for a handful of pages/controllers that have proven "resistant" to migration.

@kares
Copy link
Member

kares commented Oct 9, 2023

yeah, sounds like the fix should be rather simple than, but it still requires someone to do "a lot of" work (ideally getting the test suite/CI running with Rails versions we intend to support). I would be happy to keep this project going but lack time to even properly support my other oss work 😞 ...

There's also this that might be related 😅 https://github.com/gocd/gocd/blob/c4888b585a239dd32b32a532d0de0b286c62c687/server/src/main/webapp/WEB-INF/rails/config/initializers/session_store.rb#L18

✔️ that is the proper way to switch to the servlet store but only in a servlet container environment (if you simply remove that initializer this should no longer block you from running)

@chadlwilson
Copy link
Contributor Author

chadlwilson commented Oct 9, 2023

There's also this that might be related 😅 https://github.com/gocd/gocd/blob/c4888b585a239dd32b32a532d0de0b286c62c687/server/src/main/webapp/WEB-INF/rails/config/initializers
✔️ that is the proper way to switch to the servlet store but only in a servlet container environment (if you simply remove that initializer this should no longer block you from running)

Our current setup is using Jetty started inline as servlet container, deploying a war into Jetty programmatically, of which RackServlet is one of a few servlets handling different routes and then splitting (with some url rewriting) across. Some routes use Java Spring FW, some use Rails/Rack via JRuby. Is that the type of servlet container usage you're referring to that could make this code appropriate?

I believe that's why that is there (not being around when this was all wired together and just taking over as defacto maintainer I'm doing some guessing as to intent and how this all works!)

Regardless, for my own curiosity I'll try removing and see what happens 😅

@kares
Copy link
Member

kares commented Oct 9, 2023

Jetty "inline" (pbly aka embedded) servlet container is still a servlet container 😜.
If the $servlet_context woud not be there you would not have ended up with jruby-rack's (servlet) session store failure as reported in this issue (assuming the initializer setup you mentioned previously).

JRuby-Rack (e.g. from a configured context-listener) starts an embedded JRuby which eventually sets the $servlet_context globa

Some routes use Java Spring FW, some use Rails/Rack via JRuby.

sounds like a fun project 😉

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