actionpack 5.2.4.rc1 → 6.0.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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +120 -366
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/abstract_controller/base.rb +4 -2
  6. data/lib/abstract_controller/caching/fragments.rb +6 -21
  7. data/lib/abstract_controller/callbacks.rb +12 -0
  8. data/lib/abstract_controller/collector.rb +1 -1
  9. data/lib/abstract_controller/helpers.rb +2 -2
  10. data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
  11. data/lib/action_controller.rb +1 -0
  12. data/lib/action_controller/api.rb +2 -1
  13. data/lib/action_controller/base.rb +2 -7
  14. data/lib/action_controller/caching.rb +1 -1
  15. data/lib/action_controller/log_subscriber.rb +8 -5
  16. data/lib/action_controller/metal.rb +2 -2
  17. data/lib/action_controller/metal/conditional_get.rb +9 -3
  18. data/lib/action_controller/metal/data_streaming.rb +5 -6
  19. data/lib/action_controller/metal/default_headers.rb +17 -0
  20. data/lib/action_controller/metal/exceptions.rb +22 -1
  21. data/lib/action_controller/metal/flash.rb +5 -5
  22. data/lib/action_controller/metal/force_ssl.rb +17 -57
  23. data/lib/action_controller/metal/head.rb +1 -1
  24. data/lib/action_controller/metal/helpers.rb +1 -2
  25. data/lib/action_controller/metal/http_authentication.rb +20 -21
  26. data/lib/action_controller/metal/implicit_render.rb +2 -12
  27. data/lib/action_controller/metal/instrumentation.rb +3 -5
  28. data/lib/action_controller/metal/live.rb +28 -26
  29. data/lib/action_controller/metal/mime_responds.rb +13 -2
  30. data/lib/action_controller/metal/params_wrapper.rb +18 -14
  31. data/lib/action_controller/metal/redirecting.rb +32 -11
  32. data/lib/action_controller/metal/rendering.rb +1 -1
  33. data/lib/action_controller/metal/request_forgery_protection.rb +22 -11
  34. data/lib/action_controller/metal/strong_parameters.rb +57 -32
  35. data/lib/action_controller/metal/url_for.rb +1 -1
  36. data/lib/action_controller/railties/helpers.rb +1 -1
  37. data/lib/action_controller/renderer.rb +15 -2
  38. data/lib/action_controller/test_case.rb +3 -7
  39. data/lib/action_dispatch.rb +3 -1
  40. data/lib/action_dispatch/http/cache.rb +14 -10
  41. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  42. data/lib/action_dispatch/http/content_security_policy.rb +9 -8
  43. data/lib/action_dispatch/http/filter_parameters.rb +8 -6
  44. data/lib/action_dispatch/http/filter_redirect.rb +1 -1
  45. data/lib/action_dispatch/http/headers.rb +1 -1
  46. data/lib/action_dispatch/http/mime_negotiation.rb +7 -10
  47. data/lib/action_dispatch/http/mime_type.rb +1 -5
  48. data/lib/action_dispatch/http/parameter_filter.rb +5 -79
  49. data/lib/action_dispatch/http/parameters.rb +13 -3
  50. data/lib/action_dispatch/http/request.rb +10 -13
  51. data/lib/action_dispatch/http/response.rb +14 -14
  52. data/lib/action_dispatch/http/upload.rb +5 -0
  53. data/lib/action_dispatch/http/url.rb +81 -81
  54. data/lib/action_dispatch/journey/formatter.rb +1 -1
  55. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -2
  56. data/lib/action_dispatch/journey/nodes/node.rb +9 -8
  57. data/lib/action_dispatch/journey/path/pattern.rb +3 -4
  58. data/lib/action_dispatch/journey/router.rb +0 -3
  59. data/lib/action_dispatch/journey/router/utils.rb +10 -10
  60. data/lib/action_dispatch/journey/scanner.rb +11 -4
  61. data/lib/action_dispatch/journey/visitors.rb +1 -1
  62. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  63. data/lib/action_dispatch/middleware/cookies.rb +49 -70
  64. data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -58
  65. data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
  66. data/lib/action_dispatch/middleware/debug_view.rb +50 -0
  67. data/lib/action_dispatch/middleware/exception_wrapper.rb +36 -7
  68. data/lib/action_dispatch/middleware/flash.rb +1 -1
  69. data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
  70. data/lib/action_dispatch/middleware/remote_ip.rb +6 -8
  71. data/lib/action_dispatch/middleware/request_id.rb +2 -2
  72. data/lib/action_dispatch/middleware/session/cookie_store.rb +4 -10
  73. data/lib/action_dispatch/middleware/ssl.rb +8 -8
  74. data/lib/action_dispatch/middleware/stack.rb +2 -2
  75. data/lib/action_dispatch/middleware/static.rb +5 -6
  76. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  77. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  78. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  79. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  80. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +20 -2
  81. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -4
  82. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
  83. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  84. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  85. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  86. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  87. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
  88. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +3 -0
  89. data/lib/action_dispatch/railtie.rb +1 -0
  90. data/lib/action_dispatch/request/session.rb +8 -0
  91. data/lib/action_dispatch/routing.rb +3 -2
  92. data/lib/action_dispatch/routing/inspector.rb +99 -50
  93. data/lib/action_dispatch/routing/mapper.rb +36 -29
  94. data/lib/action_dispatch/routing/polymorphic_routes.rb +3 -4
  95. data/lib/action_dispatch/routing/route_set.rb +11 -12
  96. data/lib/action_dispatch/routing/url_for.rb +1 -0
  97. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +3 -3
  98. data/lib/action_dispatch/testing/assertions/response.rb +2 -3
  99. data/lib/action_dispatch/testing/assertions/routing.rb +7 -2
  100. data/lib/action_dispatch/testing/integration.rb +11 -4
  101. data/lib/action_dispatch/testing/test_process.rb +2 -2
  102. data/lib/action_dispatch/testing/test_response.rb +4 -32
  103. data/lib/action_pack.rb +1 -1
  104. data/lib/action_pack/gem_version.rb +4 -4
  105. metadata +20 -12
