actionpack 5.2.6 → 6.1.4.4

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +327 -335
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/abstract_controller/base.rb +38 -4
  6. data/lib/abstract_controller/caching/fragments.rb +6 -22
  7. data/lib/abstract_controller/caching.rb +1 -1
  8. data/lib/abstract_controller/callbacks.rb +14 -2
  9. data/lib/abstract_controller/collector.rb +1 -2
  10. data/lib/abstract_controller/helpers.rb +106 -90
  11. data/lib/abstract_controller/railties/routes_helpers.rb +17 -1
  12. data/lib/abstract_controller/rendering.rb +9 -9
  13. data/lib/abstract_controller/translation.rb +11 -5
  14. data/lib/abstract_controller.rb +1 -0
  15. data/lib/action_controller/api.rb +4 -3
  16. data/lib/action_controller/base.rb +6 -9
  17. data/lib/action_controller/caching.rb +1 -3
  18. data/lib/action_controller/log_subscriber.rb +10 -7
  19. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  20. data/lib/action_controller/metal/conditional_get.rb +19 -5
  21. data/lib/action_controller/metal/content_security_policy.rb +1 -2
  22. data/lib/action_controller/metal/cookies.rb +3 -1
  23. data/lib/action_controller/metal/data_streaming.rb +6 -7
  24. data/lib/action_controller/metal/default_headers.rb +17 -0
  25. data/lib/action_controller/metal/etag_with_template_digest.rb +4 -6
  26. data/lib/action_controller/metal/exceptions.rb +56 -2
  27. data/lib/action_controller/metal/flash.rb +5 -5
  28. data/lib/action_controller/metal/head.rb +7 -4
  29. data/lib/action_controller/metal/helpers.rb +14 -5
  30. data/lib/action_controller/metal/http_authentication.rb +24 -23
  31. data/lib/action_controller/metal/implicit_render.rb +5 -15
  32. data/lib/action_controller/metal/instrumentation.rb +13 -14
  33. data/lib/action_controller/metal/live.rb +39 -32
  34. data/lib/action_controller/metal/logging.rb +20 -0
  35. data/lib/action_controller/metal/mime_responds.rb +19 -4
  36. data/lib/action_controller/metal/parameter_encoding.rb +35 -4
  37. data/lib/action_controller/metal/params_wrapper.rb +32 -22
  38. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  39. data/lib/action_controller/metal/redirecting.rb +6 -6
  40. data/lib/action_controller/metal/renderers.rb +4 -4
  41. data/lib/action_controller/metal/rendering.rb +8 -3
  42. data/lib/action_controller/metal/request_forgery_protection.rb +26 -49
  43. data/lib/action_controller/metal/rescue.rb +1 -1
  44. data/lib/action_controller/metal/streaming.rb +0 -1
  45. data/lib/action_controller/metal/strong_parameters.rb +167 -58
  46. data/lib/action_controller/metal/url_for.rb +1 -1
  47. data/lib/action_controller/metal.rb +10 -8
  48. data/lib/action_controller/railties/helpers.rb +1 -1
  49. data/lib/action_controller/renderer.rb +37 -13
  50. data/lib/action_controller/template_assertions.rb +1 -1
  51. data/lib/action_controller/test_case.rb +71 -63
  52. data/lib/action_controller.rb +7 -4
  53. data/lib/action_dispatch/http/cache.rb +31 -27
  54. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  55. data/lib/action_dispatch/http/content_security_policy.rb +33 -19
  56. data/lib/action_dispatch/http/filter_parameters.rb +9 -8
  57. data/lib/action_dispatch/http/filter_redirect.rb +2 -3
  58. data/lib/action_dispatch/http/headers.rb +4 -4
  59. data/lib/action_dispatch/http/mime_negotiation.rb +26 -13
  60. data/lib/action_dispatch/http/mime_type.rb +43 -24
  61. data/lib/action_dispatch/http/parameters.rb +14 -23
  62. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  63. data/lib/action_dispatch/http/request.rb +45 -22
  64. data/lib/action_dispatch/http/response.rb +45 -25
  65. data/lib/action_dispatch/http/upload.rb +9 -1
  66. data/lib/action_dispatch/http/url.rb +82 -82
  67. data/lib/action_dispatch/journey/formatter.rb +55 -31
  68. data/lib/action_dispatch/journey/gtg/builder.rb +22 -37
  69. data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
  70. data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -5
  71. data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
  72. data/lib/action_dispatch/journey/nodes/node.rb +13 -11
  73. data/lib/action_dispatch/journey/parser.rb +13 -13
  74. data/lib/action_dispatch/journey/parser.y +1 -1
  75. data/lib/action_dispatch/journey/path/pattern.rb +19 -21
  76. data/lib/action_dispatch/journey/route.rb +10 -20
  77. data/lib/action_dispatch/journey/router/utils.rb +14 -12
  78. data/lib/action_dispatch/journey/router.rb +26 -34
  79. data/lib/action_dispatch/journey/routes.rb +0 -2
  80. data/lib/action_dispatch/journey/scanner.rb +10 -4
  81. data/lib/action_dispatch/journey/visitors.rb +1 -4
  82. data/lib/action_dispatch/journey.rb +0 -2
  83. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  84. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  85. data/lib/action_dispatch/middleware/cookies.rb +128 -109
  86. data/lib/action_dispatch/middleware/debug_exceptions.rb +43 -66
  87. data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
  88. data/lib/action_dispatch/middleware/debug_view.rb +66 -0
  89. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -30
  90. data/lib/action_dispatch/middleware/flash.rb +1 -1
  91. data/lib/action_dispatch/middleware/host_authorization.rb +141 -0
  92. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
  93. data/lib/action_dispatch/middleware/remote_ip.rb +14 -16
  94. data/lib/action_dispatch/middleware/request_id.rb +5 -6
  95. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -3
  96. data/lib/action_dispatch/middleware/session/cookie_store.rb +3 -9
  97. data/lib/action_dispatch/middleware/show_exceptions.rb +3 -2
  98. data/lib/action_dispatch/middleware/ssl.rb +20 -15
  99. data/lib/action_dispatch/middleware/stack.rb +56 -2
  100. data/lib/action_dispatch/middleware/static.rb +153 -93
  101. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  102. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  103. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
  105. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  106. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  107. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  108. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  109. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
  111. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  112. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +6 -3
  113. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -1
  114. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -8
  115. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  118. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  119. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
  120. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  121. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
  122. data/lib/action_dispatch/railtie.rb +8 -2
  123. data/lib/action_dispatch/request/session.rb +11 -10
  124. data/lib/action_dispatch/request/utils.rb +26 -2
  125. data/lib/action_dispatch/routing/inspector.rb +100 -52
  126. data/lib/action_dispatch/routing/mapper.rb +155 -103
  127. data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -15
  128. data/lib/action_dispatch/routing/redirection.rb +4 -4
  129. data/lib/action_dispatch/routing/route_set.rb +71 -69
  130. data/lib/action_dispatch/routing/url_for.rb +2 -2
  131. data/lib/action_dispatch/routing.rb +21 -20
  132. data/lib/action_dispatch/system_test_case.rb +54 -11
  133. data/lib/action_dispatch/system_testing/browser.rb +53 -16
  134. data/lib/action_dispatch/system_testing/driver.rb +11 -3
  135. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
  136. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -10
  137. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  138. data/lib/action_dispatch/testing/assertions/response.rb +4 -7
  139. data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
  140. data/lib/action_dispatch/testing/assertions.rb +1 -1
  141. data/lib/action_dispatch/testing/integration.rb +60 -28
  142. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  143. data/lib/action_dispatch/testing/test_process.rb +29 -4
  144. data/lib/action_dispatch/testing/test_request.rb +3 -3
  145. data/lib/action_dispatch/testing/test_response.rb +4 -32
  146. data/lib/action_dispatch.rb +9 -3
  147. data/lib/action_pack/gem_version.rb +4 -4
  148. data/lib/action_pack.rb +1 -1
  149. metadata +35 -23
  150. data/lib/action_controller/metal/force_ssl.rb +0 -99
  151. data/lib/action_dispatch/http/parameter_filter.rb +0 -86
  152. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  153. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
  154. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
  155. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -23,6 +23,7 @@ module ActionDispatch
