actionpack 3.1.12 → 3.2.0.rc1

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 (128) hide show
  1. data/CHANGELOG.md +5503 -108
  2. data/README.rdoc +3 -3
  3. data/lib/abstract_controller/asset_paths.rb +1 -1
  4. data/lib/abstract_controller/base.rb +1 -1
  5. data/lib/abstract_controller/callbacks.rb +102 -18
  6. data/lib/abstract_controller/helpers.rb +1 -1
  7. data/lib/abstract_controller/layouts.rb +116 -50
  8. data/lib/abstract_controller/logger.rb +1 -1
  9. data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
  10. data/lib/abstract_controller/rendering.rb +1 -6
  11. data/lib/abstract_controller/view_paths.rb +6 -5
  12. data/lib/action_controller.rb +0 -15
  13. data/lib/action_controller/caching.rb +0 -1
  14. data/lib/action_controller/caching/actions.rb +5 -6
  15. data/lib/action_controller/caching/fragments.rb +18 -18
  16. data/lib/action_controller/caching/pages.rb +7 -6
  17. data/lib/action_controller/caching/sweeping.rb +1 -1
  18. data/lib/action_controller/log_subscriber.rb +8 -4
  19. data/lib/action_controller/metal.rb +7 -1
  20. data/lib/action_controller/metal/conditional_get.rb +49 -4
  21. data/lib/action_controller/metal/data_streaming.rb +17 -5
  22. data/lib/action_controller/metal/force_ssl.rb +8 -5
  23. data/lib/action_controller/metal/helpers.rb +7 -4
  24. data/lib/action_controller/metal/http_authentication.rb +9 -12
  25. data/lib/action_controller/metal/instrumentation.rb +9 -4
  26. data/lib/action_controller/metal/mime_responds.rb +4 -4
  27. data/lib/action_controller/metal/params_wrapper.rb +12 -8
  28. data/lib/action_controller/metal/redirecting.rb +7 -6
  29. data/lib/action_controller/metal/renderers.rb +9 -11
  30. data/lib/action_controller/metal/request_forgery_protection.rb +2 -1
  31. data/lib/action_controller/metal/rescue.rb +13 -0
  32. data/lib/action_controller/metal/responder.rb +11 -23
  33. data/lib/action_controller/metal/streaming.rb +0 -25
  34. data/lib/action_controller/railtie.rb +1 -0
  35. data/lib/action_controller/railties/paths.rb +4 -3
  36. data/lib/action_controller/record_identifier.rb +4 -4
  37. data/lib/action_controller/test_case.rb +60 -56
  38. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +6 -6
  39. data/lib/action_dispatch.rb +5 -1
  40. data/lib/action_dispatch/http/cache.rb +27 -15
  41. data/lib/action_dispatch/http/filter_parameters.rb +3 -1
  42. data/lib/action_dispatch/http/headers.rb +3 -5
  43. data/lib/action_dispatch/http/mime_negotiation.rb +2 -1
  44. data/lib/action_dispatch/http/mime_type.rb +7 -3
  45. data/lib/action_dispatch/http/mime_types.rb +12 -0
  46. data/lib/action_dispatch/http/parameter_filter.rb +3 -1
  47. data/lib/action_dispatch/http/parameters.rb +0 -4
  48. data/lib/action_dispatch/http/request.rb +18 -68
  49. data/lib/action_dispatch/http/response.rb +11 -32
  50. data/lib/action_dispatch/http/upload.rb +3 -14
  51. data/lib/action_dispatch/http/url.rb +1 -1
  52. data/lib/action_dispatch/middleware/callbacks.rb +1 -2
  53. data/lib/action_dispatch/middleware/cookies.rb +20 -16
  54. data/lib/action_dispatch/middleware/debug_exceptions.rb +82 -0
  55. data/lib/action_dispatch/middleware/exception_wrapper.rb +78 -0
  56. data/lib/action_dispatch/middleware/flash.rb +6 -9
  57. data/lib/action_dispatch/middleware/params_parser.rb +6 -11
  58. data/lib/action_dispatch/middleware/public_exceptions.rb +30 -0
  59. data/lib/action_dispatch/middleware/reloader.rb +38 -14
  60. data/lib/action_dispatch/middleware/remote_ip.rb +66 -36
  61. data/lib/action_dispatch/middleware/request_id.rb +39 -0
  62. data/lib/action_dispatch/middleware/session/abstract_store.rb +4 -16
  63. data/lib/action_dispatch/middleware/session/cache_store.rb +50 -0
  64. data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
  65. data/lib/action_dispatch/middleware/show_exceptions.rb +58 -142
  66. data/lib/action_dispatch/middleware/static.rb +2 -10
  67. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
  68. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +13 -8
  69. data/lib/action_dispatch/railtie.rb +15 -1
  70. data/lib/action_dispatch/routing.rb +1 -2
  71. data/lib/action_dispatch/routing/mapper.rb +108 -107
  72. data/lib/action_dispatch/routing/redirection.rb +63 -69
  73. data/lib/action_dispatch/routing/route_set.rb +75 -43
  74. data/lib/action_dispatch/routing/routes_proxy.rb +0 -4
  75. data/lib/action_dispatch/routing/url_for.rb +3 -3
  76. data/lib/action_dispatch/testing/assertions/response.rb +5 -7
  77. data/lib/action_dispatch/testing/assertions/routing.rb +10 -9
  78. data/lib/action_dispatch/testing/integration.rb +8 -25
  79. data/lib/action_dispatch/testing/test_process.rb +3 -2
  80. data/lib/action_dispatch/testing/test_request.rb +4 -23
  81. data/lib/action_pack/version.rb +3 -3
  82. data/lib/action_view.rb +1 -5
  83. data/lib/action_view/asset_paths.rb +7 -8
  84. data/lib/action_view/base.rb +7 -5
  85. data/lib/action_view/helpers/asset_paths.rb +1 -1
  86. data/lib/action_view/helpers/asset_tag_helper.rb +4 -8
  87. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +3 -0
  88. data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
  89. data/lib/action_view/helpers/capture_helper.rb +3 -3
  90. data/lib/action_view/helpers/controller_helper.rb +1 -1
  91. data/lib/action_view/helpers/date_helper.rb +26 -18
  92. data/lib/action_view/helpers/debug_helper.rb +1 -1
  93. data/lib/action_view/helpers/form_helper.rb +71 -13
  94. data/lib/action_view/helpers/form_options_helper.rb +65 -34
  95. data/lib/action_view/helpers/form_tag_helper.rb +24 -18
  96. data/lib/action_view/helpers/javascript_helper.rb +12 -3
  97. data/lib/action_view/helpers/number_helper.rb +3 -2
  98. data/lib/action_view/helpers/record_tag_helper.rb +51 -5
  99. data/lib/action_view/helpers/rendering_helper.rb +2 -2
  100. data/lib/action_view/helpers/sanitize_helper.rb +6 -7
  101. data/lib/action_view/helpers/tag_helper.rb +1 -1
  102. data/lib/action_view/helpers/text_helper.rb +5 -4
  103. data/lib/action_view/helpers/url_helper.rb +19 -11
  104. data/lib/action_view/locale/en.yml +6 -0
  105. data/lib/action_view/log_subscriber.rb +1 -1
  106. data/lib/action_view/lookup_context.rb +123 -125
  107. data/lib/action_view/path_set.rb +60 -13
  108. data/lib/action_view/renderer/abstract_renderer.rb +16 -11
  109. data/lib/action_view/renderer/partial_renderer.rb +59 -40
  110. data/lib/action_view/renderer/template_renderer.rb +29 -17
  111. data/lib/action_view/template.rb +0 -1
  112. data/lib/action_view/template/error.rb +6 -5
  113. data/lib/action_view/template/handlers.rb +0 -6
  114. data/lib/action_view/template/handlers/builder.rb +10 -1
  115. data/lib/action_view/template/handlers/erb.rb +2 -2
  116. data/lib/action_view/template/resolver.rb +20 -31
  117. data/lib/action_view/test_case.rb +7 -10
  118. data/lib/sprockets/assets.rake +1 -1
  119. data/lib/sprockets/bootstrap.rb +3 -31
  120. data/lib/sprockets/compressors.rb +69 -7
  121. data/lib/sprockets/helpers/rails_helper.rb +6 -11
  122. data/lib/sprockets/railtie.rb +1 -0
  123. data/lib/sprockets/static_compiler.rb +0 -3
  124. metadata +57 -86
  125. checksums.yaml +0 -7
  126. data/lib/action_dispatch/middleware/closed_error.rb +0 -7
  127. data/lib/action_dispatch/routing/route.rb +0 -67
  128. data/lib/action_view/template/handler.rb +0 -49