@@ -3,7 +3,7 @@
3
3
  module ActionDispatch
4
4
  module Http
5
5
  module FilterRedirect
6
- FILTERED = "[FILTERED]".freeze # :nodoc:
6
+ FILTERED = "[FILTERED]" # :nodoc:
7
7
 
8
8
  def filtered_location # :nodoc:
9
9
  if location_filter_match?
@@ -121,7 +121,7 @@ module ActionDispatch
121
121
  # not contained within the headers hash.
122
122
  def env_name(key)
123
123
  key = key.to_s
124
- if key =~ HTTP_HEADER
124
+ if HTTP_HEADER.match?(key)
125
125
  key = key.upcase.tr("-", "_")
126
126
  key = "HTTP_" + key unless CGI_VARIABLES.include?(key)
127
127
  end
@@ -7,6 +7,11 @@ module ActionDispatch
7
7
  module MimeNegotiation
8
8
  extend ActiveSupport::Concern
9
9
 
10
+ RESCUABLE_MIME_FORMAT_ERRORS = [
11
+ ActionController::BadRequest,
12
+ ActionDispatch::Http::Parameters::ParseError,
13
+ ]
14
+
10
15
  included do
11
16
  mattr_accessor :ignore_accept_header, default: false
12
17
  end
@@ -59,7 +64,7 @@ module ActionDispatch
59
64
  fetch_header("action_dispatch.request.formats") do |k|
60
65
  params_readable = begin
61
66
  parameters[:format]
62
- rescue ActionController::BadRequest
67
+ rescue *RESCUABLE_MIME_FORMAT_ERRORS
63
68
  false
64
69
  end
65
70
 
@@ -74,11 +79,6 @@ module ActionDispatch
74
79
  else
75
80
  [Mime[:html]]
76
81
  end
77
-
78
- v = v.select do |format|
79
- format.symbol || format.ref == "*/*"
80
- end
81
-
82
82
  set_header k, v
