diff options
author | Jamis Buck <jamis@37signals.com> | 2006-03-08 16:53:34 +0000 |
---|---|---|
committer | Jamis Buck <jamis@37signals.com> | 2006-03-08 16:53:34 +0000 |
commit | 519e7e5e1236dfb75a7d759e0a143bc9e0e47385 (patch) | |
tree | 293bdae2653b4c54b4a61218dbf5f18b5f544d3a | |
parent | 8b4729a0eb2020cc5f7ed93951e97335bd3d2700 (diff) | |
download | rails-519e7e5e1236dfb75a7d759e0a143bc9e0e47385.tar.gz rails-519e7e5e1236dfb75a7d759e0a143bc9e0e47385.tar.bz2 rails-519e7e5e1236dfb75a7d759e0a143bc9e0e47385.zip |
Fix problem with unloaded ARStore sessions being loaded when they are garbage collected, causing problems if there were AR objects in the session.
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3817 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
-rw-r--r-- | actionpack/lib/action_controller/session/active_record_store.rb | 23 | ||||
-rw-r--r-- | actionpack/test/activerecord/active_record_store_test.rb | 22 |
2 files changed, 36 insertions, 9 deletions
diff --git a/actionpack/lib/action_controller/session/active_record_store.rb b/actionpack/lib/action_controller/session/active_record_store.rb index 3d84d85ac0..5f3b960b59 100644 --- a/actionpack/lib/action_controller/session/active_record_store.rb +++ b/actionpack/lib/action_controller/session/active_record_store.rb @@ -59,10 +59,8 @@ class CGI cattr_accessor :data_column_name self.data_column_name = 'data' - # Don't try to save if we haven't loaded the session. - before_update :loaded? - before_save :marshal_data! - before_save :raise_on_session_data_overflow! + before_save :marshal_data! + before_save :raise_on_session_data_overflow! class << self # Don't try to reload ARStore::Session in dev mode. @@ -122,22 +120,24 @@ class CGI @data ||= self.class.unmarshal(read_attribute(@@data_column_name)) || {} end + # Has the session been loaded yet? + def loaded? + !! @data + end + private attr_writer :data def marshal_data! + return false if !loaded? write_attribute(@@data_column_name, self.class.marshal(self.data)) end - # Has the session been loaded yet? - def loaded? - !! @data - end - # Ensures that the data about to be stored in the database is not # larger than the data storage column. Raises # ActionController::SessionOverflowError. def raise_on_session_data_overflow! + return false if !loaded? limit = self.class.data_column_size_limit if loaded? and limit and read_attribute(@@data_column_name).size > limit raise ActionController::SessionOverflowError @@ -232,7 +232,12 @@ class CGI @data end + def loaded? + !! @data + end + def save + return false if !loaded? marshaled_data = self.class.marshal(data) if @new_record diff --git a/actionpack/test/activerecord/active_record_store_test.rb b/actionpack/test/activerecord/active_record_store_test.rb index 3ab6c40909..96c147c7d0 100644 --- a/actionpack/test/activerecord/active_record_store_test.rb +++ b/actionpack/test/activerecord/active_record_store_test.rb @@ -62,6 +62,10 @@ class ActiveRecordStoreTest < Test::Unit::TestCase CGI::Session::ActiveRecordStore::Session end + def session_id_column + "session_id" + end + def setup session_class.create_table! @@ -84,6 +88,20 @@ class ActiveRecordStoreTest < Test::Unit::TestCase assert_equal({ 'foo' => 'bar' }, @new_session.model.data) end + def test_save_unloaded_session + c = session_class.connection + bogus_class = c.quote(Base64.encode64("\004\010o:\vBlammo\000")) + c.insert("INSERT INTO #{session_class.table_name} ('#{session_id_column}', 'data') VALUES ('abcdefghijklmnop', #{bogus_class})") + + sess = session_class.find_by_session_id('abcdefghijklmnop') + assert_not_nil sess + assert !sess.loaded? + + # because the session is not loaded, the save should be a no-op. If it + # isn't, this'll try and unmarshall the bogus class, and should get an error. + assert_nothing_raised { sess.save } + end + def teardown session_class.drop_table! end @@ -110,6 +128,10 @@ class ColumnLimitTest < Test::Unit::TestCase end class DeprecatedActiveRecordStoreTest < ActiveRecordStoreTest + def session_id_column + "sessid" + end + def setup session_class.connection.execute 'create table old_sessions (id integer primary key, sessid text unique, data text)' session_class.table_name = 'old_sessions' |