actionpack 4.2.10 → 7.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 (202) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +86 -600
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +13 -14
  5. data/lib/abstract_controller/asset_paths.rb +5 -1
  6. data/lib/abstract_controller/base.rb +166 -136
  7. data/lib/abstract_controller/caching/fragments.rb +149 -0
  8. data/lib/abstract_controller/caching.rb +68 -0
  9. data/lib/abstract_controller/callbacks.rb +126 -57
  10. data/lib/abstract_controller/collector.rb +13 -15
  11. data/lib/abstract_controller/deprecator.rb +9 -0
  12. data/lib/abstract_controller/error.rb +8 -0
  13. data/lib/abstract_controller/helpers.rb +181 -132
  14. data/lib/abstract_controller/logger.rb +5 -1
  15. data/lib/abstract_controller/railties/routes_helpers.rb +10 -3
  16. data/lib/abstract_controller/rendering.rb +56 -56
  17. data/lib/abstract_controller/translation.rb +29 -15
  18. data/lib/abstract_controller/url_for.rb +15 -11
  19. data/lib/abstract_controller.rb +21 -5
  20. data/lib/action_controller/api/api_rendering.rb +18 -0
  21. data/lib/action_controller/api.rb +154 -0
  22. data/lib/action_controller/base.rb +219 -155
  23. data/lib/action_controller/caching.rb +28 -68
  24. data/lib/action_controller/deprecator.rb +9 -0
  25. data/lib/action_controller/form_builder.rb +55 -0
  26. data/lib/action_controller/log_subscriber.rb +35 -22
  27. data/lib/action_controller/metal/allow_browser.rb +119 -0
  28. data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
  29. data/lib/action_controller/metal/conditional_get.rb +259 -122
  30. data/lib/action_controller/metal/content_security_policy.rb +86 -0
  31. data/lib/action_controller/metal/cookies.rb +9 -5
  32. data/lib/action_controller/metal/data_streaming.rb +87 -104
  33. data/lib/action_controller/metal/default_headers.rb +21 -0
  34. data/lib/action_controller/metal/etag_with_flash.rb +22 -0
  35. data/lib/action_controller/metal/etag_with_template_digest.rb +35 -26
  36. data/lib/action_controller/metal/exceptions.rb +71 -24
  37. data/lib/action_controller/metal/flash.rb +26 -19
  38. data/lib/action_controller/metal/head.rb +45 -36
  39. data/lib/action_controller/metal/helpers.rb +80 -64
  40. data/lib/action_controller/metal/http_authentication.rb +297 -244
  41. data/lib/action_controller/metal/implicit_render.rb +57 -9
  42. data/lib/action_controller/metal/instrumentation.rb +76 -64
  43. data/lib/action_controller/metal/live.rb +238 -176
  44. data/lib/action_controller/metal/logging.rb +22 -0
  45. data/lib/action_controller/metal/mime_responds.rb +177 -166
  46. data/lib/action_controller/metal/parameter_encoding.rb +84 -0
  47. data/lib/action_controller/metal/params_wrapper.rb +145 -118
  48. data/lib/action_controller/metal/permissions_policy.rb +38 -0
  49. data/lib/action_controller/metal/rate_limiting.rb +62 -0
  50. data/lib/action_controller/metal/redirecting.rb +203 -64
  51. data/lib/action_controller/metal/renderers.rb +108 -65
  52. data/lib/action_controller/metal/rendering.rb +216 -56
  53. data/lib/action_controller/metal/request_forgery_protection.rb +496 -163
  54. data/lib/action_controller/metal/rescue.rb +19 -21
  55. data/lib/action_controller/metal/streaming.rb +179 -138
  56. data/lib/action_controller/metal/strong_parameters.rb +1058 -382
  57. data/lib/action_controller/metal/testing.rb +11 -17
  58. data/lib/action_controller/metal/url_for.rb +37 -21
  59. data/lib/action_controller/metal.rb +236 -138
  60. data/lib/action_controller/railtie.rb +89 -11
  61. data/lib/action_controller/railties/helpers.rb +5 -1
  62. data/lib/action_controller/renderer.rb +161 -0
  63. data/lib/action_controller/template_assertions.rb +13 -0
  64. data/lib/action_controller/test_case.rb +425 -497
  65. data/lib/action_controller.rb +44 -22
  66. data/lib/action_dispatch/constants.rb +34 -0
  67. data/lib/action_dispatch/deprecator.rb +9 -0
  68. data/lib/action_dispatch/http/cache.rb +119 -63
  69. data/lib/action_dispatch/http/content_disposition.rb +47 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +364 -0
  71. data/lib/action_dispatch/http/filter_parameters.rb +36 -34
  72. data/lib/action_dispatch/http/filter_redirect.rb +24 -12
  73. data/lib/action_dispatch/http/headers.rb +66 -31
  74. data/lib/action_dispatch/http/mime_negotiation.rb +106 -75
  75. data/lib/action_dispatch/http/mime_type.rb +196 -136
  76. data/lib/action_dispatch/http/mime_types.rb +25 -7
  77. data/lib/action_dispatch/http/parameters.rb +97 -45
  78. data/lib/action_dispatch/http/permissions_policy.rb +187 -0
  79. data/lib/action_dispatch/http/rack_cache.rb +6 -0
  80. data/lib/action_dispatch/http/request.rb +299 -170
  81. data/lib/action_dispatch/http/response.rb +311 -160
  82. data/lib/action_dispatch/http/upload.rb +52 -23
  83. data/lib/action_dispatch/http/url.rb +201 -125
  84. data/lib/action_dispatch/journey/formatter.rb +110 -50
  85. data/lib/action_dispatch/journey/gtg/builder.rb +37 -50
  86. data/lib/action_dispatch/journey/gtg/simulator.rb +20 -17
  87. data/lib/action_dispatch/journey/gtg/transition_table.rb +96 -36
  88. data/lib/action_dispatch/journey/nfa/dot.rb +5 -14
  89. data/lib/action_dispatch/journey/nodes/node.rb +100 -20
  90. data/lib/action_dispatch/journey/parser.rb +19 -17
  91. data/lib/action_dispatch/journey/parser.y +4 -3
  92. data/lib/action_dispatch/journey/parser_extras.rb +14 -4
  93. data/lib/action_dispatch/journey/path/pattern.rb +79 -63
  94. data/lib/action_dispatch/journey/route.rb +108 -44
  95. data/lib/action_dispatch/journey/router/utils.rb +41 -29
  96. data/lib/action_dispatch/journey/router.rb +64 -57
  97. data/lib/action_dispatch/journey/routes.rb +23 -21
  98. data/lib/action_dispatch/journey/scanner.rb +28 -17
  99. data/lib/action_dispatch/journey/visitors.rb +100 -54
  100. data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
  101. data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
  102. data/lib/action_dispatch/journey.rb +7 -5
  103. data/lib/action_dispatch/log_subscriber.rb +25 -0
  104. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  105. data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
  106. data/lib/action_dispatch/middleware/callbacks.rb +7 -6
  107. data/lib/action_dispatch/middleware/cookies.rb +471 -328
  108. data/lib/action_dispatch/middleware/debug_exceptions.rb +149 -66
  109. data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
  110. data/lib/action_dispatch/middleware/debug_view.rb +73 -0
  111. data/lib/action_dispatch/middleware/exception_wrapper.rb +275 -73
  112. data/lib/action_dispatch/middleware/executor.rb +32 -0
  113. data/lib/action_dispatch/middleware/flash.rb +143 -101
  114. data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
  115. data/lib/action_dispatch/middleware/public_exceptions.rb +36 -27
  116. data/lib/action_dispatch/middleware/reloader.rb +10 -92
  117. data/lib/action_dispatch/middleware/remote_ip.rb +133 -107
  118. data/lib/action_dispatch/middleware/request_id.rb +29 -15
  119. data/lib/action_dispatch/middleware/server_timing.rb +78 -0
  120. data/lib/action_dispatch/middleware/session/abstract_store.rb +49 -27
  121. data/lib/action_dispatch/middleware/session/cache_store.rb +33 -16
  122. data/lib/action_dispatch/middleware/session/cookie_store.rb +86 -80
  123. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -3
  124. data/lib/action_dispatch/middleware/show_exceptions.rb +66 -36
  125. data/lib/action_dispatch/middleware/ssl.rb +134 -36
  126. data/lib/action_dispatch/middleware/stack.rb +109 -44
  127. data/lib/action_dispatch/middleware/static.rb +159 -90
  128. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +7 -24
  132. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  133. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
  136. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
  137. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
  138. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -7
  139. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +3 -3
  140. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
  141. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
  142. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +139 -15
  143. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
  144. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  145. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +6 -6
  146. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +7 -7
  147. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +9 -9
  148. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  149. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
  150. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  151. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +7 -4
  152. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +125 -93
  153. data/lib/action_dispatch/railtie.rb +44 -16
  154. data/lib/action_dispatch/request/session.rb +159 -69
  155. data/lib/action_dispatch/request/utils.rb +97 -23
  156. data/lib/action_dispatch/routing/endpoint.rb +11 -2
  157. data/lib/action_dispatch/routing/inspector.rb +195 -106
  158. data/lib/action_dispatch/routing/mapper.rb +1338 -955
  159. data/lib/action_dispatch/routing/polymorphic_routes.rb +234 -201
  160. data/lib/action_dispatch/routing/redirection.rb +78 -51
  161. data/lib/action_dispatch/routing/route_set.rb +460 -374
  162. data/lib/action_dispatch/routing/routes_proxy.rb +36 -12
  163. data/lib/action_dispatch/routing/url_for.rb +172 -124
  164. data/lib/action_dispatch/routing.rb +159 -158
  165. data/lib/action_dispatch/system_test_case.rb +206 -0
  166. data/lib/action_dispatch/system_testing/browser.rb +84 -0
  167. data/lib/action_dispatch/system_testing/driver.rb +85 -0
  168. data/lib/action_dispatch/system_testing/server.rb +33 -0
  169. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
  170. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
  171. data/lib/action_dispatch/testing/assertion_response.rb +48 -0
  172. data/lib/action_dispatch/testing/assertions/response.rb +71 -39
  173. data/lib/action_dispatch/testing/assertions/routing.rb +228 -103
  174. data/lib/action_dispatch/testing/assertions.rb +9 -6
  175. data/lib/action_dispatch/testing/integration.rb +486 -306
  176. data/lib/action_dispatch/testing/request_encoder.rb +60 -0
  177. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  178. data/lib/action_dispatch/testing/test_process.rb +35 -22
  179. data/lib/action_dispatch/testing/test_request.rb +29 -34
  180. data/lib/action_dispatch/testing/test_response.rb +48 -15
  181. data/lib/action_dispatch.rb +82 -40
  182. data/lib/action_pack/gem_version.rb +8 -4
  183. data/lib/action_pack/version.rb +6 -2
  184. data/lib/action_pack.rb +21 -18
  185. metadata +146 -56
  186. data/lib/action_controller/caching/fragments.rb +0 -103
  187. data/lib/action_controller/metal/force_ssl.rb +0 -97
  188. data/lib/action_controller/metal/hide_actions.rb +0 -40
  189. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  190. data/lib/action_controller/middleware.rb +0 -39
  191. data/lib/action_controller/model_naming.rb +0 -12
  192. data/lib/action_dispatch/http/parameter_filter.rb +0 -72
  193. data/lib/action_dispatch/journey/backwards.rb +0 -5
  194. data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
  195. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
  196. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
  197. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  198. data/lib/action_dispatch/middleware/params_parser.rb +0 -60
  199. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +0 -27
  200. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  201. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  202. data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,13 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