83
83
  end
84
84
  end
@@ -90,10 +90,7 @@ module ActionDispatch
90
90
  if variant.all? { |v| v.is_a?(Symbol) }
91
91
  @variant = ActiveSupport::ArrayInquirer.new(variant)
92
92
  else
93
- raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols. " \
94
- "For security reasons, never directly set the variant to a user-provided value, " \
95
- "like params[:variant].to_sym. Check user-provided value against a whitelist first, " \
96
- "then set the variant: request.variant = :tablet if params[:variant] == 'tablet'"
93
+ raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols."
97
94
  end
98
95
  end
99
96
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # -*- frozen-string-literal: true -*-
4
-
5
3
  require "singleton"
6
4
  require "active_support/core_ext/string/starts_ends_with"
7
5
 
@@ -74,7 +72,7 @@ module Mime
74
72
  def initialize(index, name, q = nil)
75
73
  @index = index
76
74
  @name = name
77
- q ||= 0.0 if @name == "*/*".freeze # Default wildcard match to end of list.
75
+ q ||= 0.0 if @name == "*/*" # Default wildcard match to end of list.
78
76
  @q = ((q || 1.0).to_f * 100).to_i
79
77
  end
80
78
 
@@ -279,8 +277,6 @@ module Mime
279
277
 
280
278
  def all?; false; end
281
279
 
282
- # TODO Change this to private once we've dropped Ruby 2.2 support.
283
- # Workaround for Ruby 2.2 "private attribute?" warning.
284
280
  protected
285
281
 
286
282
  attr_reader :string, :synonyms
@@ -1,86 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/object/duplicable"
3
+ require "active_support/deprecation/constant_accessor"
4
+ require "active_support/parameter_filter"
4
5
 
5
6
  module ActionDispatch
6
7
  module Http
7
- class ParameterFilter
8
- FILTERED = "[FILTERED]".freeze # :nodoc:
9
-
10
- def initialize(filters = [])
11
- @filters = filters
12
- end
13
-
14
- def filter(params)
15
- compiled_filter.call(params)
16
- end
17
-
18
- private
19
-
20
- def compiled_filter
21
- @compiled_filter ||= CompiledFilter.compile(@filters)
22
- end
23
-
24
- class CompiledFilter # :nodoc:
25
- def self.compile(filters)
26
- return lambda { |params| params.dup } if filters.empty?
27
-
28
- strings, regexps, blocks = [], [], []
29
-
30
- filters.each do |item|
31
- case item
32
- when Proc
33
- blocks << item
34
- when Regexp
35
- regexps << item
36
- else
37
- strings << Regexp.escape(item.to_s)
38
- end
39
- end
40
-
41
- deep_regexps, regexps = regexps.partition { |r| r.to_s.include?("\\.".freeze) }
42
- deep_strings, strings = strings.partition { |s| s.include?("\\.".freeze) }
43
-
44
- regexps << Regexp.new(strings.join("|".freeze), true) unless strings.empty?
45
- deep_regexps << Regexp.new(deep_strings.join("|".freeze), true) unless deep_strings.empty?
46
-
47
- new regexps, deep_regexps, blocks
48
- end
49
-
50
- attr_reader :regexps, :deep_regexps, :blocks
51
-
52
- def initialize(regexps, deep_regexps, blocks)
53
- @regexps = regexps
54
- @deep_regexps = deep_regexps.any? ? deep_regexps : nil
55
- @blocks = blocks
56
- end
57
-
58
- def call(original_params, parents = [])
59
- filtered_params = original_params.class.new
60
-
61
- original_params.each do |key, value|
62
- parents.push(key) if deep_regexps
63
- if regexps.any? { |r| key =~ r }
64
- value = FILTERED
65
- elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| joined =~ r }
66
- value = FILTERED
67
- elsif value.is_a?(Hash)
68
- value = call(value, parents)
69
- elsif value.is_a?(Array)
70
- value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
71
- elsif blocks.any?
72
- key = key.dup if key.duplicable?
73
- value = value.dup if value.duplicable?
74
- blocks.each { |b| b.call(key, value) }
75
- end
76
- parents.pop if deep_regexps
77
-
78
- filtered_params[key] = value
79
- end
80
-
81
- filtered_params
82
- end
83
- end
84
- end
8
+ include ActiveSupport::Deprecation::DeprecatedConstantAccessor
9
+ deprecate_constant "ParameterFilter", "ActiveSupport::ParameterFilter",
10
+ message: "ActionDispatch::Http::ParameterFilter is deprecated and will be removed from Rails 6.1. Use ActiveSupport::ParameterFilter instead."
85
11
  end