@@ -6,13 +6,14 @@ module ActionController
6
6
  define_method(:inherited) do |klass|
7
7
  super(klass)
8
8
 
9
- if namespace = klass.parents.detect {|m| m.respond_to?(:_railtie) }
10
- paths = namespace._railtie.paths["app/helpers"].existent
9
+ if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_helpers_paths) }
10
+ paths = namespace.railtie_helpers_paths
11
11
  else
12
- paths = app.config.helpers_paths
12
+ paths = app.helpers_paths
13
13
  end
14
14
 
15
15
  klass.helpers_path = paths
16
+
16
17
  if klass.superclass == ActionController::Base && ActionController::Base.include_all_helpers
17
18
  klass.helper :all
18
19
  end
@@ -14,9 +14,9 @@ module ActionController
14
14
  # <% end %> </div>
15
15
  #
16
16
  # # controller
17
- # def destroy
17
+ # def update
18
18
  # post = Post.find(params[:id])
19
- # post.destroy
19
+ # post.update_attributes(params[:post])
20
20
  #
21
21
  # redirect_to(post) # Calls polymorphic_url(post) which in turn calls post_url(post)
22
22
  # end
@@ -40,7 +40,7 @@ module ActionController
40
40
  # dom_class(post, :edit) # => "edit_post"
