actionpack 3.2.22.5 → 5.2.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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +279 -603
- data/MIT-LICENSE +1 -1
- data/README.rdoc +13 -297
- data/lib/abstract_controller/asset_paths.rb +4 -2
- data/lib/abstract_controller/base.rb +82 -52
- data/lib/abstract_controller/caching/fragments.rb +166 -0
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/callbacks.rb +117 -103
- data/lib/abstract_controller/collector.rb +18 -7
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +65 -38
- data/lib/abstract_controller/logger.rb +3 -2
- data/lib/abstract_controller/railties/routes_helpers.rb +5 -3
- data/lib/abstract_controller/rendering.rb +77 -129
- data/lib/abstract_controller/translation.rb +21 -3
- data/lib/abstract_controller/url_for.rb +9 -7
- data/lib/abstract_controller.rb +12 -13
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/api.rb +149 -0
- data/lib/action_controller/base.rb +81 -40
- data/lib/action_controller/caching.rb +22 -62
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +30 -18
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +190 -47
- data/lib/action_controller/metal/content_security_policy.rb +52 -0
- data/lib/action_controller/metal/cookies.rb +3 -3
- data/lib/action_controller/metal/data_streaming.rb +40 -65
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
- data/lib/action_controller/metal/exceptions.rb +19 -12
- data/lib/action_controller/metal/flash.rb +42 -9
- data/lib/action_controller/metal/force_ssl.rb +79 -19
- data/lib/action_controller/metal/head.rb +35 -10
- data/lib/action_controller/metal/helpers.rb +31 -21
- data/lib/action_controller/metal/http_authentication.rb +182 -134
- data/lib/action_controller/metal/implicit_render.rb +62 -8
- data/lib/action_controller/metal/instrumentation.rb +28 -26
- data/lib/action_controller/metal/live.rb +312 -0
- data/lib/action_controller/metal/mime_responds.rb +159 -163
- data/lib/action_controller/metal/parameter_encoding.rb +51 -0
- data/lib/action_controller/metal/params_wrapper.rb +146 -93
- data/lib/action_controller/metal/redirecting.rb +80 -56
- data/lib/action_controller/metal/renderers.rb +119 -47
- data/lib/action_controller/metal/rendering.rb +89 -32
- data/lib/action_controller/metal/request_forgery_protection.rb +373 -41
- data/lib/action_controller/metal/rescue.rb +9 -16
- data/lib/action_controller/metal/streaming.rb +39 -45
- data/lib/action_controller/metal/strong_parameters.rb +1086 -0
- data/lib/action_controller/metal/testing.rb +8 -29
- data/lib/action_controller/metal/url_for.rb +43 -32
- data/lib/action_controller/metal.rb +112 -106
- data/lib/action_controller/railtie.rb +56 -18
- data/lib/action_controller/railties/helpers.rb +24 -0
- data/lib/action_controller/renderer.rb +117 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +402 -347
- data/lib/action_controller.rb +31 -30
- data/lib/action_dispatch/http/cache.rb +133 -34
- data/lib/action_dispatch/http/content_security_policy.rb +272 -0
- data/lib/action_dispatch/http/filter_parameters.rb +40 -24
- data/lib/action_dispatch/http/filter_redirect.rb +37 -0
- data/lib/action_dispatch/http/headers.rb +117 -16
- data/lib/action_dispatch/http/mime_negotiation.rb +98 -33
- data/lib/action_dispatch/http/mime_type.rb +198 -146
- data/lib/action_dispatch/http/mime_types.rb +22 -7
- data/lib/action_dispatch/http/parameter_filter.rb +61 -49
- data/lib/action_dispatch/http/parameters.rb +94 -51
- data/lib/action_dispatch/http/rack_cache.rb +4 -3
- data/lib/action_dispatch/http/request.rb +262 -117
- data/lib/action_dispatch/http/response.rb +400 -86
- data/lib/action_dispatch/http/upload.rb +66 -29
- data/lib/action_dispatch/http/url.rb +232 -60
- data/lib/action_dispatch/journey/formatter.rb +189 -0
- data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
- data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
- data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
- data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
- data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
- data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
- data/lib/action_dispatch/journey/nodes/node.rb +140 -0
- data/lib/action_dispatch/journey/parser.rb +199 -0
- data/lib/action_dispatch/journey/parser.y +50 -0
- data/lib/action_dispatch/journey/parser_extras.rb +31 -0
- data/lib/action_dispatch/journey/path/pattern.rb +199 -0
- data/lib/action_dispatch/journey/route.rb +203 -0
- data/lib/action_dispatch/journey/router/utils.rb +102 -0
- data/lib/action_dispatch/journey/router.rb +156 -0
- data/lib/action_dispatch/journey/routes.rb +82 -0
- data/lib/action_dispatch/journey/scanner.rb +64 -0
- data/lib/action_dispatch/journey/visitors.rb +268 -0
- data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
- data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
- data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
- data/lib/action_dispatch/journey.rb +7 -0
- data/lib/action_dispatch/middleware/callbacks.rb +17 -13
- data/lib/action_dispatch/middleware/cookies.rb +494 -162
- data/lib/action_dispatch/middleware/debug_exceptions.rb +176 -53
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +103 -38
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +128 -91
- data/lib/action_dispatch/middleware/public_exceptions.rb +43 -16
- data/lib/action_dispatch/middleware/reloader.rb +6 -83
- data/lib/action_dispatch/middleware/remote_ip.rb +151 -49
- data/lib/action_dispatch/middleware/request_id.rb +19 -15
- data/lib/action_dispatch/middleware/session/abstract_store.rb +38 -34
- data/lib/action_dispatch/middleware/session/cache_store.rb +14 -9
- data/lib/action_dispatch/middleware/session/cookie_store.rb +94 -44
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -4
- data/lib/action_dispatch/middleware/show_exceptions.rb +36 -61
- data/lib/action_dispatch/middleware/ssl.rb +150 -0
- data/lib/action_dispatch/middleware/stack.rb +33 -41
- data/lib/action_dispatch/middleware/static.rb +92 -48
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +134 -5
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
- data/lib/action_dispatch/railtie.rb +29 -8
- data/lib/action_dispatch/request/session.rb +234 -0
- data/lib/action_dispatch/request/utils.rb +78 -0
- data/lib/action_dispatch/routing/endpoint.rb +17 -0
- data/lib/action_dispatch/routing/inspector.rb +225 -0
- data/lib/action_dispatch/routing/mapper.rb +1329 -582
- data/lib/action_dispatch/routing/polymorphic_routes.rb +237 -94
- data/lib/action_dispatch/routing/redirection.rb +120 -50
- data/lib/action_dispatch/routing/route_set.rb +545 -322
- data/lib/action_dispatch/routing/routes_proxy.rb +37 -7
- data/lib/action_dispatch/routing/url_for.rb +103 -34
- data/lib/action_dispatch/routing.rb +66 -99
- data/lib/action_dispatch/system_test_case.rb +147 -0
- data/lib/action_dispatch/system_testing/browser.rb +49 -0
- data/lib/action_dispatch/system_testing/driver.rb +59 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
- data/lib/action_dispatch/testing/assertion_response.rb +47 -0
- data/lib/action_dispatch/testing/assertions/response.rb +53 -42
- data/lib/action_dispatch/testing/assertions/routing.rb +79 -74
- data/lib/action_dispatch/testing/assertions.rb +15 -9
- data/lib/action_dispatch/testing/integration.rb +361 -207
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +28 -19
- data/lib/action_dispatch/testing/test_request.rb +30 -33
- data/lib/action_dispatch/testing/test_response.rb +35 -11
- data/lib/action_dispatch.rb +42 -32
- data/lib/action_pack/gem_version.rb +17 -0
- data/lib/action_pack/version.rb +7 -7
- data/lib/action_pack.rb +4 -2
- metadata +116 -175
- data/lib/abstract_controller/layouts.rb +0 -423
- data/lib/abstract_controller/view_paths.rb +0 -96
- data/lib/action_controller/caching/actions.rb +0 -185
- data/lib/action_controller/caching/fragments.rb +0 -127
- data/lib/action_controller/caching/pages.rb +0 -187
- data/lib/action_controller/caching/sweeping.rb +0 -97
- data/lib/action_controller/deprecated/integration_test.rb +0 -2
- data/lib/action_controller/deprecated/performance_test.rb +0 -1
- data/lib/action_controller/deprecated.rb +0 -3
- data/lib/action_controller/metal/compatibility.rb +0 -65
- data/lib/action_controller/metal/hide_actions.rb +0 -41
- data/lib/action_controller/metal/rack_delegation.rb +0 -26
- data/lib/action_controller/metal/responder.rb +0 -286
- data/lib/action_controller/metal/session_management.rb +0 -14
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/railties/paths.rb +0 -25
- data/lib/action_controller/record_identifier.rb +0 -85
- data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
- data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
- data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
- data/lib/action_controller/vendor/html-scanner.rb +0 -20
- data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
- data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
- data/lib/action_dispatch/middleware/head.rb +0 -18
- data/lib/action_dispatch/middleware/params_parser.rb +0 -75
- data/lib/action_dispatch/middleware/rescue.rb +0 -26
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -37
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -435
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -138
- data/lib/action_dispatch/testing/performance_test.rb +0 -10
- data/lib/action_view/asset_paths.rb +0 -142
- data/lib/action_view/base.rb +0 -220
- data/lib/action_view/buffers.rb +0 -43
- data/lib/action_view/context.rb +0 -36
- data/lib/action_view/flows.rb +0 -79
- data/lib/action_view/helpers/active_model_helper.rb +0 -50
- data/lib/action_view/helpers/asset_paths.rb +0 -7
- data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
- data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
- data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
- data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
- data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
- data/lib/action_view/helpers/cache_helper.rb +0 -64
- data/lib/action_view/helpers/capture_helper.rb +0 -203
- data/lib/action_view/helpers/controller_helper.rb +0 -25
- data/lib/action_view/helpers/csrf_helper.rb +0 -32
- data/lib/action_view/helpers/date_helper.rb +0 -1062
- data/lib/action_view/helpers/debug_helper.rb +0 -40
- data/lib/action_view/helpers/form_helper.rb +0 -1486
- data/lib/action_view/helpers/form_options_helper.rb +0 -658
- data/lib/action_view/helpers/form_tag_helper.rb +0 -685
- data/lib/action_view/helpers/javascript_helper.rb +0 -110
- data/lib/action_view/helpers/number_helper.rb +0 -622
- data/lib/action_view/helpers/output_safety_helper.rb +0 -38
- data/lib/action_view/helpers/record_tag_helper.rb +0 -111
- data/lib/action_view/helpers/rendering_helper.rb +0 -92
- data/lib/action_view/helpers/sanitize_helper.rb +0 -259
- data/lib/action_view/helpers/tag_helper.rb +0 -167
- data/lib/action_view/helpers/text_helper.rb +0 -426
- data/lib/action_view/helpers/translation_helper.rb +0 -91
- data/lib/action_view/helpers/url_helper.rb +0 -693
- data/lib/action_view/helpers.rb +0 -60
- data/lib/action_view/locale/en.yml +0 -160
- data/lib/action_view/log_subscriber.rb +0 -28
- data/lib/action_view/lookup_context.rb +0 -258
- data/lib/action_view/path_set.rb +0 -101
- data/lib/action_view/railtie.rb +0 -55
- data/lib/action_view/renderer/abstract_renderer.rb +0 -41
- data/lib/action_view/renderer/partial_renderer.rb +0 -415
- data/lib/action_view/renderer/renderer.rb +0 -61
- data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
- data/lib/action_view/renderer/template_renderer.rb +0 -95
- data/lib/action_view/template/error.rb +0 -128
- data/lib/action_view/template/handlers/builder.rb +0 -26
- data/lib/action_view/template/handlers/erb.rb +0 -125
- data/lib/action_view/template/handlers.rb +0 -50
- data/lib/action_view/template/resolver.rb +0 -298
- data/lib/action_view/template/text.rb +0 -30
- data/lib/action_view/template.rb +0 -337
- data/lib/action_view/test_case.rb +0 -246
- data/lib/action_view/testing/resolvers.rb +0 -49
- data/lib/action_view.rb +0 -84
- data/lib/sprockets/assets.rake +0 -99
- data/lib/sprockets/bootstrap.rb +0 -37
- data/lib/sprockets/compressors.rb +0 -83
- data/lib/sprockets/helpers/isolated_helper.rb +0 -13
- data/lib/sprockets/helpers/rails_helper.rb +0 -182
- data/lib/sprockets/helpers.rb +0 -6
- data/lib/sprockets/railtie.rb +0 -62
- data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,118 +1,262 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/attribute_accessors"
|
4
|
+
|
1
5
|
module ActionDispatch
|
2
6
|
module Http
|
3
7
|
module URL
|
4
|
-
|
5
|
-
|
8
|
+
IP_HOST_REGEXP = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
|
9
|
+
HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
|
10
|
+
PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
|
11
|
+
|
12
|
+
mattr_accessor :tld_length, default: 1
|
6
13
|
|
7
14
|
class << self
|
8
|
-
|
9
|
-
|
10
|
-
|
15
|
+
# Returns the domain part of a host given the domain level.
|
16
|
+
#
|
17
|
+
# # Top-level domain example
|
18
|
+
# extract_domain('www.example.com', 1) # => "example.com"
|
19
|
+
# # Second-level domain example
|
20
|
+
# extract_domain('dev.www.example.co.uk', 2) # => "example.co.uk"
|
21
|
+
def extract_domain(host, tld_length)
|
22
|
+
extract_domain_from(host, tld_length) if named_host?(host)
|
11
23
|
end
|
12
24
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
25
|
+
# Returns the subdomains of a host as an Array given the domain level.
|
26
|
+
#
|
27
|
+
# # Top-level domain example
|
28
|
+
# extract_subdomains('www.example.com', 1) # => ["www"]
|
29
|
+
# # Second-level domain example
|
30
|
+
# extract_subdomains('dev.www.example.co.uk', 2) # => ["dev", "www"]
|
31
|
+
def extract_subdomains(host, tld_length)
|
32
|
+
if named_host?(host)
|
33
|
+
extract_subdomains_from(host, tld_length)
|
34
|
+
else
|
35
|
+
[]
|
36
|
+
end
|
17
37
|
end
|
18
38
|
|
19
|
-
|
20
|
-
|
39
|
+
# Returns the subdomains of a host as a String given the domain level.
|
40
|
+
#
|
41
|
+
# # Top-level domain example
|
42
|
+
# extract_subdomain('www.example.com', 1) # => "www"
|
43
|
+
# # Second-level domain example
|
44
|
+
# extract_subdomain('dev.www.example.co.uk', 2) # => "dev.www"
|
45
|
+
def extract_subdomain(host, tld_length)
|
46
|
+
extract_subdomains(host, tld_length).join(".")
|
21
47
|
end
|
22
48
|
|
23
|
-
def url_for(options
|
24
|
-
|
25
|
-
|
49
|
+
def url_for(options)
|
50
|
+
if options[:only_path]
|
51
|
+
path_for options
|
52
|
+
else
|
53
|
+
full_url_for options
|
26
54
|
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def full_url_for(options)
|
58
|
+
host = options[:host]
|
59
|
+
protocol = options[:protocol]
|
60
|
+
port = options[:port]
|
27
61
|
|
28
|
-
|
29
|
-
|
30
|
-
unless options[:only_path]
|
31
|
-
unless options[:protocol] == false
|
32
|
-
rewritten_url << (options[:protocol] || "http")
|
33
|
-
rewritten_url << ":" unless rewritten_url.match(%r{:|//})
|
34
|
-
end
|
35
|
-
rewritten_url << "//" unless rewritten_url.match("//")
|
36
|
-
rewritten_url << rewrite_authentication(options)
|
37
|
-
rewritten_url << host_or_subdomain_and_domain(options)
|
38
|
-
rewritten_url << ":#{options.delete(:port)}" if options[:port]
|
62
|
+
unless host
|
63
|
+
raise ArgumentError, "Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true"
|
39
64
|
end
|
40
65
|
|
41
|
-
|
66
|
+
build_host_url(host, port, protocol, options, path_for(options))
|
67
|
+
end
|
42
68
|
|
43
|
-
|
44
|
-
|
69
|
+
def path_for(options)
|
70
|
+
path = options[:script_name].to_s.chomp("/".freeze)
|
71
|
+
path << options[:path] if options.key?(:path)
|
45
72
|
|
46
|
-
if options[:trailing_slash]
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
rewritten_url << "?#{params.to_query}" unless params.empty?
|
52
|
-
rewritten_url << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor]
|
53
|
-
rewritten_url
|
73
|
+
add_trailing_slash(path) if options[:trailing_slash]
|
74
|
+
add_params(path, options[:params]) if options.key?(:params)
|
75
|
+
add_anchor(path, options[:anchor]) if options.key?(:anchor)
|
76
|
+
|
77
|
+
path
|
54
78
|
end
|
55
79
|
|
56
80
|
private
|
57
81
|
|
58
|
-
def
|
59
|
-
|
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)}"
|
92
|
+
end
|
60
93
|
end
|
61
94
|
|
62
|
-
def
|
95
|
+
def extract_domain_from(host, tld_length)
|
96
|
+
host.split(".").last(1 + tld_length).join(".")
|
97
|
+
end
|
98
|
+
|
99
|
+
def extract_subdomains_from(host, tld_length)
|
100
|
+
parts = host.split(".")
|
101
|
+
parts[0..-(tld_length + 2)]
|
102
|
+
end
|
103
|
+
|
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
|
110
|
+
end
|
111
|
+
|
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
|
118
|
+
|
119
|
+
protocol = normalize_protocol protocol
|
120
|
+
host = normalize_host(host, options)
|
121
|
+
|
122
|
+
result = protocol.dup
|
123
|
+
|
63
124
|
if options[:user] && options[:password]
|
64
|
-
"#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
125
|
+
result << "#{Rack::Utils.escape(options[:user])}:#{Rack::Utils.escape(options[:password])}@"
|
126
|
+
end
|
127
|
+
|
128
|
+
result << host
|
129
|
+
normalize_port(port, protocol) { |normalized_port|
|
130
|
+
result << ":#{normalized_port}"
|
131
|
+
}
|
132
|
+
|
133
|
+
result.concat path
|
134
|
+
end
|
135
|
+
|
136
|
+
def named_host?(host)
|
137
|
+
IP_HOST_REGEXP !~ host
|
138
|
+
end
|
139
|
+
|
140
|
+
def normalize_protocol(protocol)
|
141
|
+
case protocol
|
142
|
+
when nil
|
143
|
+
"http://"
|
144
|
+
when false, "//"
|
145
|
+
"//"
|
146
|
+
when PROTOCOL_REGEXP
|
147
|
+
"#{$1}://"
|
65
148
|
else
|
66
|
-
""
|
149
|
+
raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
|
67
150
|
end
|
68
151
|
end
|
69
152
|
|
70
|
-
def
|
71
|
-
return
|
153
|
+
def normalize_host(_host, options)
|
154
|
+
return _host unless named_host?(_host)
|
72
155
|
|
73
156
|
tld_length = options[:tld_length] || @@tld_length
|
157
|
+
subdomain = options.fetch :subdomain, true
|
158
|
+
domain = options[:domain]
|
159
|
+
|
160
|
+
host = "".dup
|
161
|
+
if subdomain == true
|
162
|
+
return _host if domain.nil?
|
74
163
|
|
75
|
-
|
76
|
-
|
77
|
-
host <<
|
78
|
-
host << "."
|
164
|
+
host << extract_subdomains_from(_host, tld_length).join(".")
|
165
|
+
elsif subdomain
|
166
|
+
host << subdomain.to_param
|
79
167
|
end
|
80
|
-
host <<
|
168
|
+
host << "." unless host.empty?
|
169
|
+
host << (domain || extract_domain_from(_host, tld_length))
|
81
170
|
host
|
82
171
|
end
|
172
|
+
|
173
|
+
def normalize_port(port, protocol)
|
174
|
+
return unless port
|
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
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def initialize
|
187
|
+
super
|
188
|
+
@protocol = nil
|
189
|
+
@port = nil
|
83
190
|
end
|
84
191
|
|
85
192
|
# Returns the complete URL used for this request.
|
193
|
+
#
|
194
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
195
|
+
# req.url # => "http://example.com"
|
86
196
|
def url
|
87
197
|
protocol + host_with_port + fullpath
|
88
198
|
end
|
89
199
|
|
90
200
|
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
|
201
|
+
#
|
202
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
203
|
+
# req.protocol # => "http://"
|
204
|
+
#
|
205
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on'
|
206
|
+
# req.protocol # => "https://"
|
91
207
|
def protocol
|
92
|
-
@protocol ||= ssl? ?
|
208
|
+
@protocol ||= ssl? ? "https://" : "http://"
|
93
209
|
end
|
94
210
|
|
95
|
-
# Returns the \host for this request, such as "example.com".
|
211
|
+
# Returns the \host and port for this request, such as "example.com:8080".
|
212
|
+
#
|
213
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
214
|
+
# req.raw_host_with_port # => "example.com"
|
215
|
+
#
|
216
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
217
|
+
# req.raw_host_with_port # => "example.com:80"
|
218
|
+
#
|
219
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
220
|
+
# req.raw_host_with_port # => "example.com:8080"
|
96
221
|
def raw_host_with_port
|
97
|
-
if forwarded =
|
222
|
+
if forwarded = x_forwarded_host.presence
|
98
223
|
forwarded.split(/,\s?/).last
|
99
224
|
else
|
100
|
-
|
225
|
+
get_header("HTTP_HOST") || "#{server_name || server_addr}:#{get_header('SERVER_PORT')}"
|
101
226
|
end
|
102
227
|
end
|
103
228
|
|
104
|
-
# Returns the host for this request, such as example.com.
|
229
|
+
# Returns the host for this request, such as "example.com".
|
230
|
+
#
|
231
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
232
|
+
# req.host # => "example.com"
|
105
233
|
def host
|
106
|
-
raw_host_with_port.sub(/:\d+$/,
|
234
|
+
raw_host_with_port.sub(/:\d+$/, "".freeze)
|
107
235
|
end
|
108
236
|
|
109
237
|
# Returns a \host:\port string for this request, such as "example.com" or
|
110
|
-
# "example.com:8080".
|
238
|
+
# "example.com:8080". Port is only included if it is not a default port
|
239
|
+
# (80 or 443)
|
240
|
+
#
|
241
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
242
|
+
# req.host_with_port # => "example.com"
|
243
|
+
#
|
244
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
245
|
+
# req.host_with_port # => "example.com"
|
246
|
+
#
|
247
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
248
|
+
# req.host_with_port # => "example.com:8080"
|
111
249
|
def host_with_port
|
112
250
|
"#{host}#{port_string}"
|
113
251
|
end
|
114
252
|
|
115
253
|
# Returns the port number of this request as an integer.
|
254
|
+
#
|
255
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
256
|
+
# req.port # => 80
|
257
|
+
#
|
258
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
259
|
+
# req.port # => 8080
|
116
260
|
def port
|
117
261
|
@port ||= begin
|
118
262
|
if raw_host_with_port =~ /:(\d+)$/
|
@@ -124,32 +268,60 @@ module ActionDispatch
|
|
124
268
|
end
|
125
269
|
|
126
270
|
# Returns the standard \port number for this request's protocol.
|
271
|
+
#
|
272
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
273
|
+
# req.standard_port # => 80
|
127
274
|
def standard_port
|
128
275
|
case protocol
|
129
|
-
|
130
|
-
|
276
|
+
when "https://" then 443
|
277
|
+
else 80
|
131
278
|
end
|
132
279
|
end
|
133
280
|
|
134
281
|
# Returns whether this request is using the standard port
|
282
|
+
#
|
283
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
284
|
+
# req.standard_port? # => true
|
285
|
+
#
|
286
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
287
|
+
# req.standard_port? # => false
|
135
288
|
def standard_port?
|
136
289
|
port == standard_port
|
137
290
|
end
|
138
291
|
|
139
292
|
# Returns a number \port suffix like 8080 if the \port number of this request
|
140
293
|
# is not the default HTTP \port 80 or HTTPS \port 443.
|
294
|
+
#
|
295
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
296
|
+
# req.optional_port # => nil
|
297
|
+
#
|
298
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
299
|
+
# req.optional_port # => 8080
|
141
300
|
def optional_port
|
142
301
|
standard_port? ? nil : port
|
143
302
|
end
|
144
303
|
|
145
304
|
# Returns a string \port suffix, including colon, like ":8080" if the \port
|
146
305
|
# number of this request is not the default HTTP \port 80 or HTTPS \port 443.
|
306
|
+
#
|
307
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
308
|
+
# req.port_string # => ""
|
309
|
+
#
|
310
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
311
|
+
# req.port_string # => ":8080"
|
147
312
|
def port_string
|
148
|
-
standard_port? ?
|
313
|
+
standard_port? ? "" : ":#{port}"
|
149
314
|
end
|
150
315
|
|
316
|
+
# Returns the requested port, such as 8080, based on SERVER_PORT
|
317
|
+
#
|
318
|
+
# req = ActionDispatch::Request.new 'SERVER_PORT' => '80'
|
319
|
+
# req.server_port # => 80
|
320
|
+
#
|
321
|
+
# req = ActionDispatch::Request.new 'SERVER_PORT' => '8080'
|
322
|
+
# req.server_port # => 8080
|
151
323
|
def server_port
|
152
|
-
|
324
|
+
get_header("SERVER_PORT").to_i
|
153
325
|
end
|
154
326
|
|
155
327
|
# Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
|
@@ -171,7 +343,7 @@ module ActionDispatch
|
|
171
343
|
# such as 2 to catch <tt>"www"</tt> instead of <tt>"www.rubyonrails"</tt>
|
172
344
|
# in "www.rubyonrails.co.uk".
|
173
345
|
def subdomain(tld_length = @@tld_length)
|
174
|
-
|
346
|
+
ActionDispatch::Http::URL.extract_subdomain(host, tld_length)
|
175
347
|
end
|
176
348
|
end
|
177
349
|
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_controller/metal/exceptions"
|
4
|
+
|
5
|
+
module ActionDispatch
|
6
|
+
# :stopdoc:
|
7
|
+
module Journey
|
8
|
+
# The Formatter class is used for formatting URLs. For example, parameters
|
9
|
+
# passed to +url_for+ in Rails will eventually call Formatter#generate.
|
10
|
+
class Formatter
|
11
|
+
attr_reader :routes
|
12
|
+
|
13
|
+
def initialize(routes)
|
14
|
+
@routes = routes
|
15
|
+
@cache = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate(name, options, path_parameters, parameterize = nil)
|
19
|
+
constraints = path_parameters.merge(options)
|
20
|
+
missing_keys = nil
|
21
|
+
|
22
|
+
match_route(name, constraints) do |route|
|
23
|
+
parameterized_parts = extract_parameterized_parts(route, options, path_parameters, parameterize)
|
24
|
+
|
25
|
+
# Skip this route unless a name has been provided or it is a
|
26
|
+
# standard Rails route since we can't determine whether an options
|
27
|
+
# hash passed to url_for matches a Rack application or a redirect.
|
28
|
+
next unless name || route.dispatcher?
|
29
|
+
|
30
|
+
missing_keys = missing_keys(route, parameterized_parts)
|
31
|
+
next if missing_keys && !missing_keys.empty?
|
32
|
+
params = options.dup.delete_if do |key, _|
|
33
|
+
parameterized_parts.key?(key) || route.defaults.key?(key)
|
34
|
+
end
|
35
|
+
|
36
|
+
defaults = route.defaults
|
37
|
+
required_parts = route.required_parts
|
38
|
+
|
39
|
+
route.parts.reverse_each do |key|
|
40
|
+
break if defaults[key].nil? && parameterized_parts[key].present?
|
41
|
+
next if parameterized_parts[key].to_s != defaults[key].to_s
|
42
|
+
break if required_parts.include?(key)
|
43
|
+
|
44
|
+
parameterized_parts.delete(key)
|
45
|
+
end
|
46
|
+
|
47
|
+
return [route.format(parameterized_parts), params]
|
48
|
+
end
|
49
|
+
|
50
|
+
unmatched_keys = (missing_keys || []) & constraints.keys
|
51
|
+
missing_keys = (missing_keys || []) - unmatched_keys
|
52
|
+
|
53
|
+
message = "No route matches #{Hash[constraints.sort_by { |k, v| k.to_s }].inspect}".dup
|
54
|
+
message << ", missing required keys: #{missing_keys.sort.inspect}" if missing_keys && !missing_keys.empty?
|
55
|
+
message << ", possible unmatched constraints: #{unmatched_keys.sort.inspect}" if unmatched_keys && !unmatched_keys.empty?
|
56
|
+
|
57
|
+
raise ActionController::UrlGenerationError, message
|
58
|
+
end
|
59
|
+
|
60
|
+
def clear
|
61
|
+
@cache = nil
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def extract_parameterized_parts(route, options, recall, parameterize = nil)
|
67
|
+
parameterized_parts = recall.merge(options)
|
68
|
+
|
69
|
+
keys_to_keep = route.parts.reverse_each.drop_while { |part|
|
70
|
+
!options.key?(part) || (options[part] || recall[part]).nil?
|
71
|
+
} | route.required_parts
|
72
|
+
|
73
|
+
parameterized_parts.delete_if do |bad_key, _|
|
74
|
+
!keys_to_keep.include?(bad_key)
|
75
|
+
end
|
76
|
+
|
77
|
+
if parameterize
|
78
|
+
parameterized_parts.each do |k, v|
|
79
|
+
parameterized_parts[k] = parameterize.call(k, v)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
parameterized_parts.keep_if { |_, v| v }
|
84
|
+
parameterized_parts
|
85
|
+
end
|
86
|
+
|
87
|
+
def named_routes
|
88
|
+
routes.named_routes
|
89
|
+
end
|
90
|
+
|
91
|
+
def match_route(name, options)
|
92
|
+
if named_routes.key?(name)
|
93
|
+
yield named_routes[name]
|
94
|
+
else
|
95
|
+
routes = non_recursive(cache, options)
|
96
|
+
|
97
|
+
supplied_keys = options.each_with_object({}) do |(k, v), h|
|
98
|
+
h[k.to_s] = true if v
|
99
|
+
end
|
100
|
+
|
101
|
+
hash = routes.group_by { |_, r| r.score(supplied_keys) }
|
102
|
+
|
103
|
+
hash.keys.sort.reverse_each do |score|
|
104
|
+
break if score < 0
|
105
|
+
|
106
|
+
hash[score].sort_by { |i, _| i }.each do |_, route|
|
107
|
+
yield route
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def non_recursive(cache, options)
|
114
|
+
routes = []
|
115
|
+
queue = [cache]
|
116
|
+
|
117
|
+
while queue.any?
|
118
|
+
c = queue.shift
|
119
|
+
routes.concat(c[:___routes]) if c.key?(:___routes)
|
120
|
+
|
121
|
+
options.each do |pair|
|
122
|
+
queue << c[pair] if c.key?(pair)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
routes
|
127
|
+
end
|
128
|
+
|
129
|
+
module RegexCaseComparator
|
130
|
+
DEFAULT_INPUT = /[-_.a-zA-Z0-9]+\/[-_.a-zA-Z0-9]+/
|
131
|
+
DEFAULT_REGEX = /\A#{DEFAULT_INPUT}\Z/
|
132
|
+
|
133
|
+
def self.===(regex)
|
134
|
+
DEFAULT_INPUT == regex
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Returns an array populated with missing keys if any are present.
|
139
|
+
def missing_keys(route, parts)
|
140
|
+
missing_keys = nil
|
141
|
+
tests = route.path.requirements
|
142
|
+
route.required_parts.each { |key|
|
143
|
+
case tests[key]
|
144
|
+
when nil
|
145
|
+
unless parts[key]
|
146
|
+
missing_keys ||= []
|
147
|
+
missing_keys << key
|
148
|
+
end
|
149
|
+
when RegexCaseComparator
|
150
|
+
unless RegexCaseComparator::DEFAULT_REGEX === parts[key]
|
151
|
+
missing_keys ||= []
|
152
|
+
missing_keys << key
|
153
|
+
end
|
154
|
+
else
|
155
|
+
unless /\A#{tests[key]}\Z/ === parts[key]
|
156
|
+
missing_keys ||= []
|
157
|
+
missing_keys << key
|
158
|
+
end
|
159
|
+
end
|
160
|
+
}
|
161
|
+
missing_keys
|
162
|
+
end
|
163
|
+
|
164
|
+
def possibles(cache, options, depth = 0)
|
165
|
+
cache.fetch(:___routes) { [] } + options.find_all { |pair|
|
166
|
+
cache.key?(pair)
|
167
|
+
}.flat_map { |pair|
|
168
|
+
possibles(cache[pair], options, depth + 1)
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
def build_cache
|
173
|
+
root = { ___routes: [] }
|
174
|
+
routes.routes.each_with_index do |route, i|
|
175
|
+
leaf = route.required_defaults.inject(root) do |h, tuple|
|
176
|
+
h[tuple] ||= {}
|
177
|
+
end
|
178
|
+
(leaf[:___routes] ||= []) << [i, route]
|
179
|
+
end
|
180
|
+
root
|
181
|
+
end
|
182
|
+
|
183
|
+
def cache
|
184
|
+
@cache ||= build_cache
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
# :startdoc:
|
189
|
+
end
|