mirror of
https://github.com/github/rails.git
synced 2026-01-13 08:38:05 -05:00
Compare commits
25 Commits
v3.2.19.gi
...
v3.2.19.gi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6f150c40c | ||
|
|
76ad4030e5 | ||
|
|
0a3c7ba903 | ||
|
|
d69e65ab34 | ||
|
|
56d2614309 | ||
|
|
0afd326c36 | ||
|
|
c957f5f609 | ||
|
|
90ded51cc1 | ||
|
|
74b7cb9868 | ||
|
|
bce8b07309 | ||
|
|
3fe553fa31 | ||
|
|
e1c7a232ca | ||
|
|
283923f530 | ||
|
|
18d37237c4 | ||
|
|
b30301bb6d | ||
|
|
d12475ba60 | ||
|
|
d106a28675 | ||
|
|
67b3fd5cb8 | ||
|
|
0342deaa22 | ||
|
|
91bbe59e17 | ||
|
|
f0895f838f | ||
|
|
c9a54ce81d | ||
|
|
f6844fc683 | ||
|
|
b09eac885e | ||
|
|
1edd8b587b |
@@ -1 +1 @@
|
||||
3.2.19.github3
|
||||
3.2.19.github7
|
||||
|
||||
@@ -489,6 +489,7 @@ module ActionController
|
||||
@controller.recycle!
|
||||
@controller.process_with_new_base_test(@request, @response)
|
||||
@assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {}
|
||||
@request.session['flash'] = @request.flash.to_session_value
|
||||
@request.session.delete('flash') if @request.session['flash'].blank?
|
||||
@response
|
||||
end
|
||||
|
||||
@@ -81,6 +81,7 @@ module ActionDispatch
|
||||
class Cookies
|
||||
HTTP_HEADER = "Set-Cookie".freeze
|
||||
TOKEN_KEY = "action_dispatch.secret_token".freeze
|
||||
SESSION_SERIALIZER = "action_dispatch.session_serializer".freeze
|
||||
|
||||
# Raised when storing more than 4K of session data.
|
||||
class CookieOverflow < StandardError; end
|
||||
@@ -106,13 +107,14 @@ module ActionDispatch
|
||||
secret = request.env[TOKEN_KEY]
|
||||
host = request.host
|
||||
secure = request.ssl?
|
||||
serializer = request.env[SESSION_SERIALIZER]
|
||||
|
||||
new(secret, host, secure).tap do |hash|
|
||||
new(secret, host, secure, serializer).tap do |hash|
|
||||
hash.update(request.cookies)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(secret = nil, host = nil, secure = false)
|
||||
def initialize(secret = nil, host = nil, secure = false, serializer = nil)
|
||||
@secret = secret
|
||||
@set_cookies = {}
|
||||
@delete_cookies = {}
|
||||
@@ -120,6 +122,7 @@ module ActionDispatch
|
||||
@secure = secure
|
||||
@closed = false
|
||||
@cookies = {}
|
||||
@serializer = serializer
|
||||
end
|
||||
|
||||
def each(&block)
|
||||
@@ -211,7 +214,7 @@ module ActionDispatch
|
||||
# cookies.permanent.signed[:remember_me] = current_user.id
|
||||
# # => Set-Cookie: remember_me=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
|
||||
def permanent
|
||||
@permanent ||= PermanentCookieJar.new(self, @secret)
|
||||
@permanent ||= PermanentCookieJar.new(self, @secret, @serializer)
|
||||
end
|
||||
|
||||
# Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from
|
||||
@@ -228,7 +231,7 @@ module ActionDispatch
|
||||
#
|
||||
# cookies.signed[:discount] # => 45
|
||||
def signed
|
||||
@signed ||= SignedCookieJar.new(self, @secret)
|
||||
@signed ||= SignedCookieJar.new(self, @secret, @serializer)
|
||||
end
|
||||
|
||||
def write(headers)
|
||||
@@ -252,8 +255,8 @@ module ActionDispatch
|
||||
end
|
||||
|
||||
class PermanentCookieJar < CookieJar #:nodoc:
|
||||
def initialize(parent_jar, secret)
|
||||
@parent_jar, @secret = parent_jar, secret
|
||||
def initialize(parent_jar, secret, serializer)
|
||||
@parent_jar, @secret, @serializer = parent_jar, secret, serializer
|
||||
end
|
||||
|
||||
def []=(key, options)
|
||||
@@ -268,7 +271,7 @@ module ActionDispatch
|
||||
end
|
||||
|
||||
def signed
|
||||
@signed ||= SignedCookieJar.new(self, @secret)
|
||||
@signed ||= SignedCookieJar.new(self, @secret, @serializer)
|
||||
end
|
||||
|
||||
def method_missing(method, *arguments, &block)
|
||||
@@ -280,10 +283,10 @@ module ActionDispatch
|
||||
MAX_COOKIE_SIZE = 4096 # Cookies can typically store 4096 bytes.
|
||||
SECRET_MIN_LENGTH = 30 # Characters
|
||||
|
||||
def initialize(parent_jar, secret)
|
||||
def initialize(parent_jar, secret, serializer)
|
||||
ensure_secret_secure(secret)
|
||||
@parent_jar = parent_jar
|
||||
@verifier = ActiveSupport::MessageVerifier.new(secret)
|
||||
@verifier = ActiveSupport::MessageVerifier.new(secret, :serializer => serializer)
|
||||
end
|
||||
|
||||
def [](name)
|
||||
|
||||
@@ -4,7 +4,7 @@ module ActionDispatch
|
||||
# read a notice you put there or <tt>flash["notice"] = "hello"</tt>
|
||||
# to put a new one.
|
||||
def flash
|
||||
@env[Flash::KEY] ||= (session["flash"] || Flash::FlashHash.new)
|
||||
@env[Flash::KEY] ||= Flash::FlashHash.from_session_value(session["flash"])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -77,10 +77,24 @@ module ActionDispatch
|
||||
class FlashHash
|
||||
include Enumerable
|
||||
|
||||
def initialize #:nodoc:
|
||||
@used = Set.new
|
||||
def self.from_session_value(value)
|
||||
case value
|
||||
when Hash # After github/github-rails#9, only plain Hashes are in the session
|
||||
new(value['flashes'], value['discard'])
|
||||
else
|
||||
new
|
||||
end
|
||||
end
|
||||
|
||||
def to_session_value
|
||||
return nil if empty?
|
||||
{'discard' => @used.to_a, 'flashes' => @flashes}
|
||||
end
|
||||
|
||||
def initialize(flashes = {}, discard = []) #:nodoc:
|
||||
@used = Set.new(discard)
|
||||
@closed = false
|
||||
@flashes = {}
|
||||
@flashes = flashes
|
||||
@now = nil
|
||||
end
|
||||
|
||||
@@ -93,15 +107,17 @@ module ActionDispatch
|
||||
end
|
||||
|
||||
def []=(k, v) #:nodoc:
|
||||
k = k.to_s
|
||||
keep(k)
|
||||
@flashes[k] = v
|
||||
end
|
||||
|
||||
def [](k)
|
||||
@flashes[k]
|
||||
@flashes[k.to_s]
|
||||
end
|
||||
|
||||
def update(h) #:nodoc:
|
||||
h.stringify_keys!
|
||||
h.keys.each { |k| keep(k) }
|
||||
@flashes.update h
|
||||
self
|
||||
@@ -112,11 +128,11 @@ module ActionDispatch
|
||||
end
|
||||
|
||||
def key?(name)
|
||||
@flashes.key? name
|
||||
@flashes.key? name.to_s
|
||||
end
|
||||
|
||||
def delete(key)
|
||||
@flashes.delete key
|
||||
@flashes.delete key.to_s
|
||||
self
|
||||
end
|
||||
|
||||
@@ -140,7 +156,7 @@ module ActionDispatch
|
||||
|
||||
def replace(h) #:nodoc:
|
||||
@used = Set.new
|
||||
@flashes.replace h
|
||||
@flashes.replace h.stringify_keys
|
||||
self
|
||||
end
|
||||
|
||||
@@ -235,8 +251,9 @@ module ActionDispatch
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if (session = env['rack.session']) && (flash = session['flash'])
|
||||
if (session = env['rack.session']) && (flash = Flash::FlashHash.from_session_value(session["flash"]))
|
||||
flash.sweep
|
||||
env[KEY] = flash
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
@@ -246,7 +263,7 @@ module ActionDispatch
|
||||
|
||||
if flash_hash
|
||||
if !flash_hash.empty? || session.key?('flash')
|
||||
session["flash"] = flash_hash
|
||||
session["flash"] = flash_hash.to_session_value
|
||||
new_hash = flash_hash.dup
|
||||
else
|
||||
new_hash = flash_hash
|
||||
@@ -255,7 +272,7 @@ module ActionDispatch
|
||||
env[KEY] = new_hash
|
||||
end
|
||||
|
||||
if session.key?('flash') && session['flash'].empty?
|
||||
if session['flash'] && session['flash'].empty?
|
||||
session.delete('flash')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,11 +2,11 @@ module ActionView
|
||||
# = Action View Cache Helper
|
||||
module Helpers
|
||||
module CacheHelper
|
||||
# This helper exposes a method for caching fragments of a view
|
||||
# This helper exposes a method for caching fragments of a view
|
||||
# rather than an entire action or page. This technique is useful
|
||||
# caching pieces like menus, lists of newstopics, static HTML
|
||||
# fragments, and so on. This method takes a block that contains
|
||||
# the content you wish to cache.
|
||||
# the content you wish to cache.
|
||||
#
|
||||
# See ActionController::Caching::Fragments for usage instructions.
|
||||
#
|
||||
@@ -23,7 +23,7 @@ module ActionView
|
||||
# <p>Hello users! Welcome to our website!</p>
|
||||
# <% end %>
|
||||
#
|
||||
# Static content with embedded ruby content can be cached as
|
||||
# Static content with embedded ruby content can be cached as
|
||||
# well:
|
||||
#
|
||||
# <% cache do %>
|
||||
@@ -49,10 +49,11 @@ module ActionView
|
||||
else
|
||||
# VIEW TODO: Make #capture usable outside of ERB
|
||||
# This dance is needed because Builder can't use capture
|
||||
pos = output_buffer.length
|
||||
pos = output_buffer.bytesize
|
||||
yield
|
||||
output_safe = output_buffer.html_safe?
|
||||
fragment = output_buffer.slice!(pos..-1)
|
||||
fragment = output_buffer.byteslice(pos..-1)
|
||||
self.output_buffer = output_buffer.byteslice(0...pos)
|
||||
if output_safe
|
||||
self.output_buffer = output_buffer.class.new(output_buffer)
|
||||
end
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Upstream FlashHash tests from:
|
||||
# https://github.com/rails/rails/blob/a6ce984b49519de7701aa13d04300c9d03cf8f72/actionpack/test/controller/flash_hash_test.rb
|
||||
require 'abstract_unit'
|
||||
|
||||
module ActionDispatch
|
||||
@@ -46,6 +48,31 @@ module ActionDispatch
|
||||
assert_equal({'foo' => 'bar'}, @hash.to_hash)
|
||||
end
|
||||
|
||||
def test_to_session_value
|
||||
@hash['foo'] = 'bar'
|
||||
assert_equal({'flashes' => {'foo' => 'bar'}, 'discard' => []}, @hash.to_session_value)
|
||||
|
||||
@hash.discard('foo')
|
||||
assert_equal({'flashes' => {'foo' => 'bar'}, 'discard' => %w[foo]}, @hash.to_session_value)
|
||||
|
||||
@hash.now['qux'] = 1
|
||||
assert_equal({'flashes' => {'foo' => 'bar', 'qux' => 1}, 'discard' => %w[foo qux]}, @hash.to_session_value)
|
||||
|
||||
@hash.sweep
|
||||
assert_equal(nil, @hash.to_session_value)
|
||||
end
|
||||
|
||||
def test_from_session_value_on_json_serializer
|
||||
decrypted_data = "{ \"session_id\":\"d98bdf6d129618fc2548c354c161cfb5\", \"flash\":{\"discard\":[], \"flashes\":{\"message\":\"hey you\"}} }"
|
||||
session = ActiveSupport::JSON.decode(decrypted_data)
|
||||
hash = Flash::FlashHash.from_session_value(session['flash'])
|
||||
hash.sweep
|
||||
|
||||
assert_equal({'discard' => %w[message], 'flashes' => { 'message' => 'hey you'}}, hash.to_session_value)
|
||||
assert_equal "hey you", hash[:message]
|
||||
assert_equal "hey you", hash["message"]
|
||||
end
|
||||
|
||||
def test_empty?
|
||||
assert @hash.empty?
|
||||
@hash['zomg'] = 'bears'
|
||||
@@ -75,6 +102,7 @@ module ActionDispatch
|
||||
def test_discard_no_args
|
||||
@hash['hello'] = 'world'
|
||||
@hash.discard
|
||||
|
||||
@hash.sweep
|
||||
assert_equal({}, @hash.to_hash)
|
||||
end
|
||||
@@ -83,8 +111,88 @@ module ActionDispatch
|
||||
@hash['hello'] = 'world'
|
||||
@hash['omg'] = 'world'
|
||||
@hash.discard 'hello'
|
||||
|
||||
@hash.sweep
|
||||
assert_equal({'omg' => 'world'}, @hash.to_hash)
|
||||
end
|
||||
|
||||
def test_keep_sweep
|
||||
@hash['hello'] = 'world'
|
||||
|
||||
@hash.sweep
|
||||
assert_equal({'hello' => 'world'}, @hash.to_hash)
|
||||
end
|
||||
|
||||
def test_update_sweep
|
||||
@hash['hello'] = 'world'
|
||||
@hash.update({'hi' => 'mom'})
|
||||
|
||||
@hash.sweep
|
||||
assert_equal({'hello' => 'world', 'hi' => 'mom'}, @hash.to_hash)
|
||||
end
|
||||
|
||||
def test_update_delete_sweep
|
||||
@hash['hello'] = 'world'
|
||||
@hash.delete 'hello'
|
||||
@hash.update({'hello' => 'mom'})
|
||||
|
||||
@hash.sweep
|
||||
assert_equal({'hello' => 'mom'}, @hash.to_hash)
|
||||
end
|
||||
|
||||
def test_delete_sweep
|
||||
@hash['hello'] = 'world'
|
||||
@hash['hi'] = 'mom'
|
||||
@hash.delete 'hi'
|
||||
|
||||
@hash.sweep
|
||||
assert_equal({'hello' => 'world'}, @hash.to_hash)
|
||||
end
|
||||
|
||||
def test_clear_sweep
|
||||
@hash['hello'] = 'world'
|
||||
@hash.clear
|
||||
|
||||
@hash.sweep
|
||||
assert_equal({}, @hash.to_hash)
|
||||
end
|
||||
|
||||
def test_replace_sweep
|
||||
@hash['hello'] = 'world'
|
||||
@hash.replace({'hi' => 'mom'})
|
||||
|
||||
@hash.sweep
|
||||
assert_equal({'hi' => 'mom'}, @hash.to_hash)
|
||||
end
|
||||
|
||||
def test_discard_then_add
|
||||
@hash['hello'] = 'world'
|
||||
@hash['omg'] = 'world'
|
||||
@hash.discard 'hello'
|
||||
@hash['hello'] = 'world'
|
||||
|
||||
@hash.sweep
|
||||
assert_equal({'omg' => 'world', 'hello' => 'world'}, @hash.to_hash)
|
||||
end
|
||||
|
||||
def test_keep_all_sweep
|
||||
@hash['hello'] = 'world'
|
||||
@hash['omg'] = 'world'
|
||||
@hash.discard 'hello'
|
||||
@hash.keep
|
||||
|
||||
@hash.sweep
|
||||
assert_equal({'omg' => 'world', 'hello' => 'world'}, @hash.to_hash)
|
||||
end
|
||||
|
||||
def test_double_sweep
|
||||
@hash['hello'] = 'world'
|
||||
@hash.sweep
|
||||
|
||||
assert_equal({'hello' => 'world'}, @hash.to_hash)
|
||||
|
||||
@hash.sweep
|
||||
assert_equal({}, @hash.to_hash)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -174,13 +174,13 @@ class FlashTest < ActionController::TestCase
|
||||
|
||||
assert_equal(:foo_indeed, flash.discard(:foo)) # valid key passed
|
||||
assert_nil flash.discard(:unknown) # non existant key passed
|
||||
assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.discard().to_hash) # nothing passed
|
||||
assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.discard(nil).to_hash) # nothing passed
|
||||
assert_equal({"foo" => :foo_indeed, "bar" => :bar_indeed}, flash.discard().to_hash) # nothing passed
|
||||
assert_equal({"foo" => :foo_indeed, "bar" => :bar_indeed}, flash.discard(nil).to_hash) # nothing passed
|
||||
|
||||
assert_equal(:foo_indeed, flash.keep(:foo)) # valid key passed
|
||||
assert_nil flash.keep(:unknown) # non existant key passed
|
||||
assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep().to_hash) # nothing passed
|
||||
assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep(nil).to_hash) # nothing passed
|
||||
assert_equal({"foo" => :foo_indeed, "bar" => :bar_indeed}, flash.keep().to_hash) # nothing passed
|
||||
assert_equal({"foo" => :foo_indeed, "bar" => :bar_indeed}, flash.keep(nil).to_hash) # nothing passed
|
||||
end
|
||||
|
||||
def test_redirect_to_with_alert
|
||||
|
||||
@@ -63,6 +63,11 @@ class CookiesTest < ActionController::TestCase
|
||||
head :ok
|
||||
end
|
||||
|
||||
def set_signed_string_cookie
|
||||
cookies.signed[:foo] = 'bar'
|
||||
head :ok
|
||||
end
|
||||
|
||||
def raise_data_overflow
|
||||
cookies.signed[:foo] = 'bye!' * 1024
|
||||
head :ok
|
||||
@@ -332,6 +337,22 @@ class CookiesTest < ActionController::TestCase
|
||||
}
|
||||
end
|
||||
|
||||
class ActionDispatch::Session::CustomJsonSerializer
|
||||
def self.load(value)
|
||||
JSON.load(value) + " and loaded"
|
||||
end
|
||||
|
||||
def self.dump(value)
|
||||
JSON.dump(value + " was dumped")
|
||||
end
|
||||
end
|
||||
|
||||
def test_signed_cookie_using_serializer_object
|
||||
@request.env["action_dispatch.session_serializer"] = ActionDispatch::Session::CustomJsonSerializer
|
||||
get :set_signed_string_cookie
|
||||
assert_equal 'bar was dumped and loaded', @controller.send(:cookies).signed[:foo]
|
||||
end
|
||||
|
||||
def test_cookie_with_all_domain_option
|
||||
get :set_cookie_with_domain
|
||||
assert_response :success
|
||||
|
||||
@@ -371,7 +371,7 @@ module ActiveRecord
|
||||
begin
|
||||
record.committed!
|
||||
rescue Exception => e
|
||||
record.logger.error(e) if record.respond_to?(:logger) && record.logger
|
||||
handle_commit_exceptions(record, e)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -385,6 +385,11 @@ module ActiveRecord
|
||||
row = result.rows.first
|
||||
row && row.first
|
||||
end
|
||||
|
||||
# Handle any exceptions caught trying to send the commit message to a record
|
||||
def handle_commit_exceptions(record, e)
|
||||
record.logger.error(e) if record.respond_to?(:logger) && record.logger
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -278,7 +278,7 @@ module ActiveRecord
|
||||
|
||||
# Call the after_commit callbacks
|
||||
def committed! #:nodoc:
|
||||
run_callbacks :commit
|
||||
run_callbacks :commit if destroyed? || persisted?
|
||||
ensure
|
||||
@_start_transaction_state.clear
|
||||
end
|
||||
|
||||
@@ -181,7 +181,8 @@ module Rails
|
||||
"action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions,
|
||||
"action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local,
|
||||
"action_dispatch.logger" => Rails.logger,
|
||||
"action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner
|
||||
"action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner,
|
||||
"action_dispatch.session_serializer" => config.session_options[:serializer],
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user