23
23
  include ActionDispatch::Http::FilterParameters
24
24
  include ActionDispatch::Http::URL
25
25
  include ActionDispatch::ContentSecurityPolicy::Request
26
+ include ActionDispatch::PermissionsPolicy::Request
26
27
  include Rack::Request::Env
27
28
 
28
29
  autoload :Session, "action_dispatch/request/session"
@@ -44,11 +45,14 @@ module ActionDispatch
44
45
  SERVER_ADDR
45
46
  ].freeze
46
47
 
48
+ # TODO: Remove SERVER_ADDR when we remove support to Rack 2.1.
49
+ # See https://github.com/rack/rack/commit/c173b188d81ee437b588c1e046a1c9f031dea550
47
50
  ENV_METHODS.each do |env|
48
51
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
49
- def #{env.sub(/^HTTP_/n, '').downcase} # def accept_charset
50
- get_header "#{env}".freeze # get_header "HTTP_ACCEPT_CHARSET".freeze
51
- end # end
52
+ # frozen_string_literal: true
53
+ def #{env.delete_prefix("HTTP_").downcase} # def accept_charset
54
+ get_header "#{env}" # get_header "HTTP_ACCEPT_CHARSET"
55
+ end # end
52
56
  METHOD
53
57
  end
54
58
 