41
41
  # dom_class(Person, :edit) # => "edit_person"
42
42
  def dom_class(record_or_class, prefix = nil)
43
- singular = ActiveModel::Naming.singular(record_or_class)
43
+ singular = ActiveModel::Naming.param_key(record_or_class)
44
44
  prefix ? "#{prefix}#{JOIN}#{singular}" : singular
45
45
  end
46
46
 
@@ -67,7 +67,7 @@ module ActionController
67
67
  # This can be overwritten to customize the default generated string representation if desired.
68
68
  # If you need to read back a key from a dom_id in order to query for the underlying database record,
69
69
  # you should write a helper like 'person_record_from_dom_id' that will extract the key either based
70
- # on the default implementation (which just joins all key attributes with '-') or on your own
70
+ # on the default implementation (which just joins all key attributes with '_') or on your own
71
71
  # overwritten version of the method. By default, this implementation passes the key string through a
72
72
  # method that replaces all characters that are invalid inside DOM ids, with valid ones. You need to
73
73
  # make sure yourself that your dom ids are valid, in case you overwrite this method.
@@ -79,13 +79,28 @@ module ActionController
79
79
  "expecting <?> but rendering with <?>",
80
80
  options, rendered.keys.join(', '))
81
81
  assert_block(msg) do
82
- if options.nil?
83
- @templates.blank?
84
- else
82
+ if options
85
83
  rendered.any? { |t,num| t.match(options) }
84
+ else
85
+ @templates.blank?
86
86
  end
87
87
  end
88
88
  when Hash
89
+ if expected_layout = options[:layout]
90
+ msg = build_message(message,
91
+ "expecting layout <?> but action rendered <?>",
92
+ expected_layout, @layouts.keys)
93
+
94
+ case expected_layout
95
+ when String
96
+ assert(@layouts.keys.include?(expected_layout), msg)
97
+ when Regexp
98
+ assert(@layouts.keys.any? {|l| l =~ expected_layout }, msg)
99
+ when nil
100
+ assert(@layouts.empty?, msg)
101
+ end
102
+ end
103
+
89
104
  if expected_partial = options[:partial]
90
105
  if expected_locals = options[:locals]
91
106
  actual_locals = @locals[expected_partial.to_s.sub(/^_/,'')]
@@ -98,19 +113,6 @@ module ActionController
98
113
  "expecting ? to be rendered ? time(s) but rendered ? time(s)",
99
114
  expected_partial, expected_count, actual_count)
100
115
  assert(actual_count == expected_count.to_i, msg)