1
5
  module ActionDispatch
2
6
  module Http
7
+ # # Action Dispatch HTTP UploadedFile
8
+ #
3
9
  # Models uploaded files.
4
10
  #
5
- # The actual file is accessible via the +tempfile+ accessor, though some
6
- # of its interface is available directly for convenience.
11
+ # The actual file is accessible via the `tempfile` accessor, though some of its
12
+ # interface is available directly for convenience.
7
13
  #
8
- # Uploaded files are temporary files whose lifespan is one request. When
9
- # the object is finalized Ruby unlinks the file, so there is no need to
10
- # clean them with a separate maintenance task.
14
+ # Uploaded files are temporary files whose lifespan is one request. When the
15
+ # object is finalized Ruby unlinks the file, so there is no need to clean them
16
+ # with a separate maintenance task.
11
17
  class UploadedFile
12
18
  # The basename of the file in the client.
13
19
  attr_accessor :original_filename
@@ -15,64 +21,87 @@ module ActionDispatch
15
21
  # A string with the MIME type of the file.
16
22
  attr_accessor :content_type
17
23
 
18
- # A +Tempfile+ object with the actual uploaded file. Note that some of
19
- # its interface is available directly.
24
+ # A `Tempfile` object with the actual uploaded file. Note that some of its
25
+ # interface is available directly.
20
26
  attr_accessor :tempfile