@@ -72,7 +76,7 @@ module ActionDispatch
72
76
  PASS_NOT_FOUND = Class.new { # :nodoc:
73
77
  def self.action(_); self; end
74
78
  def self.call(_); [404, { "X-Cascade" => "pass" }, []]; end
75
- def self.binary_params_for?(action); false; end
79
+ def self.action_encoding_template(action); false; end
76
80
  }
77
81
 
78
82
  def controller_class
@@ -84,8 +88,16 @@ module ActionDispatch
84
88
  def controller_class_for(name)
85
89
  if name
86
90
  controller_param = name.underscore
87
- const_name = "#{controller_param.camelize}Controller"
88
- ActiveSupport::Dependencies.constantize(const_name)
91
+ const_name = controller_param.camelize << "Controller"
92
+ begin
93
+ ActiveSupport::Dependencies.constantize(const_name)
94
+ rescue NameError => error
95
+ if error.missing_name == const_name || const_name.start_with?("#{error.missing_name}::")
96
+ raise MissingController.new(error.message, error.name)
97
+ else
98
+ raise
99
+ end
100
+ end
89
101
  else
90
102
  PASS_NOT_FOUND
91
103
  end
@@ -125,6 +137,8 @@ module ActionDispatch
125
137
  HTTP_METHOD_LOOKUP[method] = method.underscore.to_sym
126
138
  }
127
139
 
140
+ alias raw_request_method request_method # :nodoc:
141
+
128
142
  # Returns the HTTP \method that the application should see.
129
143
  # In the case where the \method was overridden by a middleware
130
144
  # (for instance, if a HEAD request was converted to a GET,
@@ -136,11 +150,11 @@ module ActionDispatch
136
150
  end
137
151
 
138
152
  def routes # :nodoc:
139
- get_header("action_dispatch.routes".freeze)
153
+ get_header("action_dispatch.routes")
140
154
  end
141
155
 
142
156
  def routes=(routes) # :nodoc:
143
- set_header("action_dispatch.routes".freeze, routes)
157
+ set_header("action_dispatch.routes", routes)
144
158
  end
145
159
 
