提交 730e6a27 编写于 作者: G Greg Ose

Merge pull request #64 from github/json-sessions

Support custom serialization for Session::CookieStore
2.3.14.github43
2.3.14.github45
......@@ -45,37 +45,74 @@ def initialize(flash)
end
def []=(k, v)
k = k.to_s
@flash[k] = v
@flash.discard(k)
v
end
def [](k)
@flash[k]
@flash[k.to_s]
end
end
class FlashHash < Hash
def self.from_session_value(value)
flash = case value
when FlashHash # Rails 2.3
value
when Hash # Rails 4.0
flashes = value['flashes'] || {}
flashes.stringify_keys!
discard = value['discard'] || []
discard = discard.map do |item|
item.kind_of?(Symbol) ? item.to_s : item
end
used = Hash[flashes.keys.map{|k| [k, discard.include?(k)] }]
new_from_values(flashes, used)
else
new
end
flash
end
def initialize #:nodoc:
super
@used = {}
end
def to_session_value
return nil if empty?
rails_3_discard_list = @used.map{|k,v| k if v}.compact
{'discard' => rails_3_discard_list, 'flashes' => Hash[to_a]}
end
def []=(k, v) #:nodoc:
k = k.to_s
keep(k)
super
super(k, v)
end
def [](k)
super(k.to_s)
end
def delete(k)
super(k.to_s)
end
def update(h) #:nodoc:
h.stringify_keys!
h.keys.each { |k| keep(k) }
super
super(h)
end
alias :merge! :update
def replace(h) #:nodoc:
@used = {}
super
super(h.stringify_keys)
end
# Sets a flash that will not be available to the next action, only to the current.
......@@ -126,8 +163,7 @@ def sweep #:nodoc:
end
def store(session, key = "flash")
return if self.empty?
session[key] = self
session[key] = to_session_value
end
private
......@@ -138,11 +174,20 @@ def store(session, key = "flash")
# use('msg', false) # marks the "msg" entry as unused (keeps it around for one more action)
def use(k=nil, v=true)
unless k.nil?
@used[k] = v
@used[k.to_s] = v
else
keys.each{ |key| use(key, v) }
end
end
def self.new_from_values(flashes, used)
new.tap do |flash_hash|
flashes.each do |k, v|
flash_hash[k] = v
end
flash_hash.instance_variable_set("@used", used)
end
end
end
module InstanceMethods #:nodoc:
......@@ -168,11 +213,11 @@ def redirect_to_with_flash(options = {}, response_status_and_flash = {}) #:doc:
if notice = response_status_and_flash.delete(:notice)
flash[:notice] = notice
end
if other_flashes = response_status_and_flash.delete(:flash)
flash.update(other_flashes)
end
redirect_to_without_flash(options, response_status_and_flash)
end
......@@ -181,19 +226,19 @@ def redirect_to_with_flash(options = {}, response_status_and_flash = {}) #:doc:
# to put a new one.
def flash #:doc:
if !defined?(@_flash)
@_flash = session["flash"] || FlashHash.new
@_flash = Flash::FlashHash.from_session_value(session["flash"])
@_flash.sweep
end
@_flash
end
# Convenience accessor for flash[:alert]
def alert
flash[:alert]
end
# Convenience accessor for flash[:alert]=
def alert=(message)
flash[:alert] = message
......@@ -203,7 +248,7 @@ def alert=(message)
def notice
flash[:notice]
end
# Convenience accessor for flash[:notice]=
def notice=(message)
flash[:notice] = message
......
......@@ -2,7 +2,7 @@
module ActionController
module Session
class AbstractStore
class AbstractStore
ENV_SESSION_KEY = 'rack.session'.freeze
ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze
......@@ -55,17 +55,17 @@ def session_id
def [](key)
load_for_read!
super
super(key.to_s) || super(key)
end
def has_key?(key)
load_for_read!
super
super(key.to_s) || super(key)
end
def []=(key, value)
load_for_write!
super
super(key.to_s, value)
end
def clear
......@@ -87,7 +87,9 @@ def update(hash)
def delete(key)
load_for_write!
super
value = super(key)
string_value = super(key.to_s)
string_value || value
end
def data
......@@ -119,7 +121,7 @@ def destroy
end
private
def load_for_read!
load! if !loaded? && exists?
end
......@@ -183,7 +185,7 @@ def call(env)
request = ActionController::Request.new(env)
return response if (options[:secure] && !request.ssl?)
session_data.send(:load!) if session_data.is_a?(AbstractStore::SessionHash) && !session_data.loaded?
sid = options[:id] || generate_sid
......@@ -205,12 +207,12 @@ def call(env)
end
private
def prepare!(env)
env[ENV_SESSION_KEY] = SessionHash.new(self, env)
env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
end
def generate_sid
ActiveSupport::SecureRandom.hex(16)
end
......@@ -222,7 +224,7 @@ def load_session(env)
[sid, session]
end
end
def extract_session_id(env)
stale_session_check! do
request = Rack::Request.new(env)
......@@ -235,7 +237,7 @@ def extract_session_id(env)
def current_session_id(env)
env[ENV_SESSION_OPTIONS_KEY][:id]
end
def exists?(env)
current_session_id(env).present?
end
......@@ -247,11 +249,11 @@ def get_session(env, sid)
def set_session(env, sid, session_data)
raise '#set_session needs to be implemented.'
end
def destroy(env)
raise '#destroy needs to be implemented.'
end
module SessionUtils
private
def stale_session_check!
......
......@@ -86,7 +86,8 @@ def initialize(app, options = {})
@secret = options.delete(:secret).freeze
@digest = options.delete(:digest) || 'SHA1'
@verifier = verifier_for(@secret, @digest)
@serializer = options.delete(:serializer) || Marshal
@verifier = verifier_for(@secret, @digest, @serializer)
@default_options = DEFAULT_OPTIONS.merge(options).freeze
......@@ -138,13 +139,13 @@ def prepare!(env)
def load_session(env)
data = unpacked_cookie_data(env)
data = persistent_session_id!(data)
[data[:session_id], data]
[data["session_id"] || data[:session_id], data]
end
def extract_session_id(env)
if data = unpacked_cookie_data(env)
persistent_session_id!(data) unless data.empty?
data[:session_id]
data["session_id"] || data[:session_id]
else
nil
end
......@@ -214,9 +215,9 @@ def ensure_secret_secure(secret)
end
end
def verifier_for(secret, digest)
def verifier_for(secret, digest, serializer)
key = secret.respond_to?(:call) ? secret.call : secret
ActiveSupport::MessageVerifier.new(key, digest: digest)
ActiveSupport::MessageVerifier.new(key, digest: digest, serializer: serializer)
end
def generate_sid
......@@ -232,12 +233,12 @@ def persistent_session_id!(data)
end
def inject_persistent_session_id(data)
requires_session_id?(data) ? { :session_id => generate_sid } : {}
requires_session_id?(data) ? { "session_id" => generate_sid } : {}
end
def requires_session_id?(data)
if data
data.respond_to?(:key?) && !data.key?(:session_id)
data.respond_to?(:key?) && !(data.key?("session_id") || data.key?(:session_id))
else
true
end
......
......@@ -219,7 +219,7 @@ def rendered
# A shortcut to the flash. Returns an empty hash if no session flash exists.
def flash
session['flash'] || {}
ActionController::Flash::FlashHash.from_session_value(session["flash"]) || {}
end
# Do we have a flash?
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册