21
- alias :to_io :tempfile
22
27
 
23
28
  # A string with the headers of the multipart request.
24
29
  attr_accessor :headers
25
30
 
26
31
  def initialize(hash) # :nodoc:
27
- @tempfile = hash[:tempfile]
28
- raise(ArgumentError, ':tempfile is required') unless @tempfile
32
+ @tempfile = hash[:tempfile]
33
+ raise(ArgumentError, ":tempfile is required") unless @tempfile
34
+
35
+ @content_type = hash[:type]
36
+
37
+ if hash[:filename]
38
+ @original_filename = hash[:filename].dup
29
39
 
30
- @original_filename = hash[:filename]
31
- if @original_filename
32
40
  begin
33
41
  @original_filename.encode!(Encoding::UTF_8)
34
42
  rescue EncodingError
35
43
  @original_filename.force_encoding(Encoding::UTF_8)
36
44
  end
45
+ else
46
+ @original_filename = nil
47
+ end
48
+
49
+ if hash[:head]
50
+ @headers = hash[:head].dup
51
+
52
+ begin
53
+ @headers.encode!(Encoding::UTF_8)
54
+ rescue EncodingError
55
+ @headers.force_encoding(Encoding::UTF_8)
56
+ end
57
+ else
58
+ @headers = nil
37
59
  end