86
12
  end
@@ -111,13 +111,23 @@ module ActionDispatch
111
111
  begin
112
112
  strategy.call(raw_post)
113
113
  rescue # JSON or Ruby code block errors.
114
- my_logger = logger || ActiveSupport::Logger.new($stderr)
115
- my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}"
116
-
114
+ log_parse_error_once
117
115
  raise ParseError
118
116
  end
119
117
  end
120
118
 
119
+ def log_parse_error_once
120
+ @parse_error_logged ||= begin
121
+ parse_logger = logger || ActiveSupport::Logger.new($stderr)
122
+ parse_logger.debug <<~MSG.chomp
123
+ Error occurred while parsing request parameters.
124
+ Contents:
125
+
126
+ #{raw_post}
127
+ MSG
128
+ end
129
+ end
130
+
121
131
  def params_parsers
122
132
  ActionDispatch::Request.parameter_parsers
123
133
  end
@@ -136,11 +136,11 @@ module ActionDispatch
136
136
  end
137
137
 
138
138
  def routes # :nodoc:
139
- get_header("action_dispatch.routes".freeze)
139
+ get_header("action_dispatch.routes")
140
140
  end
141
141
 
142
142
  def routes=(routes) # :nodoc:
143
- set_header("action_dispatch.routes".freeze, routes)
143
+ set_header("action_dispatch.routes", routes)
144
144
  end
145
145
 
146
146
  def engine_script_name(_routes) # :nodoc:
@@ -158,11 +158,11 @@ module ActionDispatch
158
158
  end
159
159
 
160
160
  def controller_instance # :nodoc:
161
- get_header("action_controller.instance".freeze)
161
+ get_header("action_controller.instance")
162
162
  end
163
163
 
164
164
  def controller_instance=(controller) # :nodoc:
165
- set_header("action_controller.instance".freeze, controller)
165
+ set_header("action_controller.instance", controller)
166
166
  end
167
167
 
168
168
  def http_auth_salt
@@ -173,7 +173,7 @@ module ActionDispatch
173
173
  # We're treating `nil` as "unset", and we want the default setting to be
174
174
  # `true`. This logic should be extracted to `env_config` and calculated
175
175
  # once.
176
- !(get_header("action_dispatch.show_exceptions".freeze) == false)
176
+ !(get_header("action_dispatch.show_exceptions") == false)
177
177
  end
178
178
 
179
179
  # Returns a symbol form of the #request_method.
@@ -280,10 +280,10 @@ module ActionDispatch
280
280
  end
281
281
 
282
282
  def remote_ip=(remote_ip)
283
- set_header "action_dispatch.remote_ip".freeze, remote_ip
283
+ set_header "action_dispatch.remote_ip", remote_ip
284
284
  end
285
285
 
286
- ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id".freeze # :nodoc:
286
+ ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
287
287
 
288
288
  # Returns the unique request id, which is based on either the X-Request-Id header that can
289
289
  # be generated by a firewall, load balancer, or web server or by the RequestId middleware
@@ -383,9 +383,6 @@ module ActionDispatch
383
383
  end
384
384
  self.request_parameters = Request::Utils.normalize_encode_params(pr)
385
385
  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
386
  rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
390
387
  raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
391
388
  end
@@ -407,18 +404,18 @@ module ActionDispatch
407
404
 
408
405
  def request_parameters=(params)
409
406
  raise if params.nil?
