actionpack 3.0.20 → 3.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (161) hide show
  1. data/CHANGELOG +88 -142
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +5 -6
  4. data/lib/abstract_controller.rb +1 -0
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +24 -19
  7. data/lib/abstract_controller/callbacks.rb +19 -19
  8. data/lib/abstract_controller/helpers.rb +11 -13
  9. data/lib/abstract_controller/layouts.rb +4 -5
  10. data/lib/abstract_controller/railties/routes_helpers.rb +18 -0
  11. data/lib/abstract_controller/rendering.rb +34 -31
  12. data/lib/abstract_controller/url_for.rb +27 -0
  13. data/lib/abstract_controller/view_paths.rb +31 -6
  14. data/lib/action_controller.rb +5 -3
  15. data/lib/action_controller/base.rb +15 -16
  16. data/lib/action_controller/caching.rb +2 -2
  17. data/lib/action_controller/caching/actions.rb +11 -12
  18. data/lib/action_controller/caching/fragments.rb +41 -19
  19. data/lib/action_controller/caching/pages.rb +3 -9
  20. data/lib/action_controller/caching/sweeping.rb +0 -1
  21. data/lib/action_controller/deprecated.rb +1 -1
  22. data/lib/action_controller/log_subscriber.rb +1 -1
  23. data/lib/action_controller/metal.rb +78 -20
  24. data/lib/action_controller/metal/compatibility.rb +0 -9
  25. data/lib/action_controller/metal/conditional_get.rb +9 -9
  26. data/lib/action_controller/metal/data_streaming.rb +145 -0
  27. data/lib/action_controller/metal/force_ssl.rb +35 -0
  28. data/lib/action_controller/metal/head.rb +1 -1
  29. data/lib/action_controller/metal/helpers.rb +37 -44
  30. data/lib/action_controller/metal/hide_actions.rb +2 -3
  31. data/lib/action_controller/metal/http_authentication.rb +41 -38
  32. data/lib/action_controller/metal/implicit_render.rb +13 -13
  33. data/lib/action_controller/metal/instrumentation.rb +2 -2
  34. data/lib/action_controller/metal/mime_responds.rb +25 -19
  35. data/lib/action_controller/metal/params_wrapper.rb +224 -0
  36. data/lib/action_controller/metal/redirecting.rb +6 -2
  37. data/lib/action_controller/metal/renderers.rb +50 -36
  38. data/lib/action_controller/metal/rendering.rb +34 -25
  39. data/lib/action_controller/metal/request_forgery_protection.rb +18 -36
  40. data/lib/action_controller/metal/responder.rb +47 -12
  41. data/lib/action_controller/metal/streaming.rb +244 -138
  42. data/lib/action_controller/metal/testing.rb +0 -9
  43. data/lib/action_controller/metal/url_for.rb +12 -14
  44. data/lib/action_controller/railtie.rb +19 -37
  45. data/lib/action_controller/railties/paths.rb +24 -0
  46. data/lib/action_controller/record_identifier.rb +4 -10
  47. data/lib/action_controller/test_case.rb +36 -19
  48. data/lib/action_controller/vendor/html-scanner/html/node.rb +5 -5
  49. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +3 -3
  50. data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -0
  51. data/lib/action_dispatch.rb +4 -1
  52. data/lib/action_dispatch/http/cache.rb +5 -32
  53. data/lib/action_dispatch/http/filter_parameters.rb +3 -1
  54. data/lib/action_dispatch/http/mime_negotiation.rb +22 -3
  55. data/lib/action_dispatch/http/mime_type.rb +45 -5
  56. data/lib/action_dispatch/http/rack_cache.rb +58 -0
  57. data/lib/action_dispatch/http/request.rb +27 -41
  58. data/lib/action_dispatch/http/response.rb +56 -54
  59. data/lib/action_dispatch/http/upload.rb +1 -11
  60. data/lib/action_dispatch/http/url.rb +102 -42
  61. data/lib/action_dispatch/middleware/callbacks.rb +8 -25
  62. data/lib/action_dispatch/middleware/closed_error.rb +7 -0
  63. data/lib/action_dispatch/middleware/cookies.rb +37 -15
  64. data/lib/action_dispatch/middleware/flash.rb +80 -11
  65. data/lib/action_dispatch/middleware/params_parser.rb +2 -2
  66. data/lib/action_dispatch/middleware/reloader.rb +76 -0
  67. data/lib/action_dispatch/middleware/session/abstract_store.rb +56 -226
  68. data/lib/action_dispatch/middleware/session/cookie_store.rb +20 -44
  69. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -46
  70. data/lib/action_dispatch/middleware/show_exceptions.rb +15 -2
  71. data/lib/action_dispatch/middleware/stack.rb +50 -17
  72. data/lib/action_dispatch/middleware/static.rb +41 -29
  73. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +3 -3
  74. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
  75. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +3 -3
  76. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -2
  77. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +2 -6
  78. data/lib/action_dispatch/railtie.rb +8 -0
  79. data/lib/action_dispatch/routing.rb +13 -1
  80. data/lib/action_dispatch/routing/mapper.rb +345 -227
  81. data/lib/action_dispatch/routing/polymorphic_routes.rb +33 -13
  82. data/lib/action_dispatch/routing/redirection.rb +110 -0
  83. data/lib/action_dispatch/routing/route.rb +15 -13
  84. data/lib/action_dispatch/routing/route_set.rb +116 -90
  85. data/lib/action_dispatch/routing/routes_proxy.rb +35 -0
  86. data/lib/action_dispatch/routing/url_for.rb +25 -1
  87. data/lib/action_dispatch/testing/assertions/response.rb +8 -10
  88. data/lib/action_dispatch/testing/assertions/routing.rb +15 -15
  89. data/lib/action_dispatch/testing/assertions/selector.rb +13 -220
  90. data/lib/action_dispatch/testing/integration.rb +37 -28
  91. data/lib/action_dispatch/testing/performance_test.rb +1 -3
  92. data/lib/action_dispatch/testing/test_process.rb +1 -1
  93. data/lib/action_dispatch/testing/test_request.rb +9 -3
  94. data/lib/action_dispatch/testing/test_response.rb +4 -111
  95. data/lib/action_pack.rb +1 -1
  96. data/lib/action_pack/version.rb +3 -3
  97. data/lib/action_view.rb +39 -24
  98. data/lib/action_view/base.rb +61 -86
  99. data/lib/action_view/buffers.rb +43 -0
  100. data/lib/action_view/context.rb +21 -24
  101. data/lib/action_view/flows.rb +79 -0
  102. data/lib/action_view/helpers.rb +8 -6
  103. data/lib/action_view/helpers/active_model_helper.rb +0 -23
  104. data/lib/action_view/helpers/asset_paths.rb +79 -0
  105. data/lib/action_view/helpers/asset_tag_helper.rb +30 -500
  106. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +147 -0
  107. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +101 -0
  108. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +200 -0
  109. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +152 -0
  110. data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
  111. data/lib/action_view/helpers/cache_helper.rb +11 -19
  112. data/lib/action_view/helpers/capture_helper.rb +19 -8
  113. data/lib/action_view/helpers/controller_helper.rb +21 -0
  114. data/lib/action_view/helpers/csrf_helper.rb +22 -4
  115. data/lib/action_view/helpers/date_helper.rb +36 -22
  116. data/lib/action_view/helpers/form_helper.rb +199 -113
  117. data/lib/action_view/helpers/form_options_helper.rb +10 -11
  118. data/lib/action_view/helpers/form_tag_helper.rb +94 -22
  119. data/lib/action_view/helpers/javascript_helper.rb +24 -107
  120. data/lib/action_view/helpers/number_helper.rb +36 -33
  121. data/lib/action_view/helpers/output_safety_helper.rb +38 -0
  122. data/lib/action_view/helpers/record_tag_helper.rb +6 -6
  123. data/lib/action_view/helpers/rendering_helper.rb +90 -0
  124. data/lib/action_view/helpers/sanitize_helper.rb +2 -2
  125. data/lib/action_view/helpers/sprockets_helper.rb +69 -0
  126. data/lib/action_view/helpers/tag_helper.rb +34 -12
  127. data/lib/action_view/helpers/text_helper.rb +30 -145
  128. data/lib/action_view/helpers/translation_helper.rb +10 -17
  129. data/lib/action_view/helpers/url_helper.rb +70 -67
  130. data/lib/action_view/locale/en.yml +1 -1
  131. data/lib/action_view/lookup_context.rb +36 -14
  132. data/lib/action_view/{paths.rb → path_set.rb} +9 -8
  133. data/lib/action_view/railtie.rb +12 -4
  134. data/lib/action_view/renderer/abstract_renderer.rb +36 -0
  135. data/lib/action_view/{render/partials.rb → renderer/partial_renderer.rb} +147 -146
  136. data/lib/action_view/renderer/renderer.rb +54 -0
  137. data/lib/action_view/renderer/streaming_template_renderer.rb +106 -0
  138. data/lib/action_view/renderer/template_renderer.rb +74 -0
  139. data/lib/action_view/template.rb +91 -54
  140. data/lib/action_view/template/error.rb +11 -8
  141. data/lib/action_view/template/handler.rb +9 -1
  142. data/lib/action_view/template/handlers.rb +9 -9
  143. data/lib/action_view/template/handlers/builder.rb +4 -4
  144. data/lib/action_view/template/handlers/erb.rb +21 -41
  145. data/lib/action_view/template/resolver.rb +171 -57
  146. data/lib/action_view/template/text.rb +0 -4
  147. data/lib/action_view/test_case.rb +32 -16
  148. data/lib/action_view/testing/resolvers.rb +16 -10
  149. data/lib/sprockets/railtie.rb +100 -0
  150. metadata +162 -140
  151. checksums.yaml +0 -7
  152. data/lib/action_controller/deprecated/base.rb +0 -143
  153. data/lib/action_controller/deprecated/dispatcher.rb +0 -28
  154. data/lib/action_controller/deprecated/url_writer.rb +0 -14
  155. data/lib/action_dispatch/routing/deprecated_mapper.rb +0 -525
  156. data/lib/action_view/helpers/prototype_helper.rb +0 -851
  157. data/lib/action_view/helpers/raw_output_helper.rb +0 -18
  158. data/lib/action_view/helpers/scriptaculous_helper.rb +0 -263
  159. data/lib/action_view/render/layouts.rb +0 -83
  160. data/lib/action_view/render/rendering.rb +0 -67
  161. data/lib/action_view/template/handlers/rjs.rb +0 -17