38
- @content_type = hash[:type]
39
- @headers = hash[:head]
40
60
  end
41
61
 
42
- # Shortcut for +tempfile.read+.
43
- def read(length=nil, buffer=nil)
62
+ # Shortcut for `tempfile.read`.
63
+ def read(length = nil, buffer = nil)
44
64
  @tempfile.read(length, buffer)
45
65
  end
46
66
 
47
- # Shortcut for +tempfile.open+.
67
+ # Shortcut for `tempfile.open`.
48
68
  def open
49
69
  @tempfile.open
50
70
  end
51
71
 
52
- # Shortcut for +tempfile.close+.
53
- def close(unlink_now=false)
72
+ # Shortcut for `tempfile.close`.
73
+ def close(unlink_now = false)
54
74
  @tempfile.close(unlink_now)
55
75
  end
56
76
 
57
- # Shortcut for +tempfile.path+.
77
+ # Shortcut for `tempfile.path`.
58
78
  def path
59
79
  @tempfile.path
60
80
  end
61
81
 
62
- # Shortcut for +tempfile.rewind+.
82
+ # Shortcut for `tempfile.to_path`.
83
+ def to_path
84
+ @tempfile.to_path
85
+ end
86
+
87
+ # Shortcut for `tempfile.rewind`.
63
88
  def rewind
64
89
  @tempfile.rewind
65
90
  end
66
91
 
67
- # Shortcut for +tempfile.size+.
92
+ # Shortcut for `tempfile.size`.
68
93
  def size
69
94
  @tempfile.size
70
95
  end
71
96
 
72
- # Shortcut for +tempfile.eof?+.
97
+ # Shortcut for `tempfile.eof?`.
73
98
  def eof?
74
99
  @tempfile.eof?
75
100
  end
101
+
102
+ def to_io
103
+ @tempfile.to_io
104
+ end
76
105
  end
77
106
  end
78
107
  end