146
160
  def engine_script_name(_routes) # :nodoc:
@@ -158,11 +172,11 @@ module ActionDispatch
158
172
  end
159
173
 
160
174
  def controller_instance # :nodoc:
161
- get_header("action_controller.instance".freeze)
175
+ get_header("action_controller.instance")
162
176
  end
163
177
 
164
178
  def controller_instance=(controller) # :nodoc:
165
- set_header("action_controller.instance".freeze, controller)
179
+ set_header("action_controller.instance", controller)
166
180
  end
167
181
 
168
182
  def http_auth_salt
@@ -173,7 +187,7 @@ module ActionDispatch
173
187
  # We're treating `nil` as "unset", and we want the default setting to be
174
188
  # `true`. This logic should be extracted to `env_config` and calculated
175
189
  # once.
176
- !(get_header("action_dispatch.show_exceptions".freeze) == false)
190
+ !(get_header("action_dispatch.show_exceptions") == false)
177
191
  end
178
192
 
179
193
  # Returns a symbol form of the #request_method.
@@ -264,7 +278,7 @@ module ActionDispatch
264
278
  # (case-insensitive), which may need to be manually added depending on the
265
279
  # choice of JavaScript libraries and frameworks.
266
280
  def xml_http_request?
267
- get_header("HTTP_X_REQUESTED_WITH") =~ /XMLHttpRequest/i
281
+ /XMLHttpRequest/i.match?(get_header("HTTP_X_REQUESTED_WITH"))
268
282
  end
269
283
  alias :xhr? :xml_http_request?
270
284
 
@@ -280,10 +294,11 @@ module ActionDispatch
280
294
  end
281
295
 
282
296
  def remote_ip=(remote_ip)
283
- set_header "action_dispatch.remote_ip".freeze, remote_ip
297
+ @remote_ip = nil
298
+ set_header "action_dispatch.remote_ip", remote_ip
284
299
  end
285
300
 
286
- ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id".freeze # :nodoc:
301
+ ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
287
302
 
288
303
  # Returns the unique request id, which is based on either the X-Request-Id header that can
289
304
  # be generated by a firewall, load balancer, or web server or by the RequestId middleware
@@ -321,7 +336,7 @@ module ActionDispatch
321
336
  # variable is already set, wrap it in a StringIO.
322
337
  def body
323
338
  if raw_post = get_header("RAW_POST_DATA")
324
- raw_post = raw_post.dup.force_encoding(Encoding::BINARY)
339
+ raw_post = (+raw_post).force_encoding(Encoding::BINARY)
325
340
  StringIO.new(raw_post)
326
341
  else
327
342
  body_stream
@@ -366,6 +381,9 @@ module ActionDispatch
366
381
  def GET
367
382
  fetch_header("action_dispatch.request.query_parameters") do |k|
368
383
  rack_query_params = super || {}
384
+ controller = path_parameters[:controller]
385
+ action = path_parameters[:action]
386
+ rack_query_params = Request::Utils.set_binary_encoding(self, rack_query_params, controller, action)
369
387
  # Check for non UTF-8 parameter values, which would cause errors later
370
388
  Request::Utils.check_param_encoding(rack_query_params)
371
389
  set_header k, Request::Utils.normalize_encode_params(rack_query_params)
@@ -381,11 +399,10 @@ module ActionDispatch
381
399
  pr = parse_formatted_parameters(params_parsers) do |params|
382
400
  super || {}
383
401
  end
402
+ pr = Request::Utils.set_binary_encoding(self, pr, path_parameters[:controller], path_parameters[:action])
403
+ Request::Utils.check_param_encoding(pr)
384
404
  self.request_parameters = Request::Utils.normalize_encode_params(pr)
385
405
  end
386
- rescue Http::Parameters::ParseError # one of the parse strategies blew up
387
- self.request_parameters = Request::Utils.normalize_encode_params(super || {})
388
- raise
389
406
  rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
390
407
  raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
391
408
  end
