actionpack 4.2.8 → 5.2.4.2
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 +285 -444
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -7
- data/lib/abstract_controller.rb +12 -5
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +45 -49
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +78 -15
- data/lib/abstract_controller/callbacks.rb +47 -31
- data/lib/abstract_controller/collector.rb +8 -11
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +25 -25
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +4 -2
- data/lib/abstract_controller/rendering.rb +42 -41
- data/lib/abstract_controller/translation.rb +10 -7
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/action_controller.rb +29 -21
- data/lib/action_controller/api.rb +149 -0
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/base.rb +27 -19
- data/lib/action_controller/caching.rb +14 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +10 -15
- data/lib/action_controller/metal.rb +98 -83
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +118 -44
- 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 +27 -46
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +20 -13
- data/lib/action_controller/metal/exceptions.rb +8 -14
- data/lib/action_controller/metal/flash.rb +4 -3
- data/lib/action_controller/metal/force_ssl.rb +23 -21
- data/lib/action_controller/metal/head.rb +21 -19
- data/lib/action_controller/metal/helpers.rb +24 -14
- data/lib/action_controller/metal/http_authentication.rb +64 -57
- data/lib/action_controller/metal/implicit_render.rb +62 -8
- data/lib/action_controller/metal/instrumentation.rb +19 -21
- data/lib/action_controller/metal/live.rb +90 -106
- data/lib/action_controller/metal/mime_responds.rb +33 -46
- data/lib/action_controller/metal/parameter_encoding.rb +51 -0
- data/lib/action_controller/metal/params_wrapper.rb +61 -53
- data/lib/action_controller/metal/redirecting.rb +49 -28
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +72 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +203 -92
- data/lib/action_controller/metal/rescue.rb +9 -16
- data/lib/action_controller/metal/streaming.rb +12 -10
- data/lib/action_controller/metal/strong_parameters.rb +582 -165
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +2 -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 +280 -411
- data/lib/action_dispatch.rb +27 -19
- data/lib/action_dispatch/http/cache.rb +93 -47
- data/lib/action_dispatch/http/content_security_policy.rb +272 -0
- data/lib/action_dispatch/http/filter_parameters.rb +26 -20
- data/lib/action_dispatch/http/filter_redirect.rb +10 -11
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +60 -41
- data/lib/action_dispatch/http/mime_type.rb +134 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameter_filter.rb +25 -11
- data/lib/action_dispatch/http/parameters.rb +98 -39
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +200 -118
- data/lib/action_dispatch/http/response.rb +225 -110
- data/lib/action_dispatch/http/upload.rb +12 -6
- data/lib/action_dispatch/http/url.rb +110 -28
- data/lib/action_dispatch/journey.rb +7 -5
- data/lib/action_dispatch/journey/formatter.rb +55 -32
- data/lib/action_dispatch/journey/gtg/builder.rb +7 -5
- data/lib/action_dispatch/journey/gtg/simulator.rb +3 -9
- data/lib/action_dispatch/journey/gtg/transition_table.rb +17 -16
- data/lib/action_dispatch/journey/nfa/builder.rb +5 -3
- data/lib/action_dispatch/journey/nfa/dot.rb +13 -13
- data/lib/action_dispatch/journey/nfa/simulator.rb +3 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -48
- data/lib/action_dispatch/journey/nodes/node.rb +18 -6
- data/lib/action_dispatch/journey/parser.rb +23 -22
- data/lib/action_dispatch/journey/parser.y +3 -2
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +50 -44
- data/lib/action_dispatch/journey/route.rb +106 -28
- data/lib/action_dispatch/journey/router.rb +35 -23
- data/lib/action_dispatch/journey/router/utils.rb +20 -11
- data/lib/action_dispatch/journey/routes.rb +18 -16
- data/lib/action_dispatch/journey/scanner.rb +18 -15
- data/lib/action_dispatch/journey/visitors.rb +99 -52
- data/lib/action_dispatch/middleware/callbacks.rb +1 -2
- data/lib/action_dispatch/middleware/cookies.rb +304 -193
- data/lib/action_dispatch/middleware/debug_exceptions.rb +152 -57
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +68 -69
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/public_exceptions.rb +27 -25
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +41 -31
- data/lib/action_dispatch/middleware/request_id.rb +17 -9
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -25
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +72 -67
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +26 -22
- data/lib/action_dispatch/middleware/ssl.rb +114 -36
- data/lib/action_dispatch/middleware/stack.rb +31 -44
- data/lib/action_dispatch/middleware/static.rb +57 -50
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +2 -14
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -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 +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -64
- data/lib/action_dispatch/railtie.rb +19 -11
- data/lib/action_dispatch/request/session.rb +106 -59
- data/lib/action_dispatch/request/utils.rb +67 -24
- data/lib/action_dispatch/routing.rb +17 -18
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +58 -67
- data/lib/action_dispatch/routing/mapper.rb +734 -447
- data/lib/action_dispatch/routing/polymorphic_routes.rb +161 -139
- data/lib/action_dispatch/routing/redirection.rb +36 -26
- data/lib/action_dispatch/routing/route_set.rb +321 -291
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +65 -25
- 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.rb +6 -4
- data/lib/action_dispatch/testing/assertions/response.rb +45 -20
- data/lib/action_dispatch/testing/assertions/routing.rb +30 -26
- data/lib/action_dispatch/testing/integration.rb +347 -209
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +28 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +35 -7
- data/lib/action_pack.rb +4 -2
- data/lib/action_pack/gem_version.rb +5 -3
- data/lib/action_pack/version.rb +3 -1
- metadata +56 -39
- 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/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- 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,7 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/object/duplicable"
|
4
|
+
|
1
5
|
module ActionDispatch
|
2
6
|
module Http
|
3
7
|
class ParameterFilter
|
4
|
-
FILTERED =
|
8
|
+
FILTERED = "[FILTERED]".freeze # :nodoc:
|
5
9
|
|
6
10
|
def initialize(filters = [])
|
7
11
|
@filters = filters
|
@@ -30,36 +34,46 @@ module ActionDispatch
|
|
30
34
|
when Regexp
|
31
35
|
regexps << item
|
32
36
|
else
|
33
|
-
strings << item.to_s
|
37
|
+
strings << Regexp.escape(item.to_s)
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
37
|
-
regexps
|
38
|
-
|
41
|
+
deep_regexps, regexps = regexps.partition { |r| r.to_s.include?("\\.".freeze) }
|
42
|
+
deep_strings, strings = strings.partition { |s| s.include?("\\.".freeze) }
|
43
|
+
|
44
|
+
regexps << Regexp.new(strings.join("|".freeze), true) unless strings.empty?
|
45
|
+
deep_regexps << Regexp.new(deep_strings.join("|".freeze), true) unless deep_strings.empty?
|
46
|
+
|
47
|
+
new regexps, deep_regexps, blocks
|
39
48
|
end
|
40
49
|
|
41
|
-
attr_reader :regexps, :blocks
|
50
|
+
attr_reader :regexps, :deep_regexps, :blocks
|
42
51
|
|
43
|
-
def initialize(regexps, blocks)
|
52
|
+
def initialize(regexps, deep_regexps, blocks)
|
44
53
|
@regexps = regexps
|
45
|
-
@
|
54
|
+
@deep_regexps = deep_regexps.any? ? deep_regexps : nil
|
55
|
+
@blocks = blocks
|
46
56
|
end
|
47
57
|
|
48
|
-
def call(original_params)
|
49
|
-
filtered_params =
|
58
|
+
def call(original_params, parents = [])
|
59
|
+
filtered_params = original_params.class.new
|
50
60
|
|
51
61
|
original_params.each do |key, value|
|
62
|
+
parents.push(key) if deep_regexps
|
52
63
|
if regexps.any? { |r| key =~ r }
|
53
64
|
value = FILTERED
|
65
|
+
elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| joined =~ r }
|
66
|
+
value = FILTERED
|
54
67
|
elsif value.is_a?(Hash)
|
55
|
-
value = call(value)
|
68
|
+
value = call(value, parents)
|
56
69
|
elsif value.is_a?(Array)
|
57
|
-
value = value.map { |v| v.is_a?(Hash) ? call(v) : v }
|
70
|
+
value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
|
58
71
|
elsif blocks.any?
|
59
72
|
key = key.dup if key.duplicable?
|
60
73
|
value = value.dup if value.duplicable?
|
61
74
|
blocks.each { |b| b.call(key, value) }
|
62
75
|
end
|
76
|
+
parents.pop if deep_regexps
|
63
77
|
|
64
78
|
filtered_params[key] = value
|
65
79
|
end
|
@@ -1,35 +1,79 @@
|
|
1
|
-
|
2
|
-
require 'active_support/core_ext/hash/indifferent_access'
|
3
|
-
require 'active_support/deprecation'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
3
|
module ActionDispatch
|
6
4
|
module Http
|
7
5
|
module Parameters
|
8
|
-
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
PARAMETERS_KEY = "action_dispatch.request.path_parameters"
|
9
|
+
|
10
|
+
DEFAULT_PARSERS = {
|
11
|
+
Mime[:json].symbol => -> (raw_post) {
|
12
|
+
data = ActiveSupport::JSON.decode(raw_post)
|
13
|
+
data.is_a?(Hash) ? data : { _json: data }
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
# Raised when raw data from the request cannot be parsed by the parser
|
18
|
+
# defined for request's content MIME type.
|
19
|
+
class ParseError < StandardError
|
20
|
+
def initialize
|
21
|
+
super($!.message)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
included do
|
26
|
+
class << self
|
27
|
+
# Returns the parameter parsers.
|
28
|
+
attr_reader :parameter_parsers
|
29
|
+
end
|
30
|
+
|
31
|
+
self.parameter_parsers = DEFAULT_PARSERS
|
32
|
+
end
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
# Configure the parameter parser for a given MIME type.
|
36
|
+
#
|
37
|
+
# It accepts a hash where the key is the symbol of the MIME type
|
38
|
+
# and the value is a proc.
|
39
|
+
#
|
40
|
+
# original_parsers = ActionDispatch::Request.parameter_parsers
|
41
|
+
# xml_parser = -> (raw_post) { Hash.from_xml(raw_post) || {} }
|
42
|
+
# new_parsers = original_parsers.merge(xml: xml_parser)
|
43
|
+
# ActionDispatch::Request.parameter_parsers = new_parsers
|
44
|
+
def parameter_parsers=(parsers)
|
45
|
+
@parameter_parsers = parsers.transform_keys { |key| key.respond_to?(:symbol) ? key.symbol : key }
|
46
|
+
end
|
47
|
+
end
|
9
48
|
|
10
49
|
# Returns both GET and POST \parameters in a single hash.
|
11
50
|
def parameters
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
51
|
+
params = get_header("action_dispatch.request.parameters")
|
52
|
+
return params if params
|
53
|
+
|
54
|
+
params = begin
|
55
|
+
request_parameters.merge(query_parameters)
|
56
|
+
rescue EOFError
|
57
|
+
query_parameters.dup
|
58
|
+
end
|
59
|
+
params.merge!(path_parameters)
|
60
|
+
params = set_binary_encoding(params, params[:controller], params[:action])
|
61
|
+
set_header("action_dispatch.request.parameters", params)
|
62
|
+
params
|
20
63
|
end
|
21
64
|
alias :params :parameters
|
22
65
|
|
23
66
|
def path_parameters=(parameters) #:nodoc:
|
24
|
-
|
25
|
-
|
26
|
-
|
67
|
+
delete_header("action_dispatch.request.parameters")
|
68
|
+
|
69
|
+
parameters = set_binary_encoding(parameters, parameters[:controller], parameters[:action])
|
70
|
+
# If any of the path parameters has an invalid encoding then
|
71
|
+
# raise since it's likely to trigger errors further on.
|
72
|
+
Request::Utils.check_param_encoding(parameters)
|
27
73
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
)
|
32
|
-
path_parameters
|
74
|
+
set_header PARAMETERS_KEY, parameters
|
75
|
+
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
76
|
+
raise ActionController::BadRequest.new("Invalid path parameters: #{e.message}")
|
33
77
|
end
|
34
78
|
|
35
79
|
# Returns a hash with the \parameters used to form the \path of the request.
|
@@ -37,31 +81,46 @@ module ActionDispatch
|
|
37
81
|
#
|
38
82
|
# {'action' => 'my_action', 'controller' => 'my_controller'}
|
39
83
|
def path_parameters
|
40
|
-
|
84
|
+
get_header(PARAMETERS_KEY) || set_header(PARAMETERS_KEY, {})
|
41
85
|
end
|
42
86
|
|
43
|
-
|
87
|
+
private
|
44
88
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
else
|
53
|
-
params.each_with_object({}) do |(key, val), new_hash|
|
54
|
-
new_hash[key] = if val.is_a?(Array)
|
55
|
-
val.map! { |el| normalize_encode_params(el) }
|
56
|
-
else
|
57
|
-
normalize_encode_params(val)
|
58
|
-
end
|
59
|
-
end.with_indifferent_access
|
89
|
+
def set_binary_encoding(params, controller, action)
|
90
|
+
return params unless controller && controller.valid_encoding?
|
91
|
+
|
92
|
+
if binary_params_for?(controller, action)
|
93
|
+
ActionDispatch::Request::Utils.each_param_value(params) do |param|
|
94
|
+
param.force_encoding ::Encoding::ASCII_8BIT
|
95
|
+
end
|
60
96
|
end
|
61
|
-
else
|
62
97
|
params
|
63
98
|
end
|
64
|
-
|
99
|
+
|
100
|
+
def binary_params_for?(controller, action)
|
101
|
+
controller_class_for(controller).binary_params_for?(action)
|
102
|
+
rescue NameError
|
103
|
+
false
|
104
|
+
end
|
105
|
+
|
106
|
+
def parse_formatted_parameters(parsers)
|
107
|
+
return yield if content_length.zero? || content_mime_type.nil?
|
108
|
+
|
109
|
+
strategy = parsers.fetch(content_mime_type.symbol) { return yield }
|
110
|
+
|
111
|
+
begin
|
112
|
+
strategy.call(raw_post)
|
113
|
+
rescue # JSON or Ruby code block errors.
|
114
|
+
my_logger = logger || ActiveSupport::Logger.new($stderr)
|
115
|
+
my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}"
|
116
|
+
|
117
|
+
raise ParseError
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def params_parsers
|
122
|
+
ActionDispatch::Request.parameter_parsers
|
123
|
+
end
|
65
124
|
end
|
66
125
|
end
|
67
126
|
end
|
@@ -1,27 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "stringio"
|
4
|
+
|
5
|
+
require "active_support/inflector"
|
6
|
+
require "action_dispatch/http/headers"
|
7
|
+
require "action_controller/metal/exceptions"
|
8
|
+
require "rack/request"
|
9
|
+
require "action_dispatch/http/cache"
|
10
|
+
require "action_dispatch/http/mime_negotiation"
|
11
|
+
require "action_dispatch/http/parameters"
|
12
|
+
require "action_dispatch/http/filter_parameters"
|
13
|
+
require "action_dispatch/http/upload"
|
14
|
+
require "action_dispatch/http/url"
|
15
|
+
require "active_support/core_ext/array/conversions"
|
14
16
|
|
15
17
|
module ActionDispatch
|
16
|
-
class Request
|
18
|
+
class Request
|
19
|
+
include Rack::Request::Helpers
|
17
20
|
include ActionDispatch::Http::Cache::Request
|
18
21
|
include ActionDispatch::Http::MimeNegotiation
|
19
22
|
include ActionDispatch::Http::Parameters
|
20
23
|
include ActionDispatch::Http::FilterParameters
|
21
24
|
include ActionDispatch::Http::URL
|
25
|
+
include ActionDispatch::ContentSecurityPolicy::Request
|
26
|
+
include Rack::Request::Env
|
22
27
|
|
23
|
-
autoload :Session,
|
24
|
-
autoload :Utils,
|
28
|
+
autoload :Session, "action_dispatch/request/session"
|
29
|
+
autoload :Utils, "action_dispatch/request/utils"
|
25
30
|
|
26
31
|
LOCALHOST = Regexp.union [/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/]
|
27
32
|
|
@@ -29,19 +34,28 @@ module ActionDispatch
|
|
29
34
|
PATH_TRANSLATED REMOTE_HOST
|
30
35
|
REMOTE_IDENT REMOTE_USER REMOTE_ADDR
|
31
36
|
SERVER_NAME SERVER_PROTOCOL
|
37
|
+
ORIGINAL_SCRIPT_NAME
|
32
38
|
|
33
39
|
HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
|
34
40
|
HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM
|
35
|
-
HTTP_NEGOTIATE HTTP_PRAGMA
|
41
|
+
HTTP_NEGOTIATE HTTP_PRAGMA HTTP_CLIENT_IP
|
42
|
+
HTTP_X_FORWARDED_FOR HTTP_ORIGIN HTTP_VERSION
|
43
|
+
HTTP_X_CSRF_TOKEN HTTP_X_REQUEST_ID HTTP_X_FORWARDED_HOST
|
44
|
+
SERVER_ADDR
|
45
|
+
].freeze
|
36
46
|
|
37
47
|
ENV_METHODS.each do |env|
|
38
48
|
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
39
49
|
def #{env.sub(/^HTTP_/n, '').downcase} # def accept_charset
|
40
|
-
|
50
|
+
get_header "#{env}".freeze # get_header "HTTP_ACCEPT_CHARSET".freeze
|
41
51
|
end # end
|
42
52
|
METHOD
|
43
53
|
end
|
44
54
|
|
55
|
+
def self.empty
|
56
|
+
new({})
|
57
|
+
end
|
58
|
+
|
45
59
|
def initialize(env)
|
46
60
|
super
|
47
61
|
@method = nil
|
@@ -50,33 +64,49 @@ module ActionDispatch
|
|
50
64
|
@original_fullpath = nil
|
51
65
|
@fullpath = nil
|
52
66
|
@ip = nil
|
53
|
-
@uuid = nil
|
54
67
|
end
|
55
68
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
69
|
+
def commit_cookie_jar! # :nodoc:
|
70
|
+
end
|
71
|
+
|
72
|
+
PASS_NOT_FOUND = Class.new { # :nodoc:
|
73
|
+
def self.action(_); self; end
|
74
|
+
def self.call(_); [404, { "X-Cascade" => "pass" }, []]; end
|
75
|
+
def self.binary_params_for?(action); false; end
|
76
|
+
}
|
77
|
+
|
78
|
+
def controller_class
|
79
|
+
params = path_parameters
|
80
|
+
params[:action] ||= "index"
|
81
|
+
controller_class_for(params[:controller])
|
82
|
+
end
|
83
|
+
|
84
|
+
def controller_class_for(name)
|
85
|
+
if name
|
86
|
+
controller_param = name.underscore
|
87
|
+
const_name = "#{controller_param.camelize}Controller"
|
88
|
+
ActiveSupport::Dependencies.constantize(const_name)
|
89
|
+
else
|
90
|
+
PASS_NOT_FOUND
|
64
91
|
end
|
65
92
|
end
|
66
93
|
|
94
|
+
# Returns true if the request has a header matching the given key parameter.
|
95
|
+
#
|
96
|
+
# request.key? :ip_spoofing_check # => true
|
67
97
|
def key?(key)
|
68
|
-
|
98
|
+
has_header? key
|
69
99
|
end
|
70
100
|
|
71
101
|
# List of HTTP request methods from the following RFCs:
|
72
|
-
# Hypertext Transfer Protocol -- HTTP/1.1 (
|
73
|
-
# HTTP Extensions for Distributed Authoring -- WEBDAV (
|
74
|
-
# Versioning Extensions to WebDAV (
|
75
|
-
# Ordered Collections Protocol (WebDAV) (
|
76
|
-
# Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (
|
77
|
-
# Web Distributed Authoring and Versioning (WebDAV) SEARCH (
|
78
|
-
# Calendar Extensions to WebDAV (
|
79
|
-
# PATCH Method for HTTP (
|
102
|
+
# Hypertext Transfer Protocol -- HTTP/1.1 (https://www.ietf.org/rfc/rfc2616.txt)
|
103
|
+
# HTTP Extensions for Distributed Authoring -- WEBDAV (https://www.ietf.org/rfc/rfc2518.txt)
|
104
|
+
# Versioning Extensions to WebDAV (https://www.ietf.org/rfc/rfc3253.txt)
|
105
|
+
# Ordered Collections Protocol (WebDAV) (https://www.ietf.org/rfc/rfc3648.txt)
|
106
|
+
# Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (https://www.ietf.org/rfc/rfc3744.txt)
|
107
|
+
# Web Distributed Authoring and Versioning (WebDAV) SEARCH (https://www.ietf.org/rfc/rfc5323.txt)
|
108
|
+
# Calendar Extensions to WebDAV (https://www.ietf.org/rfc/rfc4791.txt)
|
109
|
+
# PATCH Method for HTTP (https://www.ietf.org/rfc/rfc5789.txt)
|
80
110
|
RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
|
81
111
|
RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
|
82
112
|
RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
|
@@ -90,7 +120,7 @@ module ActionDispatch
|
|
90
120
|
|
91
121
|
HTTP_METHOD_LOOKUP = {}
|
92
122
|
|
93
|
-
# Populate the HTTP method lookup cache
|
123
|
+
# Populate the HTTP method lookup cache.
|
94
124
|
HTTP_METHODS.each { |method|
|
95
125
|
HTTP_METHOD_LOOKUP[method] = method.underscore.to_sym
|
96
126
|
}
|
@@ -102,73 +132,89 @@ module ActionDispatch
|
|
102
132
|
# the application should use), this \method returns the overridden
|
103
133
|
# value, not the original.
|
104
134
|
def request_method
|
105
|
-
@request_method ||= check_method(
|
135
|
+
@request_method ||= check_method(super)
|
106
136
|
end
|
107
137
|
|
108
|
-
def
|
109
|
-
|
110
|
-
@request_method = env["REQUEST_METHOD"] = request_method
|
111
|
-
end
|
138
|
+
def routes # :nodoc:
|
139
|
+
get_header("action_dispatch.routes".freeze)
|
112
140
|
end
|
113
141
|
|
114
|
-
|
115
|
-
|
116
|
-
HTTP_METHOD_LOOKUP[request_method]
|
142
|
+
def routes=(routes) # :nodoc:
|
143
|
+
set_header("action_dispatch.routes".freeze, routes)
|
117
144
|
end
|
118
145
|
|
119
|
-
|
120
|
-
|
121
|
-
# more information.
|
122
|
-
def method
|
123
|
-
@method ||= check_method(env["rack.methodoverride.original_method"] || env['REQUEST_METHOD'])
|
146
|
+
def engine_script_name(_routes) # :nodoc:
|
147
|
+
get_header(_routes.env_key)
|
124
148
|
end
|
125
149
|
|
126
|
-
|
127
|
-
|
128
|
-
HTTP_METHOD_LOOKUP[method]
|
150
|
+
def engine_script_name=(name) # :nodoc:
|
151
|
+
set_header(routes.env_key, name.dup)
|
129
152
|
end
|
130
153
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
154
|
+
def request_method=(request_method) #:nodoc:
|
155
|
+
if check_method(request_method)
|
156
|
+
@request_method = set_header("REQUEST_METHOD", request_method)
|
157
|
+
end
|
135
158
|
end
|
136
159
|
|
137
|
-
|
138
|
-
|
139
|
-
def post?
|
140
|
-
HTTP_METHOD_LOOKUP[request_method] == :post
|
160
|
+
def controller_instance # :nodoc:
|
161
|
+
get_header("action_controller.instance".freeze)
|
141
162
|
end
|
142
163
|
|
143
|
-
|
144
|
-
|
145
|
-
def patch?
|
146
|
-
HTTP_METHOD_LOOKUP[request_method] == :patch
|
164
|
+
def controller_instance=(controller) # :nodoc:
|
165
|
+
set_header("action_controller.instance".freeze, controller)
|
147
166
|
end
|
148
167
|
|
149
|
-
|
150
|
-
|
151
|
-
def put?
|
152
|
-
HTTP_METHOD_LOOKUP[request_method] == :put
|
168
|
+
def http_auth_salt
|
169
|
+
get_header "action_dispatch.http_auth_salt"
|
153
170
|
end
|
154
171
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
172
|
+
def show_exceptions? # :nodoc:
|
173
|
+
# We're treating `nil` as "unset", and we want the default setting to be
|
174
|
+
# `true`. This logic should be extracted to `env_config` and calculated
|
175
|
+
# once.
|
176
|
+
!(get_header("action_dispatch.show_exceptions".freeze) == false)
|
159
177
|
end
|
160
178
|
|
161
|
-
#
|
162
|
-
|
163
|
-
|
164
|
-
|
179
|
+
# Returns a symbol form of the #request_method.
|
180
|
+
def request_method_symbol
|
181
|
+
HTTP_METHOD_LOOKUP[request_method]
|
182
|
+
end
|
183
|
+
|
184
|
+
# Returns the original value of the environment's REQUEST_METHOD,
|
185
|
+
# even if it was overridden by middleware. See #request_method for
|
186
|
+
# more information.
|
187
|
+
def method
|
188
|
+
@method ||= check_method(get_header("rack.methodoverride.original_method") || get_header("REQUEST_METHOD"))
|
189
|
+
end
|
190
|
+
|
191
|
+
# Returns a symbol form of the #method.
|
192
|
+
def method_symbol
|
193
|
+
HTTP_METHOD_LOOKUP[method]
|
165
194
|
end
|
166
195
|
|
167
196
|
# Provides access to the request's HTTP headers, for example:
|
168
197
|
#
|
169
198
|
# request.headers["Content-Type"] # => "text/plain"
|
170
199
|
def headers
|
171
|
-
Http::Headers.new(
|
200
|
+
@headers ||= Http::Headers.new(self)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Early Hints is an HTTP/2 status code that indicates hints to help a client start
|
204
|
+
# making preparations for processing the final response.
|
205
|
+
#
|
206
|
+
# If the env contains +rack.early_hints+ then the server accepts HTTP2 push for Link headers.
|
207
|
+
#
|
208
|
+
# The +send_early_hints+ method accepts a hash of links as follows:
|
209
|
+
#
|
210
|
+
# send_early_hints("Link" => "</style.css>; rel=preload; as=style\n</script.js>; rel=preload")
|
211
|
+
#
|
212
|
+
# If you are using +javascript_include_tag+ or +stylesheet_link_tag+ the
|
213
|
+
# Early Hints headers are included by default if supported.
|
214
|
+
def send_early_hints(links)
|
215
|
+
return unless env["rack.early_hints"]
|
216
|
+
|
217
|
+
env["rack.early_hints"].call(links)
|
172
218
|
end
|
173
219
|
|
174
220
|
# Returns a +String+ with the last requested path including their params.
|
@@ -179,7 +225,7 @@ module ActionDispatch
|
|
179
225
|
# # get '/foo?bar'
|
180
226
|
# request.original_fullpath # => '/foo?bar'
|
181
227
|
def original_fullpath
|
182
|
-
@original_fullpath ||= (
|
228
|
+
@original_fullpath ||= (get_header("ORIGINAL_FULLPATH") || fullpath)
|
183
229
|
end
|
184
230
|
|
185
231
|
# Returns the +String+ full path including params of the last URL requested.
|
@@ -218,62 +264,84 @@ module ActionDispatch
|
|
218
264
|
# (case-insensitive), which may need to be manually added depending on the
|
219
265
|
# choice of JavaScript libraries and frameworks.
|
220
266
|
def xml_http_request?
|
221
|
-
|
267
|
+
get_header("HTTP_X_REQUESTED_WITH") =~ /XMLHttpRequest/i
|
222
268
|
end
|
223
269
|
alias :xhr? :xml_http_request?
|
224
270
|
|
271
|
+
# Returns the IP address of client as a +String+.
|
225
272
|
def ip
|
226
273
|
@ip ||= super
|
227
274
|
end
|
228
275
|
|
229
|
-
#
|
276
|
+
# Returns the IP address of client as a +String+,
|
277
|
+
# usually set by the RemoteIp middleware.
|
230
278
|
def remote_ip
|
231
|
-
@remote_ip ||= (
|
279
|
+
@remote_ip ||= (get_header("action_dispatch.remote_ip") || ip).to_s
|
232
280
|
end
|
233
281
|
|
282
|
+
def remote_ip=(remote_ip)
|
283
|
+
set_header "action_dispatch.remote_ip".freeze, remote_ip
|
284
|
+
end
|
285
|
+
|
286
|
+
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id".freeze # :nodoc:
|
287
|
+
|
234
288
|
# Returns the unique request id, which is based on either the X-Request-Id header that can
|
235
289
|
# be generated by a firewall, load balancer, or web server or by the RequestId middleware
|
236
290
|
# (which sets the action_dispatch.request_id environment variable).
|
237
291
|
#
|
238
292
|
# This unique ID is useful for tracing a request from end-to-end as part of logging or debugging.
|
239
|
-
# This relies on the
|
240
|
-
def
|
241
|
-
|
293
|
+
# This relies on the Rack variable set by the ActionDispatch::RequestId middleware.
|
294
|
+
def request_id
|
295
|
+
get_header ACTION_DISPATCH_REQUEST_ID
|
296
|
+
end
|
297
|
+
|
298
|
+
def request_id=(id) # :nodoc:
|
299
|
+
set_header ACTION_DISPATCH_REQUEST_ID, id
|
242
300
|
end
|
243
301
|
|
302
|
+
alias_method :uuid, :request_id
|
303
|
+
|
244
304
|
# Returns the lowercase name of the HTTP server software.
|
245
305
|
def server_software
|
246
|
-
(
|
306
|
+
(get_header("SERVER_SOFTWARE") && /^([a-zA-Z]+)/ =~ get_header("SERVER_SOFTWARE")) ? $1.downcase : nil
|
247
307
|
end
|
248
308
|
|
249
309
|
# Read the request \body. This is useful for web services that need to
|
250
310
|
# work with raw requests directly.
|
251
311
|
def raw_post
|
252
|
-
unless
|
312
|
+
unless has_header? "RAW_POST_DATA"
|
253
313
|
raw_post_body = body
|
254
|
-
|
314
|
+
set_header("RAW_POST_DATA", raw_post_body.read(content_length))
|
255
315
|
raw_post_body.rewind if raw_post_body.respond_to?(:rewind)
|
256
316
|
end
|
257
|
-
|
317
|
+
get_header "RAW_POST_DATA"
|
258
318
|
end
|
259
319
|
|
260
320
|
# The request body is an IO input stream. If the RAW_POST_DATA environment
|
261
321
|
# variable is already set, wrap it in a StringIO.
|
262
322
|
def body
|
263
|
-
if raw_post =
|
264
|
-
raw_post.force_encoding(Encoding::BINARY)
|
323
|
+
if raw_post = get_header("RAW_POST_DATA")
|
324
|
+
raw_post = raw_post.dup.force_encoding(Encoding::BINARY)
|
265
325
|
StringIO.new(raw_post)
|
266
326
|
else
|
267
|
-
|
327
|
+
body_stream
|
268
328
|
end
|
269
329
|
end
|
270
330
|
|
331
|
+
# Determine whether the request body contains form-data by checking
|
332
|
+
# the request Content-Type for one of the media-types:
|
333
|
+
# "application/x-www-form-urlencoded" or "multipart/form-data". The
|
334
|
+
# list of form-data media types can be modified through the
|
335
|
+
# +FORM_DATA_MEDIA_TYPES+ array.
|
336
|
+
#
|
337
|
+
# A request body is not assumed to contain form-data when no
|
338
|
+
# Content-Type header is provided and the request_method is POST.
|
271
339
|
def form_data?
|
272
|
-
FORM_DATA_MEDIA_TYPES.include?(
|
340
|
+
FORM_DATA_MEDIA_TYPES.include?(media_type)
|
273
341
|
end
|
274
342
|
|
275
343
|
def body_stream #:nodoc:
|
276
|
-
|
344
|
+
get_header("rack.input")
|
277
345
|
end
|
278
346
|
|
279
347
|
# TODO This should be broken apart into AD::Request::Session and probably
|
@@ -284,60 +352,74 @@ module ActionDispatch
|
|
284
352
|
else
|
285
353
|
self.session = {}
|
286
354
|
end
|
287
|
-
@env['action_dispatch.request.flash_hash'] = nil
|
288
355
|
end
|
289
356
|
|
290
357
|
def session=(session) #:nodoc:
|
291
|
-
Session.set
|
358
|
+
Session.set self, session
|
292
359
|
end
|
293
360
|
|
294
361
|
def session_options=(options)
|
295
|
-
Session::Options.set
|
362
|
+
Session::Options.set self, options
|
296
363
|
end
|
297
364
|
|
298
|
-
# Override Rack's GET method to support indifferent access
|
365
|
+
# Override Rack's GET method to support indifferent access.
|
299
366
|
def GET
|
300
|
-
|
367
|
+
fetch_header("action_dispatch.request.query_parameters") do |k|
|
368
|
+
rack_query_params = super || {}
|
369
|
+
# Check for non UTF-8 parameter values, which would cause errors later
|
370
|
+
Request::Utils.check_param_encoding(rack_query_params)
|
371
|
+
set_header k, Request::Utils.normalize_encode_params(rack_query_params)
|
372
|
+
end
|
301
373
|
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
302
|
-
raise ActionController::BadRequest.new(
|
374
|
+
raise ActionController::BadRequest.new("Invalid query parameters: #{e.message}")
|
303
375
|
end
|
304
376
|
alias :query_parameters :GET
|
305
377
|
|
306
|
-
# Override Rack's POST method to support indifferent access
|
378
|
+
# Override Rack's POST method to support indifferent access.
|
307
379
|
def POST
|
308
|
-
|
380
|
+
fetch_header("action_dispatch.request.request_parameters") do
|
381
|
+
pr = parse_formatted_parameters(params_parsers) do |params|
|
382
|
+
super || {}
|
383
|
+
end
|
384
|
+
self.request_parameters = Request::Utils.normalize_encode_params(pr)
|
385
|
+
end
|
386
|
+
rescue Http::Parameters::ParseError # one of the parse strategies blew up
|
387
|
+
self.request_parameters = Request::Utils.normalize_encode_params(super || {})
|
388
|
+
raise
|
309
389
|
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
310
|
-
raise ActionController::BadRequest.new(
|
390
|
+
raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
|
311
391
|
end
|
312
392
|
alias :request_parameters :POST
|
313
393
|
|
314
394
|
# Returns the authorization header regardless of whether it was specified directly or through one of the
|
315
395
|
# proxy alternatives.
|
316
396
|
def authorization
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
397
|
+
get_header("HTTP_AUTHORIZATION") ||
|
398
|
+
get_header("X-HTTP_AUTHORIZATION") ||
|
399
|
+
get_header("X_HTTP_AUTHORIZATION") ||
|
400
|
+
get_header("REDIRECT_X_HTTP_AUTHORIZATION")
|
321
401
|
end
|
322
402
|
|
323
|
-
# True if the request came from localhost, 127.0.0.1.
|
403
|
+
# True if the request came from localhost, 127.0.0.1, or ::1.
|
324
404
|
def local?
|
325
405
|
LOCALHOST =~ remote_addr && LOCALHOST =~ remote_ip
|
326
406
|
end
|
327
407
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
)
|
408
|
+
def request_parameters=(params)
|
409
|
+
raise if params.nil?
|
410
|
+
set_header("action_dispatch.request.request_parameters".freeze, params)
|
411
|
+
end
|
333
412
|
|
334
|
-
|
413
|
+
def logger
|
414
|
+
get_header("action_dispatch.logger".freeze)
|
335
415
|
end
|
336
416
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
417
|
+
def commit_flash
|
418
|
+
end
|
419
|
+
|
420
|
+
def ssl?
|
421
|
+
super || scheme == "wss".freeze
|
422
|
+
end
|
341
423
|
|
342
424
|
private
|
343
425
|
def check_method(name)
|