@@ -1,5 +1,8 @@
1
- require 'active_support/core_ext/module/attribute_accessors'
2
- require 'active_support/core_ext/hash/slice'
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "active_support/core_ext/module/attribute_accessors"
3
6
 
4
7
  module ActionDispatch
5
8
  module Http
@@ -8,14 +11,26 @@ module ActionDispatch
8
11
  HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
9
12
  PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
10
13
 
11
- mattr_accessor :tld_length
12
- self.tld_length = 1
14
+ mattr_accessor :secure_protocol, default: false
15
+ mattr_accessor :tld_length, default: 1
13
16
 
14
17
  class << self
18
+ # Returns the domain part of a host given the domain level.
19
+ #
20
+ # # Top-level domain example
21
+ # extract_domain('www.example.com', 1) # => "example.com"
22
+ # # Second-level domain example
23
+ # extract_domain('dev.www.example.co.uk', 2) # => "example.co.uk"
15
24
  def extract_domain(host, tld_length)
16
25
  extract_domain_from(host, tld_length) if named_host?(host)
17
26
  end
18
27
 
28
+ # Returns the subdomains of a host as an Array given the domain level.
29
+ #
30
+ # # Top-level domain example
31
+ # extract_subdomains('www.example.com', 1) # => ["www"]
32
+ # # Second-level domain example
33
+ # extract_subdomains('dev.www.example.co.uk', 2) # => ["dev", "www"]
19
34
  def extract_subdomains(host, tld_length)
20
35
  if named_host?(host)
21
36
  extract_subdomains_from(host, tld_length)
@@ -24,8 +39,14 @@ module ActionDispatch
24
39
  end
25
40
  end
26
41
 
42
+ # Returns the subdomains of a host as a String given the domain level.
43
+ #
44
+ # # Top-level domain example
45
+ # extract_subdomain('www.example.com', 1) # => "www"
46
+ # # Second-level domain example
47
+ # extract_subdomain('dev.www.example.co.uk', 2) # => "dev.www"
27
48
  def extract_subdomain(host, tld_length)
28
- extract_subdomains(host, tld_length).join('.')
49
+ extract_subdomains(host, tld_length).join(".")
29
50
  end
30
51
 
31
52
  def url_for(options)
@@ -42,17 +63,18 @@ module ActionDispatch
42
63
  port = options[:port]
43
64
 
44
65
  unless host
45
- raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true'
66
+ raise ArgumentError, "Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true"
46
67
  end
47
68
 
48
69
  build_host_url(host, port, protocol, options, path_for(options))
49
70
  end
50
71
 
51
72
  def path_for(options)
52
- path = options[:script_name].to_s.chomp("/")
73
+ path = options[:script_name].to_s.chomp("/")
53
74
  path << options[:path] if options.key?(:path)
54
75
 
55
- add_trailing_slash(path) if options[:trailing_slash]
76
+ path = "/" if options[:trailing_slash] && path.blank?
77
+
56
78
  add_params(path, options[:params]) if options.key?(:params)
57
79
  add_anchor(path, options[:anchor]) if options.key?(:anchor)
58
80
 
@@ -60,206 +82,260 @@ module ActionDispatch
60
82
  end
61
83
 
62
84
  private
63
-
64
- def add_params(path, params)
65
- params = { params: params } unless params.is_a?(Hash)
66
- params.reject! { |_,v| v.to_param.nil? }
67
- path << "?#{params.to_query}" unless params.empty?
68
- end
69
-
70
- def add_anchor(path, anchor)
71
- if anchor
72
- path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
85
+ def add_params(path, params)
86
+ params = { params: params } unless params.is_a?(Hash)
87
+ params.reject! { |_, v| v.to_param.nil? }
88
+ query = params.to_query
89
+ path << "?#{query}" unless query.empty?
73
90
  end
74
- end
75
91
 
76
- def extract_domain_from(host, tld_length)
77
- host.split('.').last(1 + tld_length).join('.')
78
- end
79
-
80
- def extract_subdomains_from(host, tld_length)
81
- parts = host.split('.')
82
- parts[0..-(tld_length + 2)]
83
- end
92
+ def add_anchor(path, anchor)
93
+ if anchor
94
+ path << "##{Journey::Router::Utils.escape_fragment(anchor.to_param)}"
95
+ end
96
+ end
84
97
 