101
- elsif options.key?(:layout)
102
- msg = build_message(message,
103
- "expecting layout <?> but action rendered <?>",
104
- expected_layout, @layouts.keys)
105
-
106
- case layout = options[:layout]
107
- when String
108
- assert(@layouts.include?(expected_layout), msg)
109
- when Regexp
110
- assert(@layouts.any? {|l| l =~ layout }, msg)
111
- when nil
112
- assert(@layouts.empty?, msg)
113
- end
114
116
  else
115
117
  msg = build_message(message,
116
118
  "expecting partial <?> but action rendered <?>",
@@ -145,23 +147,17 @@ module ActionController
145
147
  extra_keys = routes.extra_keys(parameters)
146
148
  non_path_parameters = get? ? query_parameters : request_parameters
147
149
  parameters.each do |key, value|
148
- if value.is_a?(Array) && (value.frozen? || value.any?(&:frozen?))
149
- value = value.map{ |v| v.duplicable? ? v.dup : v }
150
- elsif value.is_a?(Hash) && (value.frozen? || value.any?{ |k,v| v.frozen? })
151
- value = Hash[value.map{ |k,v| [k, v.duplicable? ? v.dup : v] }]
152
- elsif value.frozen? && value.duplicable?
150
+ if value.is_a? Fixnum
151
+ value = value.to_s
152
+ elsif value.is_a? Array
153
+ value = Result.new(value.map { |v| v.is_a?(String) ? v.dup : v })
154
+ elsif value.is_a? String
153
155
  value = value.dup
154
156
  end
155
157
 
156
158
  if extra_keys.include?(key.to_sym)
157
159
  non_path_parameters[key] = value
158
160
  else
159
- if value.is_a?(Array)
160
- value = Result.new(value.map(&:to_param))
161
- else
162
- value = value.to_param
163
- end
164
-
165
161
  path_parameters[key.to_s] = value
166
162
  end
167
163
  end
@@ -181,10 +177,6 @@ module ActionController
181
177
  end
182
178
 
183
179
  def recycle!
184
- write_cookies!
185
- @env.delete('HTTP_COOKIE') if @cookies.blank?
186
- @env.delete('action_dispatch.cookies')
187
- @cookies = nil
188
180
  @formats = nil
189
181
  @env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
190
182
  @env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
@@ -192,6 +184,14 @@ module ActionController
192
184
  @method = @request_method = nil
193
185
  @fullpath = @ip = @remote_ip = @protocol = nil
194
186
  @env['action_dispatch.request.query_parameters'] = {}
187
+ @set_cookies ||= {}
188
+ @set_cookies.update(Hash[cookie_jar.instance_variable_get("@set_cookies").map{ |k,o| [k,o[:value]] }])
189
+ deleted_cookies = cookie_jar.instance_variable_get("@delete_cookies")
190
+ @set_cookies.reject!{ |k,v| deleted_cookies.include?(k) }
191
+ cookie_jar.update(rack_cookies)
192
+ cookie_jar.update(cookies)
193
+ cookie_jar.update(@set_cookies)
194
+ cookie_jar.recycle!
195
195
  end
196
196
  end
197
197
 
@@ -212,7 +212,7 @@ module ActionController
212
212
  DEFAULT_OPTIONS = Rack::Session::Abstract::ID::DEFAULT_OPTIONS
213
213
 
214
214
  def initialize(session = {})
215
- @env, @by = nil, nil
215
+ super(nil, nil)
216
216
  replace(session.stringify_keys)
217
217
  @loaded = true
218
218
  end
@@ -298,27 +298,26 @@ module ActionController
298
298
  # assert_equal "Dave", cookies[:name] # makes sure that a cookie called :name was set as "Dave"
299
299
  # assert flash.empty? # makes sure that there's nothing in the flash
300
300
  #
301
- # For historic reasons, the assigns hash uses string-based keys. So assigns[:person] won't work, but assigns["person"] will. To
301
+ # For historic reasons, the assigns hash uses string-based keys. So <tt>assigns[:person]</tt> won't work, but <tt>assigns["person"]</tt> will. To
302
302
  # appease our yearning for symbols, though, an alternative accessor has been devised using a method call instead of index referencing.
303
- # So assigns(:person) will work just like assigns["person"], but again, assigns[:person] will not work.
303
+ # So <tt>assigns(:person)</tt> will work just like <tt>assigns["person"]</tt>, but again, <tt>assigns[:person]</tt> will not work.
304
304
  #
305
- # On top of the collections, you have the complete url that a given action redirected to available in redirect_to_url.
305
+ # On top of the collections, you have the complete url that a given action redirected to available in <tt>redirect_to_url</tt>.
306
306
  #
307
307
  # For redirects within the same controller, you can even call follow_redirect and the redirect will be followed, triggering another
308
308
  # action call which can then be asserted against.
309
309
  #
310
- # == Manipulating the request collections
310
+ # == Manipulating session and cookie variables
311
311
  #
312
- # The collections described above link to the response, so you can test if what the actions were expected to do happened. But
313
- # sometimes you also want to manipulate these collections in the incoming request. This is really only relevant for sessions
314
- # and cookies, though. For sessions, you just do:
312
+ # Sometimes you need to set up the session and cookie variables for a test.
313
+ # To do this just assign a value to the session or cookie collection:
315
314
  #
316
- # @request.session[:key] = "value"
317
- # @request.cookies[:key] = "value"
315
+ # session[:key] = "value"
316
+ # cookies[:key] = "value"
318
317
  #
319
- # To clear the cookies for a test just clear the request's cookies hash:
318
+ # To clear the cookies for a test just clear the cookie collection:
320
319
  #
321
- # @request.cookies.clear
320
+ # cookies.clear
322
321
  #
323
322
  # == \Testing named routes
324
323
  #
@@ -336,9 +335,21 @@ module ActionController
336
335
  module ClassMethods
337
336
 
338
337
  # Sets the controller class name. Useful if the name can't be inferred from test class.
339
- # Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
338
+ # Normalizes +controller_class+ before using. Examples:
339
+ #
340
+ # tests WidgetController
341
+ # tests :widget
342
+ # tests 'widget'
343
+ #
340
344
  def tests(controller_class)
341
- self.controller_class = controller_class
345
+ case controller_class
346
+ when String, Symbol
347
+ self.controller_class = "#{controller_class.to_s.underscore}_controller".camelize.constantize
348
+ when Class
349
+ self.controller_class = controller_class
350
+ else
351
+ raise ArgumentError, "controller class must be a String, Symbol, or Class"
352
+ end
342
353
  end
343
354
 
344
355
  def controller_class=(new_class)
@@ -355,9 +366,7 @@ module ActionController
355
366
  end
356
367
 
357
368
  def determine_default_controller_class(name)
358
- name.sub(/Test$/, '').constantize
359
- rescue NameError
360
- nil
369
+ name.sub(/Test$/, '').safe_constantize
361
370
  end
362
371
 
363
372
  def prepare_controller_class(new_class)
@@ -417,7 +426,7 @@ module ActionController
417
426
  def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
418
427
  # Ensure that numbers and symbols passed as params are converted to
419
428
  # proper params, as is the case when engaging rack.
420
- parameters = paramify_values(parameters) if html_format?(parameters)
429
+ parameters = paramify_values(parameters)
421
430
 
422
431
  # Sanity check for required instance variables so we can give an
423
432
  # understandable error message.
@@ -445,15 +454,16 @@ module ActionController
445
454
 
446
455
  @request.session = ActionController::TestSession.new(session) if session
447
456
  @request.session["flash"] = @request.flash.update(flash || {})
457
+ @request.session["flash"].sweep
448
458
 
449
459
  @controller.request = @request
460
+ @controller.params.merge!(parameters)
450
461
  build_request_uri(action, parameters)
451
462
  @controller.class.class_eval { include Testing }
452
463
  @controller.recycle!
453
464
  @controller.process_with_new_base_test(@request, @response)
454
465
  @assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {}
455
466
  @request.session.delete('flash') if @request.session['flash'].blank?
456
- @request.cookies.merge!(@response.cookies)
457
467
  @response
458
468
  end
459
469
 
@@ -503,12 +513,6 @@ module ActionController
503
513
  @request.env["QUERY_STRING"] = query_string || ""
504
514
  end
505
515
  end
506
-
507
- def html_format?(parameters)
508
- return true unless parameters.is_a?(Hash)
509
- format = Mime[parameters[:format]]
510
- format.nil? || format.html?
511
- end
512
516
  end
513
517
 
514
518
  # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
@@ -66,7 +66,7 @@ module HTML
66
66
 
67
67
  # A regular expression of the valid characters used to separate protocols like
68
68
  # the ':' in 'http://foo.com'
69
- self.protocol_separator = /:|(&#0*58)|(&#x70)|(&#x0*3a)|(%|&#37;)3A/i
69
+ self.protocol_separator = /:|(&#0*58)|(&#x70)|(%|&#37;)3A/
70
70
 
71
71
  # Specifies a Set of HTML attributes that can have URIs.
72
72
  self.uri_attributes = Set.new(%w(href src cite action longdesc xlink:href lowsrc))
@@ -104,14 +104,14 @@ module HTML
104
104
  # Specifies the default Set of allowed shorthand css properties for the #sanitize and #sanitize_css helpers.
105
105
  self.shorthand_css_properties = Set.new(%w(background border margin padding))
106
106
 
107
- # Sanitizes a block of css code. Used by #sanitize when it comes across a style attribute
107
+ # Sanitizes a block of css code. Used by #sanitize when it comes across a style attribute
108
108
  def sanitize_css(style)
109
109
  # disallow urls
110
110
  style = style.to_s.gsub(/url\s*\(\s*[^\s)]+?\s*\)\s*/, ' ')
111
111
 
112
112
  # gauntlet
113
- if style !~ /\A([:,;#%.\sa-zA-Z0-9!]|\w-\w|\'[\s\w]+\'|\"[\s\w]+\"|\([\d,\s]+\))*\z/ ||
114
- style !~ /\A(\s*[-\w]+\s*:\s*[^:;]*(;|$)\s*)*\z/
113
+ if style !~ /^([:,;#%.\sa-zA-Z0-9!]|\w-\w|\'[\s\w]+\'|\"[\s\w]+\"|\([\d,\s]+\))*$/ ||
114
+ style !~ /^(\s*[-\w]+\s*:\s*[^:;]*(;|$)\s*)*$/
115
115
  return ''
116
116
  end
117
117
 
@@ -122,7 +122,7 @@ module HTML
122
122
  elsif shorthand_css_properties.include?(prop.split('-')[0].downcase)
123
123
  unless val.split().any? do |keyword|
124
124
  !allowed_css_keywords.include?(keyword) &&
125
- keyword !~ /\A(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)\z/
125
+ keyword !~ /^(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$/
126
126
  end
127
127
  clean << prop + ': ' + val + ';'
128
128
  end
@@ -171,7 +171,7 @@ module HTML
171
171
 
172
172
  def contains_bad_protocols?(attr_name, value)
173
173
  uri_attributes.include?(attr_name) &&
174
- (value =~ /(^[^\/:]*):|(&#0*58)|(&#x70)|(&#x0*3a)|(%|&#37;)3A/i && !allowed_protocols.include?(value.split(protocol_separator).first.downcase.strip))
174
+ (value =~ /(^[^\/:]*):|(&#0*58)|(&#x70)|(%|&#37;)3A/ && !allowed_protocols.include?(value.split(protocol_separator).first.downcase))
175
175
  end
176
176
  end
177
177
  end
@@ -47,12 +47,16 @@ module ActionDispatch
47
47
  end
48
48
 
49
49
  autoload_under 'middleware' do
50
+ autoload :RequestId
50
51
  autoload :BestStandardsSupport
51
52
  autoload :Callbacks
52
53
  autoload :Cookies
54
+ autoload :DebugExceptions
55
+ autoload :ExceptionWrapper
53
56
  autoload :Flash
54
57
  autoload :Head
55
58
  autoload :ParamsParser
59
+ autoload :PublicExceptions
56
60
  autoload :Reloader
57
61
  autoload :RemoteIp
58
62
  autoload :Rescue
@@ -60,7 +64,6 @@ module ActionDispatch
60
64
  autoload :Static
61
65
  end
62
66
 
63
- autoload :ClosedError, 'action_dispatch/middleware/closed_error'
64
67
  autoload :MiddlewareStack, 'action_dispatch/middleware/stack'
65
68
  autoload :Routing
66
69
 
@@ -82,6 +85,7 @@ module ActionDispatch
82
85
  autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
83
86
  autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
84
87
  autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
88
+ autoload :CacheStore, 'action_dispatch/middleware/session/cache_store'
85
89
  end
86
90
 
87
91
  autoload_under 'testing' do
@@ -4,14 +4,18 @@ module ActionDispatch
4
4
  module Http
5
5
  module Cache
6
6
  module Request
7
+
8
+ HTTP_IF_MODIFIED_SINCE = 'HTTP_IF_MODIFIED_SINCE'.freeze
9
+ HTTP_IF_NONE_MATCH = 'HTTP_IF_NONE_MATCH'.freeze
10
+
7
11
  def if_modified_since
8
- if since = env['HTTP_IF_MODIFIED_SINCE']
12
+ if since = env[HTTP_IF_MODIFIED_SINCE]
9
13
  Time.rfc2822(since) rescue nil
10
14
  end
11
15
  end
12
16
 
13
17
  def if_none_match
14
- env['HTTP_IF_NONE_MATCH']
18
+ env[HTTP_IF_NONE_MATCH]
15
19
  end
16
20
 
17
21
  def not_modified?(modified_at)
@@ -43,31 +47,35 @@ module ActionDispatch
43
47
  alias :etag? :etag
44
48
 
45
49
  def last_modified
46
- if last = headers['Last-Modified']
50
+ if last = headers[LAST_MODIFIED]
47
51
  Time.httpdate(last)
48
52
  end
49
53
  end
50
54
 
51
55
  def last_modified?
52
- headers.include?('Last-Modified')
56
+ headers.include?(LAST_MODIFIED)
53
57
  end
54
58
 
55
59
  def last_modified=(utc_time)
56
- headers['Last-Modified'] = utc_time.httpdate
60
+ headers[LAST_MODIFIED] = utc_time.httpdate
57
61
  end
58
62
 
59
63
  def etag=(etag)
60
64
  key = ActiveSupport::Cache.expand_cache_key(etag)
61
- @etag = self["ETag"] = %("#{Digest::MD5.hexdigest(key)}")
65
+ @etag = self[ETAG] = %("#{Digest::MD5.hexdigest(key)}")
62
66
  end
63
67
 
64
68
  private
65
69
 
70
+ LAST_MODIFIED = "Last-Modified".freeze
71
+ ETAG = "ETag".freeze
72
+ CACHE_CONTROL = "Cache-Control".freeze
73
+
66
74
  def prepare_cache_control!
67
75
  @cache_control = {}
68
- @etag = self["ETag"]
76
+ @etag = self[ETAG]
69
77
 
70
- if cache_control = self["Cache-Control"]
78
+ if cache_control = self[CACHE_CONTROL]
71
79
  cache_control.split(/,\s*/).each do |segment|
72
80
  first, last = segment.split("=")
73
81
  @cache_control[first.to_sym] = last || true
@@ -81,28 +89,32 @@ module ActionDispatch
81
89
  end
82
90
  end
83
91
 
84
- DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
92
+ DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate".freeze
93
+ NO_CACHE = "no-cache".freeze
94
+ PUBLIC = "public".freeze
95
+ PRIVATE = "private".freeze
96
+ MUST_REVALIDATE = "must-revalidate".freeze
85
97
 
86
98
  def set_conditional_cache_control!
87
- return if self["Cache-Control"].present?
99
+ return if self[CACHE_CONTROL].present?
88
100
 
89
101
  control = @cache_control
90
102
 
91
103
  if control.empty?
92
- headers["Cache-Control"] = DEFAULT_CACHE_CONTROL
104
+ headers[CACHE_CONTROL] = DEFAULT_CACHE_CONTROL
93
105
  elsif control[:no_cache]
94
- headers["Cache-Control"] = "no-cache"
106
+ headers[CACHE_CONTROL] = NO_CACHE
95
107
  else
96
108
  extras = control[:extras]
97
109
  max_age = control[:max_age]
98
110
 
99
111
  options = []
100
112
  options << "max-age=#{max_age.to_i}" if max_age
101
- options << (control[:public] ? "public" : "private")
102
- options << "must-revalidate" if control[:must_revalidate]
113
+ options << (control[:public] ? PUBLIC : PRIVATE)
114
+ options << MUST_REVALIDATE if control[:must_revalidate]
103
115
  options.concat(extras) if extras
104
116
 
105
- headers["Cache-Control"] = options.join(", ")
117
+ headers[CACHE_CONTROL] = options.join(", ")
106
118
  end
107
119
  end
108
120
  end