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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +86 -600
- data/MIT-LICENSE +1 -1
- data/README.rdoc +13 -14
- data/lib/abstract_controller/asset_paths.rb +5 -1
- data/lib/abstract_controller/base.rb +166 -136
- data/lib/abstract_controller/caching/fragments.rb +149 -0
- data/lib/abstract_controller/caching.rb +68 -0
- data/lib/abstract_controller/callbacks.rb +126 -57
- data/lib/abstract_controller/collector.rb +13 -15
- data/lib/abstract_controller/deprecator.rb +9 -0
- data/lib/abstract_controller/error.rb +8 -0
- data/lib/abstract_controller/helpers.rb +181 -132
- data/lib/abstract_controller/logger.rb +5 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +10 -3
- data/lib/abstract_controller/rendering.rb +56 -56
- data/lib/abstract_controller/translation.rb +29 -15
- data/lib/abstract_controller/url_for.rb +15 -11
- data/lib/abstract_controller.rb +21 -5
- data/lib/action_controller/api/api_rendering.rb +18 -0
- data/lib/action_controller/api.rb +154 -0
- data/lib/action_controller/base.rb +219 -155
- data/lib/action_controller/caching.rb +28 -68
- data/lib/action_controller/deprecator.rb +9 -0
- data/lib/action_controller/form_builder.rb +55 -0
- data/lib/action_controller/log_subscriber.rb +35 -22
- data/lib/action_controller/metal/allow_browser.rb +119 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
- data/lib/action_controller/metal/conditional_get.rb +259 -122
- data/lib/action_controller/metal/content_security_policy.rb +86 -0
- data/lib/action_controller/metal/cookies.rb +9 -5
- data/lib/action_controller/metal/data_streaming.rb +87 -104
- data/lib/action_controller/metal/default_headers.rb +21 -0
- data/lib/action_controller/metal/etag_with_flash.rb +22 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +35 -26
- data/lib/action_controller/metal/exceptions.rb +71 -24
- data/lib/action_controller/metal/flash.rb +26 -19
- data/lib/action_controller/metal/head.rb +45 -36
- data/lib/action_controller/metal/helpers.rb +80 -64
- data/lib/action_controller/metal/http_authentication.rb +297 -244
- data/lib/action_controller/metal/implicit_render.rb +57 -9
- data/lib/action_controller/metal/instrumentation.rb +76 -64
- data/lib/action_controller/metal/live.rb +238 -176
- data/lib/action_controller/metal/logging.rb +22 -0
- data/lib/action_controller/metal/mime_responds.rb +177 -166
- data/lib/action_controller/metal/parameter_encoding.rb +84 -0
- data/lib/action_controller/metal/params_wrapper.rb +145 -118
- data/lib/action_controller/metal/permissions_policy.rb +38 -0
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +203 -64
- data/lib/action_controller/metal/renderers.rb +108 -65
- data/lib/action_controller/metal/rendering.rb +216 -56
- data/lib/action_controller/metal/request_forgery_protection.rb +496 -163
- data/lib/action_controller/metal/rescue.rb +19 -21
- data/lib/action_controller/metal/streaming.rb +179 -138
- data/lib/action_controller/metal/strong_parameters.rb +1058 -382
- data/lib/action_controller/metal/testing.rb +11 -17
- data/lib/action_controller/metal/url_for.rb +37 -21
- data/lib/action_controller/metal.rb +236 -138
- data/lib/action_controller/railtie.rb +89 -11
- data/lib/action_controller/railties/helpers.rb +5 -1
- data/lib/action_controller/renderer.rb +161 -0
- data/lib/action_controller/template_assertions.rb +13 -0
- data/lib/action_controller/test_case.rb +425 -497
- data/lib/action_controller.rb +44 -22
- data/lib/action_dispatch/constants.rb +34 -0
- data/lib/action_dispatch/deprecator.rb +9 -0
- data/lib/action_dispatch/http/cache.rb +119 -63
- data/lib/action_dispatch/http/content_disposition.rb +47 -0
- data/lib/action_dispatch/http/content_security_policy.rb +364 -0
- data/lib/action_dispatch/http/filter_parameters.rb +36 -34
- data/lib/action_dispatch/http/filter_redirect.rb +24 -12
- data/lib/action_dispatch/http/headers.rb +66 -31
- data/lib/action_dispatch/http/mime_negotiation.rb +106 -75
- data/lib/action_dispatch/http/mime_type.rb +196 -136
- data/lib/action_dispatch/http/mime_types.rb +25 -7
- data/lib/action_dispatch/http/parameters.rb +97 -45
- data/lib/action_dispatch/http/permissions_policy.rb +187 -0
- data/lib/action_dispatch/http/rack_cache.rb +6 -0
- data/lib/action_dispatch/http/request.rb +299 -170
- data/lib/action_dispatch/http/response.rb +311 -160
- data/lib/action_dispatch/http/upload.rb +52 -23
- data/lib/action_dispatch/http/url.rb +201 -125
- data/lib/action_dispatch/journey/formatter.rb +110 -50
- data/lib/action_dispatch/journey/gtg/builder.rb +37 -50
- data/lib/action_dispatch/journey/gtg/simulator.rb +20 -17
- data/lib/action_dispatch/journey/gtg/transition_table.rb +96 -36
- data/lib/action_dispatch/journey/nfa/dot.rb +5 -14
- data/lib/action_dispatch/journey/nodes/node.rb +100 -20
- data/lib/action_dispatch/journey/parser.rb +19 -17
- data/lib/action_dispatch/journey/parser.y +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +14 -4
- data/lib/action_dispatch/journey/path/pattern.rb +79 -63
- data/lib/action_dispatch/journey/route.rb +108 -44
- data/lib/action_dispatch/journey/router/utils.rb +41 -29
- data/lib/action_dispatch/journey/router.rb +64 -57
- data/lib/action_dispatch/journey/routes.rb +23 -21
- data/lib/action_dispatch/journey/scanner.rb +28 -17
- data/lib/action_dispatch/journey/visitors.rb +100 -54
- data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
- data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
- data/lib/action_dispatch/journey.rb +7 -5
- data/lib/action_dispatch/log_subscriber.rb +25 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
- data/lib/action_dispatch/middleware/callbacks.rb +7 -6
- data/lib/action_dispatch/middleware/cookies.rb +471 -328
- data/lib/action_dispatch/middleware/debug_exceptions.rb +149 -66
- data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
- data/lib/action_dispatch/middleware/debug_view.rb +73 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +275 -73
- data/lib/action_dispatch/middleware/executor.rb +32 -0
- data/lib/action_dispatch/middleware/flash.rb +143 -101
- data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +36 -27
- data/lib/action_dispatch/middleware/reloader.rb +10 -92
- data/lib/action_dispatch/middleware/remote_ip.rb +133 -107
- data/lib/action_dispatch/middleware/request_id.rb +29 -15
- data/lib/action_dispatch/middleware/server_timing.rb +78 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +49 -27
- data/lib/action_dispatch/middleware/session/cache_store.rb +33 -16
- data/lib/action_dispatch/middleware/session/cookie_store.rb +86 -80
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +66 -36
- data/lib/action_dispatch/middleware/ssl.rb +134 -36
- data/lib/action_dispatch/middleware/stack.rb +109 -44
- data/lib/action_dispatch/middleware/static.rb +159 -90
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +7 -24
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +139 -15
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +6 -6
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +9 -9
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +7 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +125 -93
- data/lib/action_dispatch/railtie.rb +44 -16
- data/lib/action_dispatch/request/session.rb +159 -69
- data/lib/action_dispatch/request/utils.rb +97 -23
- data/lib/action_dispatch/routing/endpoint.rb +11 -2
- data/lib/action_dispatch/routing/inspector.rb +195 -106
- data/lib/action_dispatch/routing/mapper.rb +1338 -955
- data/lib/action_dispatch/routing/polymorphic_routes.rb +234 -201
- data/lib/action_dispatch/routing/redirection.rb +78 -51
- data/lib/action_dispatch/routing/route_set.rb +460 -374
- data/lib/action_dispatch/routing/routes_proxy.rb +36 -12
- data/lib/action_dispatch/routing/url_for.rb +172 -124
- data/lib/action_dispatch/routing.rb +159 -158
- data/lib/action_dispatch/system_test_case.rb +206 -0
- data/lib/action_dispatch/system_testing/browser.rb +84 -0
- data/lib/action_dispatch/system_testing/driver.rb +85 -0
- data/lib/action_dispatch/system_testing/server.rb +33 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
- data/lib/action_dispatch/testing/assertion_response.rb +48 -0
- data/lib/action_dispatch/testing/assertions/response.rb +71 -39
- data/lib/action_dispatch/testing/assertions/routing.rb +228 -103
- data/lib/action_dispatch/testing/assertions.rb +9 -6
- data/lib/action_dispatch/testing/integration.rb +486 -306
- data/lib/action_dispatch/testing/request_encoder.rb +60 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +35 -22
- data/lib/action_dispatch/testing/test_request.rb +29 -34
- data/lib/action_dispatch/testing/test_response.rb +48 -15
- data/lib/action_dispatch.rb +82 -40
- data/lib/action_pack/gem_version.rb +8 -4
- data/lib/action_pack/version.rb +6 -2
- data/lib/action_pack.rb +21 -18
- metadata +146 -56
- data/lib/action_controller/caching/fragments.rb +0 -103
- data/lib/action_controller/metal/force_ssl.rb +0 -97
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/http/parameter_filter.rb +0 -72
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +0 -27
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- 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
|
6
|
-
#
|
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
|
-
#
|
10
|
-
#
|
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
|
19
|
-
#
|
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
|
28
|
-
raise(ArgumentError,
|
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
|
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
|
67
|
+
# Shortcut for `tempfile.open`.
|
48
68
|
def open
|
49
69
|
@tempfile.open
|
50
70
|
end
|
51
71
|
|
52
|
-
# Shortcut for
|
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
|
77
|
+
# Shortcut for `tempfile.path`.
|
58
78
|
def path
|
59
79
|
@tempfile.path
|
60
80
|
end
|
61
81
|
|
62
|
-
# Shortcut for
|
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
|
92
|
+
# Shortcut for `tempfile.size`.
|
68
93
|
def size
|
69
94
|
@tempfile.size
|
70
95
|
end
|
71
96
|
|
72
|
-
# Shortcut for
|
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
|
-
|
2
|
-
|
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 :
|
12
|
-
|
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,
|
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
|
73
|
+
path = options[:script_name].to_s.chomp("/")
|
53
74
|
path << options[:path] if options.key?(:path)
|
54
75
|
|
55
|
-
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
-
|
86
|
-
|
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
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
103
|
-
|
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
|
-
|
114
|
+
protocol = normalize_protocol protocol
|
115
|
+
host = normalize_host(host, options)
|
106
116
|
|
107
|
-
|
108
|
-
result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
109
|
-
end
|
117
|
+
result = protocol.dup
|
110
118
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
}
|
119
|
+
if options[:user] && options[:password]
|
120
|
+
result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
121
|
+
end
|
115
122
|
|
116
|
-
|
117
|
-
|
123
|
+
result << host
|
124
|
+
normalize_port(port, protocol) { |normalized_port|
|
125
|
+
result << ":#{normalized_port}"
|
126
|
+
}
|
118
127
|
|
119
|
-
|
120
|
-
|
121
|
-
end
|
128
|
+
result.concat path
|
129
|
+
end
|
122
130
|
|
123
|
-
|
124
|
-
|
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
|
-
|
137
|
-
|
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
|
-
|
140
|
-
|
141
|
-
|
151
|
+
tld_length = options[:tld_length] || @@tld_length
|
152
|
+
subdomain = options.fetch :subdomain, true
|
153
|
+
domain = options[:domain]
|
142
154
|
|
143
|
-
|
144
|
-
|
145
|
-
|
155
|
+
host = +""
|
156
|
+
if subdomain == true
|
157
|
+
return _host if domain.nil?
|
146
158
|
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|
-
|
157
|
-
|
168
|
+
def normalize_port(port, protocol)
|
169
|
+
return unless port
|
158
170
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
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
|
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? ?
|
203
|
+
@protocol ||= ssl? ? "https://" : "http://"
|
183
204
|
end
|
184
205
|
|
185
|
-
# Returns the
|
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 =
|
217
|
+
if forwarded = x_forwarded_host.presence
|
188
218
|
forwarded.split(/,\s?/).last
|
189
219
|
else
|
190
|
-
|
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
|
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 ||=
|
208
|
-
|
209
|
-
|
210
|
-
|
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
|
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
|
-
|
219
|
-
|
220
|
-
|
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
|
230
|
-
#
|
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
|
236
|
-
#
|
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? ?
|
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
|
-
|
318
|
+
get_header("SERVER_PORT").to_i
|
243
319
|
end
|
244
320
|
|
245
|
-
# Returns the
|
246
|
-
# a different
|
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
|
252
|
-
#
|
253
|
-
#
|
254
|
-
#
|
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
|
260
|
-
#
|
261
|
-
#
|
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
|