85
- def add_trailing_slash(path)
86
- # includes querysting
87
- if path.include?('?')
88
- path.sub!(/\?/, '/\&')
89
- # does not have a .format
90
- elsif !path.include?(".")
91
- path.sub!(/[^\/]\z|\A\z/, '\&/')
98
+ def extract_domain_from(host, tld_length)
99
+ host.split(".").last(1 + tld_length).join(".")
92
100
  end
93
- end
94
101
 
95
- def build_host_url(host, port, protocol, options, path)
96
- if match = host.match(HOST_REGEXP)
97
- protocol ||= match[1] unless protocol == false
98
- host = match[2]
99
- port = match[3] unless options.key? :port
102
+ def extract_subdomains_from(host, tld_length)
103
+ parts = host.split(".")
104
+ parts[0..-(tld_length + 2)]
100
105
  end
101
106
 
102
- protocol = normalize_protocol protocol
103
- host = normalize_host(host, options)
107
+ def build_host_url(host, port, protocol, options, path)
108
+ if match = host.match(HOST_REGEXP)
109
+ protocol ||= match[1] unless protocol == false
110
+ host = match[2]
111
+ port = match[3] unless options.key? :port
112
+ end
104
113
 
105
- result = protocol.dup
114
+ protocol = normalize_protocol protocol
115
+ host = normalize_host(host, options)
106
116
 
107
- if options[:user] && options[:password]
108
- result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
109
- end
117
+ result = protocol.dup
110
118
 
111
- result << host
112
- normalize_port(port, protocol) { |normalized_port|
113
- result << ":#{normalized_port}"
114
- }
119
+ if options[:user] && options[:password]
120
+ result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
121
+ end
115
122
 
116
- result.concat path
117
- end
123
+ result << host
124
+ normalize_port(port, protocol) { |normalized_port|
125
+ result << ":#{normalized_port}"
126
+ }
118
127
 
119
- def named_host?(host)
120
- IP_HOST_REGEXP !~ host
121
- end
128
+ result.concat path
129
+ end
122
130
 
123
- def normalize_protocol(protocol)
124
- case protocol
125
- when nil
126
- "http://"
127
- when false, "//"
128
- "//"
129
- when PROTOCOL_REGEXP
130
- "#{$1}://"
131
- else
132
- raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
131
+ def named_host?(host)
132
+ !IP_HOST_REGEXP.match?(host)
133
133
  end
134
- end
135
134
 
136
- def normalize_host(_host, options)
137
- return _host unless named_host?(_host)
135
+ def normalize_protocol(protocol)
136
+ case protocol
137
+ when nil
138
+ secure_protocol ? "https://" : "http://"
139
+ when false, "//"
140
+ "//"
141
+ when PROTOCOL_REGEXP
142
+ "#{$1}://"
143
+ else
144
+ raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
145
+ end
146
+ end
147
+
148
+ def normalize_host(_host, options)
149
+ return _host unless named_host?(_host)
138
150
 
139
- tld_length = options[:tld_length] || @@tld_length
140
- subdomain = options.fetch :subdomain, true
141
- domain = options[:domain]
151
+ tld_length = options[:tld_length] || @@tld_length
152
+ subdomain = options.fetch :subdomain, true
153
+ domain = options[:domain]
142
154
 
143
- host = ""
144
- if subdomain == true
145
- return _host if domain.nil?
155
+ host = +""
156
+ if subdomain == true
157
+ return _host if domain.nil?
146
158
 
147
- host << extract_subdomains_from(_host, tld_length).join('.')
148
- elsif subdomain
149
- host << subdomain.to_param
159
+ host << extract_subdomains_from(_host, tld_length).join(".")
160
+ elsif subdomain
161
+ host << subdomain.to_param
162
+ end
163
+ host << "." unless host.empty?
164
+ host << (domain || extract_domain_from(_host, tld_length))
165
+ host
150
166
  end