@@ -402,23 +419,27 @@ module ActionDispatch
402
419
 
403
420
  # True if the request came from localhost, 127.0.0.1, or ::1.
404
421
  def local?
405
- LOCALHOST =~ remote_addr && LOCALHOST =~ remote_ip
422
+ LOCALHOST.match?(remote_addr) && LOCALHOST.match?(remote_ip)
406
423
  end
407
424
 
408
425
  def request_parameters=(params)
409
426
  raise if params.nil?
410
- set_header("action_dispatch.request.request_parameters".freeze, params)
427
+ set_header("action_dispatch.request.request_parameters", params)
411
428
  end
412
429
 
413
430
  def logger
414
- get_header("action_dispatch.logger".freeze)
431
+ get_header("action_dispatch.logger")
415
432
  end
416
433
 
417
434
  def commit_flash
418
435
  end
419
436
 
420
437
  def ssl?
421
- super || scheme == "wss".freeze
438
+ super || scheme == "wss"
439
+ end
440
+
441
+ def inspect # :nodoc:
442
+ "#<#{self.class.name} #{method} #{original_url.dump} for #{remote_ip}>"
422
443
  end
423
444
 
424
445
  private
@@ -428,3 +449,5 @@ module ActionDispatch
428
449
  end
429
450
  end
430
451
  end
452
+
453
+ ActiveSupport.run_load_hooks :action_dispatch_request, ActionDispatch::Request
@@ -78,14 +78,26 @@ module ActionDispatch # :nodoc:
78
78
  x
79
79
  end
80
80
 
81
- CONTENT_TYPE = "Content-Type".freeze
82
- SET_COOKIE = "Set-Cookie".freeze
83
- LOCATION = "Location".freeze
84
- NO_CONTENT_CODES = [100, 101, 102, 204, 205, 304]
81
+ CONTENT_TYPE = "Content-Type"
82
+ SET_COOKIE = "Set-Cookie"
83
+ LOCATION = "Location"
84
+ NO_CONTENT_CODES = [100, 101, 102, 103, 204, 205, 304]
85
85
 
86
86
  cattr_accessor :default_charset, default: "utf-8"
87
87
  cattr_accessor :default_headers
88
88
 
89
+ def self.return_only_media_type_on_content_type=(*)
90
+ ActiveSupport::Deprecation.warn(
91
+ ".return_only_media_type_on_content_type= is dreprecated with no replacement and will be removed in 6.2."
92
+ )
93
+ end
94
+
95
+ def self.return_only_media_type_on_content_type
96
+ ActiveSupport::Deprecation.warn(
97
+ ".return_only_media_type_on_content_type is dreprecated with no replacement and will be removed in 6.2."
98
+ )
99
+ end
100
+
89
101
  include Rack::Response::Helpers
90
102
  # Aliasing these off because AD::Http::Cache::Response defines them.
91
103
  alias :_cache_control :cache_control
@@ -105,7 +117,7 @@ module ActionDispatch # :nodoc:
105
117
 
106
118
  def body
107
119
  @str_body ||= begin
108
- buf = "".dup
120
+ buf = +""
109
121
  each { |chunk| buf << chunk }
110
122
  buf
111
123
  end
@@ -142,7 +154,6 @@ module ActionDispatch # :nodoc:
142
154
  end
143
155
 
144
156
  private
145
-
146
157
  def each_chunk(&block)
147
158
  @buf.each(&block)
148
159
  end
@@ -224,16 +235,6 @@ module ActionDispatch # :nodoc:
224
235
  @status = Rack::Utils.status_code(status)
225
236
  end
226
237
 
227
- # Sets the HTTP content type.
228
- def content_type=(content_type)
229
- return unless content_type
230
- new_header_info = parse_content_type(content_type.to_s)
231
- prev_header_info = parsed_content_type_header
232
- charset = new_header_info.charset || prev_header_info.charset
233
- charset ||= self.class.default_charset unless prev_header_info.mime_type
234
- set_content_type new_header_info.mime_type, charset
235
- end
236
-
237
238
  # Sets the HTTP response's content MIME type. For example, in the controller