410
- set_header("action_dispatch.request.request_parameters".freeze, params)
407
+ set_header("action_dispatch.request.request_parameters", params)
411
408
  end
412
409
 
413
410
  def logger
414
- get_header("action_dispatch.logger".freeze)
411
+ get_header("action_dispatch.logger")
415
412
  end
416
413
 
417
414
  def commit_flash
418
415
  end
419
416
 
420
417
  def ssl?
421
- super || scheme == "wss".freeze
418
+ super || scheme == "wss"
422
419
  end
423
420
 
424
421
  private
@@ -78,9 +78,9 @@ 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
81
+ CONTENT_TYPE = "Content-Type"
82
+ SET_COOKIE = "Set-Cookie"
83
+ LOCATION = "Location"
84
84
  NO_CONTENT_CODES = [100, 101, 102, 204, 205, 304]
85
85
 
86
86
  cattr_accessor :default_charset, default: "utf-8"
@@ -105,7 +105,7 @@ module ActionDispatch # :nodoc:
105
105
 
106
106
  def body
107
107
  @str_body ||= begin
108
- buf = "".dup
108
+ buf = +""
109
109
  each { |chunk| buf << chunk }
110
110
  buf
111
111
  end
@@ -224,16 +224,6 @@ module ActionDispatch # :nodoc:
224
224
  @status = Rack::Utils.status_code(status)
225
225
  end
226
226
 
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
227
  # Sets the HTTP response's content MIME type. For example, in the controller
238
228
  # you could write this:
239
229
  #
@@ -242,7 +232,17 @@ module ActionDispatch # :nodoc:
242
232
  # If a character set has been defined for this response (see charset=) then
243
233
  # the character set information will also be included in the content type
244
234
  # information.
235
+ def content_type=(content_type)
236
+ return unless content_type
237
+ new_header_info = parse_content_type(content_type.to_s)
238
+ prev_header_info = parsed_content_type_header
239
+ charset = new_header_info.charset || prev_header_info.charset
240
+ charset ||= self.class.default_charset unless prev_header_info.mime_type
241
+ set_content_type new_header_info.mime_type, charset
242
+ end
245
243
 
244
+ # Content type of response.
245
+ # It returns just MIME type and does NOT contain charset part.
246
246
  def content_type
247
247
  parsed_content_type_header.mime_type
248
248
  end
@@ -65,6 +65,11 @@ module ActionDispatch
65
65
  @tempfile.path
66
66
  end
67
67
 
68
+ # Shortcut for +tempfile.to_path+.
69
+ def to_path
70
+ @tempfile.to_path
71
+ end
72
+
68
73
  # Shortcut for +tempfile.rewind+.
69
74
  def rewind
70
75
  @tempfile.rewind
@@ -67,7 +67,7 @@ module ActionDispatch
67
67
  end
68
68
 
69
69
  def path_for(options)
70
- path = options[:script_name].to_s.chomp("/".freeze)
70
+ path = options[:script_name].to_s.chomp("/")
71
71
  path << options[:path] if options.key?(:path)
72
72
 
73
73
  add_trailing_slash(path) if options[:trailing_slash]
@@ -79,108 +79,108 @@ module ActionDispatch
79
79
 
80
80
  private
81
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 !~ 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
+ "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
155
152
 
156
- tld_length = options[:tld_length] || @@tld_length
157
- subdomain = options.fetch :subdomain, true
158
- domain = options[:domain]
153
+ def normalize_host(_host, options)
154
+ return _host unless named_host?(_host)
159
155
 
160
- host = "".dup
161
- if subdomain == true
162
- return _host if domain.nil?
156
+ tld_length = options[:tld_length] || @@tld_length
157
+ subdomain = options.fetch :subdomain, true
158
+ domain = options[:domain]
163
159
 
164
- host << extract_subdomains_from(_host, tld_length).join(".")
165
- elsif subdomain
166
- host << subdomain.to_param
160
+ host = +""
161
+ if subdomain == true
162
+ return _host if domain.nil?
163
+
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