151
- host << "." unless host.empty?
152
- host << (domain || extract_domain_from(_host, tld_length))
153
- host
154
- end
155
167
 
156
- def normalize_port(port, protocol)
157
- return unless port
168
+ def normalize_port(port, protocol)
169
+ return unless port
158
170
 
159
- case protocol
160
- when "//" then yield port
161
- when "https://"
162
- yield port unless port.to_i == 443
163
- else
164
- yield port unless port.to_i == 80
171
+ case protocol
172
+ when "//" then yield port
173
+ when "https://"
174
+ yield port unless port.to_i == 443
175
+ else
176
+ yield port unless port.to_i == 80
177
+ end
165
178
  end
166
- end
167
179
  end
168
180
 
169
- def initialize(env)
181
+ def initialize
170
182
  super
171
183
  @protocol = nil
172
184
  @port = nil
173
185
  end
174
186
 
175
187
  # Returns the complete URL used for this request.
188
+ #
189
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
190
+ # req.url # => "http://example.com"
176
191
  def url
177
192
  protocol + host_with_port + fullpath
178
193
  end
179
194
 
180
195
  # Returns 'https://' if this is an SSL request and 'http://' otherwise.
196
+ #
197
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
198
+ # req.protocol # => "http://"
199
+ #
200
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on'
201
+ # req.protocol # => "https://"
181
202
  def protocol
182
- @protocol ||= ssl? ? 'https://' : 'http://'
203
+ @protocol ||= ssl? ? "https://" : "http://"
183
204
  end
184
205
 
185
- # Returns the \host for this request, such as "example.com".
206
+ # Returns the host and port for this request, such as "example.com:8080".
207
+ #
208
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
209
+ # req.raw_host_with_port # => "example.com"
210
+ #
211
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
212
+ # req.raw_host_with_port # => "example.com:80"
213
+ #
214
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
215
+ # req.raw_host_with_port # => "example.com:8080"
186
216
  def raw_host_with_port
187
- if forwarded = env["HTTP_X_FORWARDED_HOST"].presence
217
+ if forwarded = x_forwarded_host.presence
188
218
  forwarded.split(/,\s?/).last
189
219
  else
190
- env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
220
+ get_header("HTTP_HOST") || "#{server_name}:#{get_header('SERVER_PORT')}"
191
221
  end
192
222
  end
193
223
 
194
- # Returns the host for this request, such as example.com.
224
+ # Returns the host for this request, such as "example.com".
225
+ #
226
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
227
+ # req.host # => "example.com"
195
228
  def host
196
- raw_host_with_port.sub(/:\d+$/, '')
229
+ raw_host_with_port.sub(/:\d+$/, "")
197
230
  end
198
231
 
199
- # Returns a \host:\port string for this request, such as "example.com" or
200
- # "example.com:8080".
232
+ # Returns a host:port string for this request, such as "example.com" or
233
+ # "example.com:8080". Port is only included if it is not a default port (80 or
234
+ # 443)
235
+ #
236
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
237
+ # req.host_with_port # => "example.com"
238
+ #
239
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
240
+ # req.host_with_port # => "example.com"
241
+ #
242
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
243
+ # req.host_with_port # => "example.com:8080"
201
244
  def host_with_port
202
245
  "#{host}#{port_string}"
203
246
  end
204
247
 
205
248
  # Returns the port number of this request as an integer.
249
+ #
250
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
251
+ # req.port # => 80
252
+ #
253
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
254
+ # req.port # => 8080
206
255
  def port
207
- @port ||= begin
208
- if raw_host_with_port =~ /:(\d+)$/
209
- $1.to_i
210
- else
211
- standard_port
212
- end
256
+ @port ||= if raw_host_with_port =~ /:(\d+)$/
257
+ $1.to_i
258
+ else
259
+ standard_port
213
260
  end
214
261
  end
215
262
 
216
- # Returns the standard \port number for this request's protocol.
263
+ # Returns the standard port number for this request's protocol.
264
+ #
265
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
266
+ # req.standard_port # => 80
217
267
  def standard_port
218
- case protocol
219
- when 'https://' then 443
220
- else 80
268
+ if "https://" == protocol
269
+ 443
270
+ else
271
+ 80
221
272
  end