238
239
  # you could write this:
239
240
  #
@@ -242,8 +243,22 @@ module ActionDispatch # :nodoc:
242
243
  # If a character set has been defined for this response (see charset=) then
243
244
  # the character set information will also be included in the content type
244
245
  # information.
246
+ def content_type=(content_type)
247
+ return unless content_type
248
+ new_header_info = parse_content_type(content_type.to_s)
249
+ prev_header_info = parsed_content_type_header
250
+ charset = new_header_info.charset || prev_header_info.charset
251
+ charset ||= self.class.default_charset unless prev_header_info.mime_type
252
+ set_content_type new_header_info.mime_type, charset
253
+ end
245
254
 
255
+ # Content type of response.
246
256
  def content_type
257
+ super.presence
258
+ end
259
+
260
+ # Media type of response.
261
+ def media_type
247
262
  parsed_content_type_header.mime_type
248
263
  end
249
264
 
@@ -404,15 +419,18 @@ module ActionDispatch # :nodoc:
404
419
  end
405
420
 
406
421
  private
407
-
408
422
  ContentTypeHeader = Struct.new :mime_type, :charset
409
423
  NullContentTypeHeader = ContentTypeHeader.new nil, nil
410
424
 
425
+ CONTENT_TYPE_PARSER = /
426
+ \A
427
+ (?<mime_type>[^;\s]+\s*(?:;\s*(?:(?!charset)[^;\s])+)*)?
428
+ (?:;\s*charset=(?<quote>"?)(?<charset>[^;\s]+)\k<quote>)?
429
+ /x # :nodoc:
430
+
411
431
  def parse_content_type(content_type)
412
- if content_type
413
- type, charset = content_type.split(/;\s*charset=/)
414
- type = nil if type && type.empty?
415
- ContentTypeHeader.new(type, charset)
432
+ if content_type && match = CONTENT_TYPE_PARSER.match(content_type)
433
+ ContentTypeHeader.new(match[:mime_type], match[:charset])
416
434
  else
417
435
  NullContentTypeHeader
418
436
  end
@@ -425,8 +443,8 @@ module ActionDispatch # :nodoc:
425
443
  end
426
444
 
427
445
  def set_content_type(content_type, charset)
428
- type = (content_type || "").dup
429
- type << "; charset=#{charset.to_s.downcase}" if charset
446
+ type = content_type || ""
447
+ type = "#{type}; charset=#{charset.to_s.downcase}" if charset
430
448
  set_header CONTENT_TYPE, type
431
449
  end
432
450
 
@@ -459,7 +477,7 @@ module ActionDispatch # :nodoc:
459
477
  end
460
478
 
461
479
  def assign_default_content_type_and_charset!
462
- return if content_type
480
+ return if media_type
463
481
 
464
482
  ct = parsed_content_type_header
465
483
  set_content_type(ct.mime_type || Mime[:html].to_s,
@@ -486,7 +504,7 @@ module ActionDispatch # :nodoc:
486
504
  end
487
505
 
488
506
  def respond_to?(method, include_private = false)
489
- if method.to_s == "to_path"
507
+ if method.to_sym == :to_path
490
508
  @response.stream.respond_to?(method)
491
509
  else
492
510
  super
@@ -517,4 +535,6 @@ module ActionDispatch # :nodoc:
517
535
  end
518
536
  end
519
537
  end
538
+
539
+ ActiveSupport.run_load_hooks(:action_dispatch_response, Response)
520
540
  end
@@ -20,7 +20,6 @@ module ActionDispatch
20
20
  # A +Tempfile+ object with the actual uploaded file. Note that some of
21
21
  # its interface is available directly.
22
22
  attr_accessor :tempfile
23
- alias :to_io :tempfile
24
23
 
25
24
  # A string with the headers of the multipart request.
26
25
  attr_accessor :headers
@@ -65,6 +64,11 @@ module ActionDispatch
65
64
  @tempfile.path
66
65
  end
67
66
 
67
+ # Shortcut for +tempfile.to_path+.
68
+ def to_path
69
+ @tempfile.to_path
70
+ end
71
+
68
72
  # Shortcut for +tempfile.rewind+.
69
73
  def rewind
70
74
  @tempfile.rewind
@@ -79,6 +83,10 @@ module ActionDispatch
79
83
  def eof?
80
84
  @tempfile.eof?
81
85
  end
86
+
87
+ def to_io
88
+ @tempfile.to_io
89
+ end
82
90
  end
83
91
  end
84
92
  end
@@ -9,6 +9,7 @@ module ActionDispatch
9
9
  HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
10
10
  PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
11
11
 
12
+ mattr_accessor :secure_protocol, default: false
12
13
  mattr_accessor :tld_length, default: 1
13
14
 
14
15
  class << self
@@ -67,7 +68,7 @@ module ActionDispatch
67
68
  end
68
69
 
69
70
  def path_for(options)
70
- path = options[:script_name].to_s.chomp("/".freeze)
71
+ path = options[:script_name].to_s.chomp("/")
71
72
  path << options[:path] if options.key?(:path)
72
73
 
73
74
  add_trailing_slash(path) if options[:trailing_slash]
@@ -78,109 +79,108 @@ module ActionDispatch
78
79
  end
79
80
 
80
81
  private
81
-
82
- def add_params(path, params)
83
- params = { params: params } unless params.is_a?(Hash)
84
- params.reject! { |_, v| v.to_param.nil? }
85
- query = params.to_query
86
- path << "?#{query}" unless query.empty?
87
- end
88
-
89
- def add_anchor(path, anchor)
90
- if anchor
91
- path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
82
+ def add_params(path, params)
83
+ params = { params: params } unless params.is_a?(Hash)
84
+ params.reject! { |_, v| v.to_param.nil? }
85
+ query = params.to_query
86
+ path << "?#{query}" unless query.empty?
92
87
  end
93
- end
94
88
 
95
- def extract_domain_from(host, tld_length)
96
- host.split(".").last(1 + tld_length).join(".")
97
- end
89
+ def add_anchor(path, anchor)
90
+ if anchor
91
+ path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
92
+ end
93
+ end
98
94
 
99
- def extract_subdomains_from(host, tld_length)
100
- parts = host.split(".")
101
- parts[0..-(tld_length + 2)]
102
- end
95
+ def extract_domain_from(host, tld_length)
96
+ host.split(".").last(1 + tld_length).join(".")
97
+ end
103
98
 
104
- def add_trailing_slash(path)
105
- if path.include?("?")
106
- path.sub!(/\?/, '/\&')
107
- elsif !path.include?(".")
108
- path.sub!(/[^\/]\z|\A\z/, '\&/')
99
+ def extract_subdomains_from(host, tld_length)
100
+ parts = host.split(".")
101
+ parts[0..-(tld_length + 2)]
109
102
  end
110
- end
111
103
 
112
- def build_host_url(host, port, protocol, options, path)
113
- if match = host.match(HOST_REGEXP)
114
- protocol ||= match[1] unless protocol == false
115
- host = match[2]
116
- port = match[3] unless options.key? :port
104
+ def add_trailing_slash(path)
105
+ if path.include?("?")
106
+ path.sub!(/\?/, '/\&')
107
+ elsif !path.include?(".")
108
+ path.sub!(/[^\/]\z|\A\z/, '\&/')
109
+ end
117
110
  end
118
111
 
119
- protocol = normalize_protocol protocol
120
- host = normalize_host(host, options)
112
+ def build_host_url(host, port, protocol, options, path)
113
+ if match = host.match(HOST_REGEXP)
114
+ protocol ||= match[1] unless protocol == false
115
+ host = match[2]
116
+ port = match[3] unless options.key? :port
117
+ end
121
118
 
122
- result = protocol.dup
119
+ protocol = normalize_protocol protocol
120
+ host = normalize_host(host, options)
123
121
 
124
- if options[:user] && options[:password]
125
- result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
126
- end
122
+ result = protocol.dup
127
123
 
128
- result << host
129
- normalize_port(port, protocol) { |normalized_port|
130
- result << ":#{normalized_port}"
131
- }
124
+ if options[:user] && options[:password]
125
+ result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
126
+ end
132
127
 
133
- result.concat path
134
- end
128
+ result << host
129
+ normalize_port(port, protocol) { |normalized_port|
130
+ result << ":#{normalized_port}"
131
+ }
135
132
 
136
- def named_host?(host)
137
- IP_HOST_REGEXP !~ host
138
- end
133
+ result.concat path
134
+ end
139
135
 
140
- def normalize_protocol(protocol)
141
- case protocol
142
- when nil
143
- "http://"
144
- when false, "//"
145
- "//"
146
- when PROTOCOL_REGEXP
147
- "#{$1}://"
148
- else
149
- raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
136
+ def named_host?(host)
137
+ !IP_HOST_REGEXP.match?(host)
150
138
  end
151
- end
152
139
 
153
- def normalize_host(_host, options)
154
- return _host unless named_host?(_host)
140
+ def normalize_protocol(protocol)
141
+ case protocol
142
+ when nil
143
+ secure_protocol ? "https://" : "http://"
144
+ when false, "//"
145
+ "//"
146
+ when PROTOCOL_REGEXP
147
+ "#{$1}://"
148
+ else
149
+ raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
150
+ end
151
+ end
152
+
153
+ def normalize_host(_host, options)
154
+ return _host unless named_host?(_host)
155
155
 
156
- tld_length = options[:tld_length] || @@tld_length
157
- subdomain = options.fetch :subdomain, true
158
- domain = options[:domain]
156
+ tld_length = options[:tld_length] || @@tld_length
157
+ subdomain = options.fetch :subdomain, true
158
+ domain = options[:domain]
159
159
 
160
- host = "".dup
161
- if subdomain == true
162
- return _host if domain.nil?
160
+ host = +""
161
+ if subdomain == true
162
+ return _host if domain.nil?
163
163
 
164
- host << extract_subdomains_from(_host, tld_length).join(".")
165
- elsif subdomain
166
- host << subdomain.to_param
164
+ host << extract_subdomains_from(_host, tld_length).join(".")
165
+ elsif subdomain
166
+ host << subdomain.to_param
167
+ end
168
+ host << "." unless host.empty?
169
+ host << (domain || extract_domain_from(_host, tld_length))
170
+ host
167
171
  end
168
- host << "." unless host.empty?
169
- host << (domain || extract_domain_from(_host, tld_length))
170
- host
171
- end
172
172
 
173
- def normalize_port(port, protocol)
174
- return unless port
173
+ def normalize_port(port, protocol)
174
+ return unless port
175
175
 
176
- case protocol
177
- when "//" then yield port
178
- when "https://"
179
- yield port unless port.to_i == 443
180
- else
181
- yield port unless port.to_i == 80
176
+ case protocol
177
+ when "//" then yield port
178
+ when "https://"
179
+ yield port unless port.to_i == 443
180
+ else
181
+ yield port unless port.to_i == 80
182
+ end
182
183
  end
183
- end
184
184
  end
185
185
 
186
186
  def initialize
@@ -231,7 +231,7 @@ module ActionDispatch
231
231
  # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
232
232
  # req.host # => "example.com"
233
233
  def host
234
- raw_host_with_port.sub(/:\d+$/, "".freeze)
234
+ raw_host_with_port.sub(/:\d+$/, "")
235
235
  end
236
236
 
237
237
  # Returns a \host:\port string for this request, such as "example.com" or