Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #3708 (closed defect: worksforme)

Opened 3 years ago

Last modified 11 months ago

Routing errors and other exceptions create sessions when sessions are disabled

Reported by: craig@iconfactory.com Assigned to: jamis@37signals.com
Priority: high Milestone: 1.2.4
Component: ActionPack Version: 1.0.0
Severity: major Keywords: session, routing
Cc: bitsweat, tarmo

Description

If you include the following in your environment.rb, sessions will be disabled:

ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.update(:disabled => true)

This works wonderfully for requests that are processed normally through Rails' routing mechanism.

However, whenever there is an exception, such as a ActionController::RoutingError caused by a bad image URL, a session will be created. This results, in the default configuration, in a /tmp/ruby_sess.* file appearing.

This problem can be fixed by first changing the #dispatch method in Dispatcher (dispatcher.rb, line 36):

  request, response = ActionController::CgiRequest.new(cgi, (session_options[:disabled] ? false : session_options)), ActionController::CgiResponse.new(cgi)

This causes CgiRequest to instantiate a Hash for @session instead of a CGI::Session.

The second part of the fix is with handling the exception page. The #process_with_exception method in ActionController::Rescue::ClassMethods should call #process_without_session_management_support instead of #process. Line 20 of rescue.rb becomes:

  new.process_without_session_management_support(request, response, :rescue_action, exception)

Without this change, @session_options in the CgiRequest gets updated in #process_with_session_management_support with the results of #session_options_for and will no longer have a false value. Later, in #assign_shortcuts, #session in CgiRequest is queried and a CGI::Session object is instantiated because @session_options is not false.

And, yeah, this was a real nasty bug to find & fix :-)

-ch

Change History

02/03/06 00:01:15 changed by craig@iconfactory.com

Note: I did not provide a patch for this because I'm not sure if it's OK for ActionController::Rescue to have a dependency on ActionController::SessionManagement (because of the stuff aliasing happening in #append_features.)

02/03/06 17:56:31 changed by craig@iconfactory.com

In thinking about the problem some more, it appears that there is a design issue with how sessions are disabled.

In ActionController::CgiRequest, sessions are disabled by setting @session_options to false (causing @session to become an empty Hash.) In ActionController::SessionManagement, sessions are disabled using the :disable key in the @session_options Hash.

Shouldn't there just be one mechanism to disable sessions in session_options?

06/21/06 01:04:40 changed by bitsweat

  • cc set to bitsweat.
  • component changed from ActiveSupport to ActionPack.

Interesting! Sorry I missed this when it was posted. Are you seeing the same issue on Rails 1.1.x?

06/21/06 02:34:00 changed by craig@iconfactory.com

Yes, this is still a problem with 1.1.2.

My workaround has been to add the following as the last route in routes.rb:

  # catch-all for routes
  #  (so that a routing exception will not be raised, and an unneeded session generated)
  map.connect '*path_info', :controller => 'exception', :action => 'index'

Still, I'd prefer to let my rescue_action_in_public mechanism do the work...

-ch

P.S. Sorry about getting the component wrong -- it wasn't easy deciding which one was most appropriate.

09/06/06 01:43:30 changed by david

  • owner changed from David to jamis@37signals.com.

11/09/06 09:11:18 changed by bitsweat

  • milestone set to 1.2.

08/07/07 01:37:56 changed by tarmo

  • cc changed from bitsweat to bitsweat, tarmo.
  • status changed from new to closed.
  • resolution set to worksforme.

I failed to confirm this on Rails 1.2.3 with the following code, no session was generated for both a valid request "/main" and an invalid one "/asd"

class ApplicationController < ActionController::Base
  session :session_key => '_asd_1.2_session_id', :disabled => true
end

class MainController < ApplicationController

  def index
    b = session['asd'].to_s.dup
    session['asd'] = Time.now.inspect
    render :text => "Time: #{b}"
  end
end

On rails edge instead of setting the session options in application controller I set them in config/environment.rb with:

Rails::Initializer.run do |config|
  config.action_controller.session = { :session_key => "_myapp_session", :secret => "some secret phrase", :disabled => true }
end

Please reopen if you can still reproduce this bug on either 1.2.3 or edge.