222
273
  end
223
274
 
224
275
  # Returns whether this request is using the standard port
276
+ #
277
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
278
+ # req.standard_port? # => true
279
+ #
280
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
281
+ # req.standard_port? # => false
225
282
  def standard_port?
226
283
  port == standard_port
227
284
  end
228
285
 
229
- # Returns a number \port suffix like 8080 if the \port number of this request
230
- # is not the default HTTP \port 80 or HTTPS \port 443.
286
+ # Returns a number port suffix like 8080 if the port number of this request is
287
+ # not the default HTTP port 80 or HTTPS port 443.
288
+ #
289
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
290
+ # req.optional_port # => nil
291
+ #
292
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
293
+ # req.optional_port # => 8080
231
294
  def optional_port
232
295
  standard_port? ? nil : port
233
296
  end
234
297
 
235
- # Returns a string \port suffix, including colon, like ":8080" if the \port
236
- # number of this request is not the default HTTP \port 80 or HTTPS \port 443.
298
+ # Returns a string port suffix, including colon, like ":8080" if the port number
299
+ # of this request is not the default HTTP port 80 or HTTPS port 443.
300
+ #
301
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
302
+ # req.port_string # => ""
303
+ #
304
+ # req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
305
+ # req.port_string # => ":8080"
237
306
  def port_string
238
- standard_port? ? '' : ":#{port}"
307
+ standard_port? ? "" : ":#{port}"
239
308
  end
240
309
 
310
+ # Returns the requested port, such as 8080, based on SERVER_PORT
311
+ #
312
+ # req = ActionDispatch::Request.new 'SERVER_PORT' => '80'
313
+ # req.server_port # => 80
314
+ #
315
+ # req = ActionDispatch::Request.new 'SERVER_PORT' => '8080'
316
+ # req.server_port # => 8080
241
317
  def server_port
242
- @env['SERVER_PORT'].to_i
318
+ get_header("SERVER_PORT").to_i
243
319
  end
244
320
 
245
- # Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
246
- # a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
321
+ # Returns the domain part of a host, such as "rubyonrails.org" in
322
+ # "www.rubyonrails.org". You can specify a different `tld_length`, such as 2 to
323
+ # catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
247
324
  def domain(tld_length = @@tld_length)
248
325
  ActionDispatch::Http::URL.extract_domain(host, tld_length)
249
326
  end
250
327
 
251
- # Returns all the \subdomains as an array, so <tt>["dev", "www"]</tt> would be
252
- # returned for "dev.www.rubyonrails.org". You can specify a different <tt>tld_length</tt>,
253
- # such as 2 to catch <tt>["www"]</tt> instead of <tt>["www", "rubyonrails"]</tt>
254
- # in "www.rubyonrails.co.uk".
328
+ # Returns all the subdomains as an array, so `["dev", "www"]` would be returned
329
+ # for "dev.www.rubyonrails.org". You can specify a different `tld_length`, such
330
+ # as 2 to catch `["www"]` instead of `["www", "rubyonrails"]` in
331
+ # "www.rubyonrails.co.uk".
255
332
  def subdomains(tld_length = @@tld_length)
256
333
  ActionDispatch::Http::URL.extract_subdomains(host, tld_length)
257
334
  end
258
335
 
259
- # Returns all the \subdomains as a string, so <tt>"dev.www"</tt> would be
260
- # returned for "dev.www.rubyonrails.org". You can specify a different <tt>tld_length</tt>,
261
- # such as 2 to catch <tt>"www"</tt> instead of <tt>"www.rubyonrails"</tt>
262
- # in "www.rubyonrails.co.uk".
336
+ # Returns all the subdomains as a string, so `"dev.www"` would be returned for
337
+ # "dev.www.rubyonrails.org". You can specify a different `tld_length`, such as 2
338
+ # to catch `"www"` instead of `"www.rubyonrails"` in "www.rubyonrails.co.uk".
263
339
  def subdomain(tld_length = @@tld_length)
264
340
  ActionDispatch::Http::URL.extract_subdomain(host, tld_length)
265
341
  end