@@ -4,7 +4,7 @@ module ActionDispatch
4
4
  attr_accessor :original_filename, :content_type, :tempfile, :headers
5
5
 
6
6
  def initialize(hash)
7
- @original_filename = encode_filename(hash[:filename])
7
+ @original_filename = hash[:filename]
8
8
  @content_type = hash[:type]
9
9
  @headers = hash[:head]
10
10
  @tempfile = hash[:tempfile]
@@ -30,16 +30,6 @@ module ActionDispatch
30
30
  def size
31
31
  @tempfile.size
32
32
  end
33
-
34
- private
35
- def encode_filename(filename)
36
- # Encode the filename in the utf8 encoding, unless it is nil or we're in 1.8
37
- if "ruby".encoding_aware? && filename
38
- filename.force_encoding("UTF-8").encode!
39
- else
40
- filename
41
- end
42
- end
43
33
  end
44
34
 
45
35
  module Upload
@@ -1,24 +1,89 @@
1
1
  module ActionDispatch
2
2
  module Http
3
3
  module URL
4
- # Returns the complete \URL used for this request.
5
- def url
6
- protocol + host_with_port + fullpath
4
+ mattr_accessor :tld_length
5
+ self.tld_length = 1
6
+
7
+ class << self
8
+ def extract_domain(host, tld_length = @@tld_length)
9
+ return nil unless named_host?(host)
10
+ host.split('.').last(1 + tld_length).join('.')
11
+ end
12
+
13
+ def extract_subdomains(host, tld_length = @@tld_length)
14
+ return [] unless named_host?(host)
15
+ parts = host.split('.')
16
+ parts[0..-(tld_length+2)]
17
+ end
18
+
19
+ def extract_subdomain(host, tld_length = @@tld_length)
20
+ extract_subdomains(host, tld_length).join('.')
21
+ end
22
+
23
+ def url_for(options = {})
24
+ unless options[:host].present? || options[:only_path].present?
25
+ raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
26
+ end
27
+
28
+ rewritten_url = ""
29
+
30
+ unless options[:only_path]
31
+ unless options[:protocol] == false
32
+ rewritten_url << (options[:protocol] || "http")
33
+ rewritten_url << ":" unless rewritten_url.match(%r{:|//})
34
+ end
35
+ rewritten_url << "//" unless rewritten_url.match("//")
36
+ rewritten_url << rewrite_authentication(options)
37
+ rewritten_url << host_or_subdomain_and_domain(options)
38
+ rewritten_url << ":#{options.delete(:port)}" if options[:port]
39
+ end
40
+
41
+ path = options.delete(:path) || ''
42
+
43
+ params = options[:params] || {}
44
+ params.reject! {|k,v| v.to_param.nil? }
45
+
46
+ rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path)
47
+ rewritten_url << "?#{params.to_query}" unless params.empty?
48
+ rewritten_url << "##{Rack::Mount::Utils.escape_uri(options[:anchor].to_param.to_s)}" if options[:anchor]
49
+ rewritten_url
50
+ end
51
+
52
+ private
53
+
54
+ def named_host?(host)
55
+ !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
56
+ end
57
+
58
+ def rewrite_authentication(options)
59
+ if options[:user] && options[:password]
60
+ "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
61
+ else
62
+ ""
63
+ end
64
+ end
65
+
66
+ def host_or_subdomain_and_domain(options)
67
+ return options[:host] unless options[:subdomain] || options[:domain]
68
+
69
+ tld_length = options[:tld_length] || @@tld_length
70
+
71
+ host = ""
72
+ host << (options[:subdomain] || extract_subdomain(options[:host], tld_length))
73
+ host << "."
74
+ host << (options[:domain] || extract_domain(options[:host], tld_length))
75
+ host
76
+ end
7
77
  end
8
78
 
9
- # Returns 'https' if this is an SSL request and 'http' otherwise.
10
- def scheme
11
- ssl? ? 'https' : 'http'
79
+ # Returns the complete URL used for this request.
80
+ def url
81
+ protocol + host_with_port + fullpath
12
82
  end
13
83
 
14
84
  # Returns 'https://' if this is an SSL request and 'http://' otherwise.
15
85
  def protocol
16
- ssl? ? 'https://' : 'http://'
17
- end
18
-
19
- # Is this an SSL request?
20
- def ssl?
21
- @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
86
+ @protocol ||= ssl? ? 'https://' : 'http://'
22
87
  end
23
88
 
24
89
  # Returns the \host for this request, such as "example.com".
@@ -43,10 +108,12 @@ module ActionDispatch
43
108
 
44
109
  # Returns the port number of this request as an integer.
45
110
  def port
46
- if raw_host_with_port =~ /:(\d+)$/
47
- $1.to_i
48
- else
49
- standard_port
111
+ @port ||= begin
112
+ if raw_host_with_port =~ /:(\d+)$/
113
+ $1.to_i
114
+ else
115
+ standard_port
116
+ end
50
117
  end
51
118
  end
52
119
 
@@ -63,10 +130,16 @@ module ActionDispatch
63
130
  port == standard_port
64
131
  end
65
132
 
66
- # Returns a \port suffix like ":8080" if the \port number of this request
133
+ # Returns a number \port suffix like 8080 if the \port number of this request
67
134
  # is not the default HTTP \port 80 or HTTPS \port 443.
135
+ def optional_port
136
+ standard_port? ? nil : port
137
+ end
138
+
139
+ # Returns a string \port suffix, including colon, like ":8080" if the \port
140
+ # number of this request is not the default HTTP \port 80 or HTTPS \port 443.
68
141
  def port_string
69
- port == standard_port ? '' : ":#{port}"
142
+ standard_port? ? '' : ":#{port}"
70
143
  end
71
144
 
72
145
  def server_port
@@ -75,38 +148,25 @@ module ActionDispatch
75
148
 
76
149
  # Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
77
150
  # a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
78
- def domain(tld_length = 1)
79
- return nil unless named_host?(host)
80
-
81
- host.split('.').last(1 + tld_length).join('.')
151
+ def domain(tld_length = @@tld_length)
152
+ ActionDispatch::Http::URL.extract_domain(host, tld_length)
82
153
  end
83
154
 
84
155
  # Returns all the \subdomains as an array, so <tt>["dev", "www"]</tt> would be
85
156
  # returned for "dev.www.rubyonrails.org". You can specify a different <tt>tld_length</tt>,
86
157
  # such as 2 to catch <tt>["www"]</tt> instead of <tt>["www", "rubyonrails"]</tt>
87
158
  # in "www.rubyonrails.co.uk".
88
- def subdomains(tld_length = 1)
89
- return [] unless named_host?(host)
90
- parts = host.split('.')
91
- parts[0..-(tld_length+2)]
92
- end
93
-
94
- def subdomain(tld_length = 1)
95
- subdomains(tld_length).join('.')
96
- end
97
-
98
- # Returns the request URI, accounting for server idiosyncrasies.
99
- # WEBrick includes the full \URL. IIS leaves REQUEST_URI blank.
100
- def request_uri
101
- ActiveSupport::Deprecation.warn "Using #request_uri is deprecated. Use fullpath instead.", caller
102
- fullpath
159
+ def subdomains(tld_length = @@tld_length)
160
+ ActionDispatch::Http::URL.extract_subdomains(host, tld_length)
103
161
  end
104
162
 
105
- private
106
-
107
- def named_host?(host)
108
- !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
163
+ # Returns all the \subdomains as a string, so <tt>"dev.www"</tt> would be
164
+ # returned for "dev.www.rubyonrails.org". You can specify a different <tt>tld_length</tt>,
165
+ # such as 2 to catch <tt>["www"]</tt> instead of <tt>"www.rubyonrails"</tt>
166
+ # in "www.rubyonrails.co.uk".
167
+ def subdomain(tld_length = @@tld_length)
168
+ subdomains(tld_length).join(".")
109
169
  end
110
170
  end
111
171
  end
112
- end
172
+ end
@@ -1,30 +1,14 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
1
3
  module ActionDispatch
2
4
  # Provide callbacks to be executed before and after the request dispatch.
3
- #
4
- # It also provides a to_prepare callback, which is performed in all requests
5
- # in development by only once in production and notification callback for async
6
- # operations.
7
- #
8
5
  class Callbacks
9
6
  include ActiveSupport::Callbacks
10
7
 
11
8
  define_callbacks :call, :rescuable => true
12
- define_callbacks :prepare, :scope => :name
13
9
 
14
- # Add a preparation callback. Preparation callbacks are run before every
15
- # request in development mode, and before the first request in production mode.
16
- #
17
- # If a symbol with a block is given, the symbol is used as an identifier.
18
- # That allows to_prepare to be called again with the same identifier to
19
- # replace the existing callback. Passing an identifier is a suggested
20
- # practice if the code adding a preparation block may be reloaded.
21
- def self.to_prepare(*args, &block)
22
- if args.first.is_a?(Symbol) && block_given?
23
- define_method :"__#{args.first}", &block
24
- set_callback(:prepare, :"__#{args.first}")
25
- else
26
- set_callback(:prepare, *args, &block)
27
- end
10
+ class << self
11
+ delegate :to_prepare, :to_cleanup, :to => "ActionDispatch::Reloader"
28
12
  end
29
13
 
30
14
  def self.before(*args, &block)
@@ -35,14 +19,13 @@ module ActionDispatch
35
19
  set_callback(:call, :after, *args, &block)
36
20
  end
37
21
 
38
- def initialize(app, prepare_each_request = false)
39
- @app, @prepare_each_request = app, prepare_each_request
40
- _run_prepare_callbacks
22
+ def initialize(app, unused = nil)
23
+ ActiveSupport::Deprecation.warn "Passing a second argument to ActionDispatch::Callbacks.new is deprecated." unless unused.nil?
24
+ @app = app
41
25
  end
42
26
 
43
27
  def call(env)
44
- _run_call_callbacks do
45
- _run_prepare_callbacks if @prepare_each_request
28
+ run_callbacks :call do
46
29
  @app.call(env)
47
30
  end
48
31
  end
@@ -0,0 +1,7 @@
1
+ module ActionDispatch
2
+ class ClosedError < StandardError #:nodoc:
3
+ def initialize(kind)
4
+ super "Cannot modify #{kind} because it was closed. This means it was already streamed back to the client or converted to HTTP headers."
5
+ end
6
+ end
7
+ end
@@ -83,24 +83,21 @@ module ActionDispatch
83
83
  # Raised when storing more than 4K of session data.
84
84
  class CookieOverflow < StandardError; end
85
85
 
86
- class CookieJar < Hash #:nodoc:
86
+ class CookieJar #:nodoc:
87
87
 
88
88
  # This regular expression is used to split the levels of a domain.
89
89
  # The top level domain can be any string without a period or
90
90
  # **.**, ***.** style TLDs like co.uk or com.au
91
91
  #
92
92
  # www.example.co.uk gives:
93
- # $1 => example
94
- # $2 => co.uk
93
+ # $& => example.co.uk
95
94
  #
96
95
  # example.com gives:
97
- # $1 => example
98
- # $2 => com
96
+ # $& => example.com
99
97
  #
100
98
  # lots.of.subdomains.example.local gives:
101
- # $1 => example
102
- # $2 => local
103
- DOMAIN_REGEXP = /([^.]*)\.([^.]*|..\...|...\...)$/
99
+ # $& => example.local
100
+ DOMAIN_REGEXP = /[^.]*\.([^.]*|..\...|...\...)$/
104
101
 
105
102
  def self.build(request)
106
103
  secret = request.env[TOKEN_KEY]
@@ -118,27 +115,46 @@ module ActionDispatch
118
115
  @delete_cookies = {}
119
116
  @host = host
120
117
  @secure = secure
121
-
122
- super()
118
+ @closed = false
119
+ @cookies = {}
123
120
  end
124
121
 
122
+ attr_reader :closed
123
+ alias :closed? :closed
124
+ def close!; @closed = true end
125
+
125
126
  # Returns the value of the cookie by +name+, or +nil+ if no such cookie exists.
126
127
  def [](name)
127
- super(name.to_s)
128
+ @cookies[name.to_s]
129
+ end
130
+
131
+ def update(other_hash)
132
+ @cookies.update other_hash
133
+ self
128
134
  end
129
135
 
130
136
  def handle_options(options) #:nodoc:
131
137
  options[:path] ||= "/"
132
138
 
133
139
  if options[:domain] == :all
134
- @host =~ DOMAIN_REGEXP
135
- options[:domain] = ".#{$1}.#{$2}"
140
+ # if there is a provided tld length then we use it otherwise default domain regexp
141
+ domain_regexp = options[:tld_length] ? /([^.]+\.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP
142
+
143
+ # if host is not ip and matches domain regexp
144
+ # (ip confirms to domain regexp so we explicitly check for ip)
145
+ options[:domain] = if (@host !~ /^[\d.]+$/) && (@host =~ domain_regexp)
146
+ ".#{$&}"
147
+ end
148
+ elsif options[:domain].is_a? Array
149
+ # if host matches one of the supplied domains without a dot in front of it
150
+ options[:domain] = options[:domain].find {|domain| @host.include? domain[/^\.?(.*)$/, 1] }
136
151
  end
137
152
  end
138
153
 
139
154
  # Sets the cookie named +name+. The second argument may be the very cookie
140
155
  # value, or a hash of options as documented above.
141
156
  def []=(key, options)
157
+ raise ClosedError, :cookies if closed?
142
158
  if options.is_a?(Hash)
143
159
  options.symbolize_keys!
144
160
  value = options[:value]
@@ -147,7 +163,7 @@ module ActionDispatch
147
163
  options = { :value => value }
148
164
  end
149
165
 
150
- value = super(key.to_s, value)
166
+ value = @cookies[key.to_s] = value
151
167
 
152
168
  handle_options(options)
153
169
 
@@ -164,7 +180,7 @@ module ActionDispatch
164
180
 
165
181
  handle_options(options)
166
182
 
167
- value = super(key.to_s)
183
+ value = @cookies.delete(key.to_s)
168
184
  @delete_cookies[key] = options
169
185
  value
170
186
  end
@@ -219,6 +235,7 @@ module ActionDispatch
219
235
  end
220
236
 
221
237
  def []=(key, options)
238
+ raise ClosedError, :cookies if closed?
222
239
  if options.is_a?(Hash)
223
240
  options.symbolize_keys!
224
241
  else
@@ -257,6 +274,7 @@ module ActionDispatch
257
274
  end
258
275
 
259
276
  def []=(key, options)
277
+ raise ClosedError, :cookies if closed?
260
278
  if options.is_a?(Hash)
261
279
  options.symbolize_keys!
262
280
  options[:value] = @verifier.generate(options[:value])
@@ -299,6 +317,7 @@ module ActionDispatch
299
317
  end
300
318
 
301
319
  def call(env)
320
+ cookie_jar = nil
302
321
  status, headers, body = @app.call(env)
303
322
 
304
323
  if cookie_jar = env['action_dispatch.cookies']
@@ -309,6 +328,9 @@ module ActionDispatch
309
328
  end
310
329
 
311
330
  [status, headers, body]
331
+ ensure
332
+ cookie_jar = ActionDispatch::Request.new(env).cookie_jar unless cookie_jar
333
+ cookie_jar.close!
312
334
  end
313
335
  end
314
336
  end
@@ -4,7 +4,7 @@ module ActionDispatch
4
4
  # read a notice you put there or <tt>flash["notice"] = "hello"</tt>
5
5
  # to put a new one.
6
6
  def flash
7
- @env['action_dispatch.request.flash_hash'] ||= (session["flash"] || Flash::FlashHash.new)
7
+ @env[Flash::KEY] ||= (session["flash"] || Flash::FlashHash.new)
8
8
  end
9
9
  end
10
10
 
@@ -40,7 +40,11 @@ module ActionDispatch
40
40
  #
41
41
  # See docs on the FlashHash class for more details about the flash.
42
42
  class Flash
43
+ KEY = 'action_dispatch.request.flash_hash'.freeze
44
+
43
45
  class FlashNow #:nodoc:
46
+ attr_accessor :flash
47
+
44
48
  def initialize(flash)
45
49
  @flash = flash
46
50
  end
@@ -66,27 +70,75 @@ module ActionDispatch
66
70
  end
67
71
  end
68
72
 
69
- class FlashHash < Hash
73
+ class FlashHash
74
+ include Enumerable
75
+
70
76
  def initialize #:nodoc:
77
+ @used = Set.new
78
+ @closed = false
79
+ @flashes = {}
80
+ @now = nil
81
+ end
82
+
83
+ def initialize_copy(other)
84
+ if other.now_is_loaded?
85
+ @now = other.now.dup
86
+ @now.flash = self
87
+ end
71
88
  super
72
- @used = Set.new
73
89
  end
74
90
 
75
91
  def []=(k, v) #:nodoc:
92
+ raise ClosedError, :flash if closed?
76
93
  keep(k)
77
- super
94
+ @flashes[k] = v
95
+ end
96
+
97
+ def [](k)
98
+ @flashes[k]
78
99
  end
79
100
 
80
101
  def update(h) #:nodoc:
81
102
  h.keys.each { |k| keep(k) }
82
- super
103
+ @flashes.update h
104
+ self
105
+ end
106
+
107
+ def keys
108
+ @flashes.keys
109
+ end
110
+
111
+ def key?(name)
112
+ @flashes.key? name
113
+ end
114
+
115
+ def delete(key)
116
+ @flashes.delete key
117
+ self
118
+ end
119
+
120
+ def to_hash
121
+ @flashes.dup
122
+ end
123
+
124
+ def empty?
125
+ @flashes.empty?
126
+ end
127
+
128
+ def clear
129
+ @flashes.clear
130
+ end
131
+
132
+ def each(&block)
133
+ @flashes.each(&block)
83
134
  end
84
135
 
85
136
  alias :merge! :update
86
137
 
87
138
  def replace(h) #:nodoc:
88
139
  @used = Set.new
89
- super
140
+ @flashes.replace h
141
+ self
90
142
  end
91
143
 
92
144
  # Sets a flash that will not be available to the next action, only to the current.
@@ -100,9 +152,13 @@ module ActionDispatch
100
152
  #
101
153
  # Entries set via <tt>now</tt> are accessed the same way as standard entries: <tt>flash['my-key']</tt>.
102
154
  def now
103
- FlashNow.new(self)
155
+ @now ||= FlashNow.new(self)
104
156
  end
105
157
 
158
+ attr_reader :closed
159
+ alias :closed? :closed
160
+ def close!; @closed = true; end
161
+
106
162
  # Keeps either the entire current flash or a specific flash entry available for the next action:
107
163
  #
108
164
  # flash.keep # keeps the entire flash
@@ -156,7 +212,12 @@ module ActionDispatch
156
212
  self[:notice] = message
157
213
  end
158
214
 
159
- private
215
+ protected
216
+
217
+ def now_is_loaded?
218
+ !!@now
219
+ end
220
+
160
221
  # Used internally by the <tt>keep</tt> and <tt>discard</tt> methods
161
222
  # use() # marks the entire flash as used
162
223
  # use('msg') # marks the "msg" entry as used
@@ -182,10 +243,18 @@ module ActionDispatch
182
243
  @app.call(env)
183
244
  ensure
184
245
  session = env['rack.session'] || {}
185
- flash_hash = env['action_dispatch.request.flash_hash']
246
+ flash_hash = env[KEY]
247
+
248
+ if flash_hash
249
+ if !flash_hash.empty? || session.key?('flash')
250
+ session["flash"] = flash_hash
251
+ new_hash = flash_hash.dup
252
+ else
253
+ new_hash = flash_hash
254
+ end
186
255
 
187
- if flash_hash && (!flash_hash.empty? || session.key?('flash'))
188
- session["flash"] = flash_hash
256
+ env[KEY] = new_hash
257
+ new_hash.close!
189
258
  end
190
259
 
191
260
  if session.key?('flash') && session['flash'].empty?