actionpack 4.1.7 → 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +311 -527
- data/README.rdoc +7 -2
- data/lib/abstract_controller/base.rb +16 -6
- data/lib/abstract_controller/callbacks.rb +28 -51
- data/lib/abstract_controller/helpers.rb +11 -4
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
- data/lib/abstract_controller/url_for.rb +1 -1
- data/lib/action_controller/base.rb +2 -1
- data/lib/action_controller/caching/fragments.rb +7 -1
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +26 -26
- data/lib/action_controller/metal/conditional_get.rb +37 -12
- data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
- data/lib/action_controller/metal/exceptions.rb +1 -1
- data/lib/action_controller/metal/force_ssl.rb +1 -1
- data/lib/action_controller/metal/head.rb +7 -3
- data/lib/action_controller/metal/http_authentication.rb +14 -9
- data/lib/action_controller/metal/instrumentation.rb +8 -5
- data/lib/action_controller/metal/live.rb +57 -6
- data/lib/action_controller/metal/mime_responds.rb +23 -246
- data/lib/action_controller/metal/params_wrapper.rb +2 -2
- data/lib/action_controller/metal/rack_delegation.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +14 -8
- data/lib/action_controller/metal/renderers.rb +30 -10
- data/lib/action_controller/metal/rendering.rb +2 -6
- data/lib/action_controller/metal/request_forgery_protection.rb +78 -7
- data/lib/action_controller/metal/streaming.rb +1 -1
- data/lib/action_controller/metal/strong_parameters.rb +125 -12
- data/lib/action_controller/metal/url_for.rb +11 -12
- data/lib/action_controller/metal.rb +12 -11
- data/lib/action_controller/model_naming.rb +1 -1
- data/lib/action_controller/railtie.rb +4 -0
- data/lib/action_controller/test_case.rb +112 -75
- data/lib/action_controller.rb +1 -1
- data/lib/action_dispatch/http/cache.rb +5 -4
- data/lib/action_dispatch/http/filter_parameters.rb +2 -2
- data/lib/action_dispatch/http/headers.rb +43 -9
- data/lib/action_dispatch/http/mime_negotiation.rb +10 -3
- data/lib/action_dispatch/http/mime_type.rb +2 -2
- data/lib/action_dispatch/http/parameter_filter.rb +1 -1
- data/lib/action_dispatch/http/parameters.rb +11 -26
- data/lib/action_dispatch/http/request.rb +37 -11
- data/lib/action_dispatch/http/response.rb +70 -18
- data/lib/action_dispatch/http/upload.rb +3 -8
- data/lib/action_dispatch/http/url.rb +88 -69
- data/lib/action_dispatch/journey/formatter.rb +33 -17
- data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +20 -28
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
- data/lib/action_dispatch/journey/nodes/node.rb +4 -0
- data/lib/action_dispatch/journey/parser.rb +52 -60
- data/lib/action_dispatch/journey/parser.y +11 -10
- data/lib/action_dispatch/journey/path/pattern.rb +16 -19
- data/lib/action_dispatch/journey/route.rb +3 -18
- data/lib/action_dispatch/journey/router/strexp.rb +9 -6
- data/lib/action_dispatch/journey/router.rb +53 -77
- data/lib/action_dispatch/journey/scanner.rb +5 -5
- data/lib/action_dispatch/journey/visitors.rb +81 -92
- data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
- data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
- data/lib/action_dispatch/middleware/callbacks.rb +1 -1
- data/lib/action_dispatch/middleware/cookies.rb +29 -29
- data/lib/action_dispatch/middleware/debug_exceptions.rb +15 -4
- data/lib/action_dispatch/middleware/exception_wrapper.rb +50 -18
- data/lib/action_dispatch/middleware/flash.rb +13 -7
- data/lib/action_dispatch/middleware/params_parser.rb +1 -1
- data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
- data/lib/action_dispatch/middleware/request_id.rb +1 -1
- data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +1 -0
- data/lib/action_dispatch/middleware/static.rb +66 -37
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +37 -9
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +2 -8
- data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +2 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -24
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +0 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
- data/lib/action_dispatch/routing/endpoint.rb +10 -0
- data/lib/action_dispatch/routing/inspector.rb +5 -12
- data/lib/action_dispatch/routing/mapper.rb +410 -281
- data/lib/action_dispatch/routing/polymorphic_routes.rb +191 -79
- data/lib/action_dispatch/routing/redirection.rb +10 -12
- data/lib/action_dispatch/routing/route_set.rb +297 -168
- data/lib/action_dispatch/routing/url_for.rb +15 -4
- data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
- data/lib/action_dispatch/testing/assertions/response.rb +2 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
- data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
- data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
- data/lib/action_dispatch/testing/assertions.rb +11 -7
- data/lib/action_dispatch/testing/integration.rb +24 -19
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +7 -0
- data/lib/action_pack/gem_version.rb +3 -3
- metadata +55 -13
- data/lib/action_controller/metal/responder.rb +0 -297
data/lib/action_controller.rb
CHANGED
|
@@ -17,6 +17,7 @@ module ActionController
|
|
|
17
17
|
autoload :ConditionalGet
|
|
18
18
|
autoload :Cookies
|
|
19
19
|
autoload :DataStreaming
|
|
20
|
+
autoload :EtagWithTemplateDigest
|
|
20
21
|
autoload :Flash
|
|
21
22
|
autoload :ForceSSL
|
|
22
23
|
autoload :Head
|
|
@@ -33,7 +34,6 @@ module ActionController
|
|
|
33
34
|
autoload :Rendering
|
|
34
35
|
autoload :RequestForgeryProtection
|
|
35
36
|
autoload :Rescue
|
|
36
|
-
autoload :Responder
|
|
37
37
|
autoload :Streaming
|
|
38
38
|
autoload :StrongParameters
|
|
39
39
|
autoload :Testing
|
|
@@ -69,17 +69,17 @@ module ActionDispatch
|
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def date
|
|
72
|
-
if date_header = headers[
|
|
72
|
+
if date_header = headers[DATE]
|
|
73
73
|
Time.httpdate(date_header)
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def date?
|
|
78
|
-
headers.include?(
|
|
78
|
+
headers.include?(DATE)
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
def date=(utc_time)
|
|
82
|
-
headers[
|
|
82
|
+
headers[DATE] = utc_time.httpdate
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
def etag=(etag)
|
|
@@ -89,10 +89,11 @@ module ActionDispatch
|
|
|
89
89
|
|
|
90
90
|
private
|
|
91
91
|
|
|
92
|
+
DATE = 'Date'.freeze
|
|
92
93
|
LAST_MODIFIED = "Last-Modified".freeze
|
|
93
94
|
ETAG = "ETag".freeze
|
|
94
95
|
CACHE_CONTROL = "Cache-Control".freeze
|
|
95
|
-
SPECIAL_KEYS = %w[extras no-cache max-age public must-revalidate]
|
|
96
|
+
SPECIAL_KEYS = Set.new(%w[extras no-cache max-age public must-revalidate])
|
|
96
97
|
|
|
97
98
|
def cache_control_segments
|
|
98
99
|
if cache_control = self[CACHE_CONTROL]
|
|
@@ -6,8 +6,8 @@ module ActionDispatch
|
|
|
6
6
|
module Http
|
|
7
7
|
# Allows you to specify sensitive parameters which will be replaced from
|
|
8
8
|
# the request log by looking in the query string of the request and all
|
|
9
|
-
#
|
|
10
|
-
# value of the params hash and all
|
|
9
|
+
# sub-hashes of the params hash to filter. If a block is given, each key and
|
|
10
|
+
# value of the params hash and all sub-hashes is passed to it, the value
|
|
11
11
|
# or key can be replaced using String#replace or similar method.
|
|
12
12
|
#
|
|
13
13
|
# env["action_dispatch.parameter_filter"] = [:password]
|
|
@@ -1,27 +1,47 @@
|
|
|
1
1
|
module ActionDispatch
|
|
2
2
|
module Http
|
|
3
|
+
# Provides access to the request's HTTP headers from the environment.
|
|
4
|
+
#
|
|
5
|
+
# env = { "CONTENT_TYPE" => "text/plain" }
|
|
6
|
+
# headers = ActionDispatch::Http::Headers.new(env)
|
|
7
|
+
# headers["Content-Type"] # => "text/plain"
|
|
3
8
|
class Headers
|
|
4
|
-
CGI_VARIABLES = %
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
CGI_VARIABLES = Set.new(%W[
|
|
10
|
+
AUTH_TYPE
|
|
11
|
+
CONTENT_LENGTH
|
|
12
|
+
CONTENT_TYPE
|
|
13
|
+
GATEWAY_INTERFACE
|
|
14
|
+
HTTPS
|
|
15
|
+
PATH_INFO
|
|
16
|
+
PATH_TRANSLATED
|
|
17
|
+
QUERY_STRING
|
|
18
|
+
REMOTE_ADDR
|
|
19
|
+
REMOTE_HOST
|
|
20
|
+
REMOTE_IDENT
|
|
21
|
+
REMOTE_USER
|
|
22
|
+
REQUEST_METHOD
|
|
23
|
+
SCRIPT_NAME
|
|
24
|
+
SERVER_NAME
|
|
25
|
+
SERVER_PORT
|
|
26
|
+
SERVER_PROTOCOL
|
|
27
|
+
SERVER_SOFTWARE
|
|
28
|
+
]).freeze
|
|
29
|
+
|
|
12
30
|
HTTP_HEADER = /\A[A-Za-z0-9-]+\z/
|
|
13
31
|
|
|
14
32
|
include Enumerable
|
|
15
33
|
attr_reader :env
|
|
16
34
|
|
|
17
|
-
def initialize(env = {})
|
|
35
|
+
def initialize(env = {}) # :nodoc:
|
|
18
36
|
@env = env
|
|
19
37
|
end
|
|
20
38
|
|
|
39
|
+
# Returns the value for the given key mapped to @env.
|
|
21
40
|
def [](key)
|
|
22
41
|
@env[env_name(key)]
|
|
23
42
|
end
|
|
24
43
|
|
|
44
|
+
# Sets the given value for the key mapped to @env.
|
|
25
45
|
def []=(key, value)
|
|
26
46
|
@env[env_name(key)] = value
|
|
27
47
|
end
|
|
@@ -31,6 +51,13 @@ module ActionDispatch
|
|
|
31
51
|
end
|
|
32
52
|
alias :include? :key?
|
|
33
53
|
|
|
54
|
+
# Returns the value for the given key mapped to @env.
|
|
55
|
+
#
|
|
56
|
+
# If the key is not found and an optional code block is not provided,
|
|
57
|
+
# raises a <tt>KeyError</tt> exception.
|
|
58
|
+
#
|
|
59
|
+
# If the code block is provided, then it will be run and
|
|
60
|
+
# its result returned.
|
|
34
61
|
def fetch(key, *args, &block)
|
|
35
62
|
@env.fetch env_name(key), *args, &block
|
|
36
63
|
end
|
|
@@ -39,12 +66,17 @@ module ActionDispatch
|
|
|
39
66
|
@env.each(&block)
|
|
40
67
|
end
|
|
41
68
|
|
|
69
|
+
# Returns a new Http::Headers instance containing the contents of
|
|
70
|
+
# <tt>headers_or_env</tt> and the original instance.
|
|
42
71
|
def merge(headers_or_env)
|
|
43
72
|
headers = Http::Headers.new(env.dup)
|
|
44
73
|
headers.merge!(headers_or_env)
|
|
45
74
|
headers
|
|
46
75
|
end
|
|
47
76
|
|
|
77
|
+
# Adds the contents of <tt>headers_or_env</tt> to original instance
|
|
78
|
+
# entries; duplicate keys are overwritten with the values from
|
|
79
|
+
# <tt>headers_or_env</tt>.
|
|
48
80
|
def merge!(headers_or_env)
|
|
49
81
|
headers_or_env.each do |key, value|
|
|
50
82
|
self[env_name(key)] = value
|
|
@@ -52,6 +84,8 @@ module ActionDispatch
|
|
|
52
84
|
end
|
|
53
85
|
|
|
54
86
|
private
|
|
87
|
+
# Converts a HTTP header name to an environment variable name if it is
|
|
88
|
+
# not contained within the headers hash.
|
|
55
89
|
def env_name(key)
|
|
56
90
|
key = key.to_s
|
|
57
91
|
if key =~ HTTP_HEADER
|
|
@@ -54,8 +54,14 @@ module ActionDispatch
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def formats
|
|
57
|
-
@env["action_dispatch.request.formats"] ||=
|
|
58
|
-
|
|
57
|
+
@env["action_dispatch.request.formats"] ||= begin
|
|
58
|
+
params_readable = begin
|
|
59
|
+
parameters[:format]
|
|
60
|
+
rescue ActionController::BadRequest
|
|
61
|
+
false
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
if params_readable
|
|
59
65
|
Array(Mime[parameters[:format]])
|
|
60
66
|
elsif use_accept_header && valid_accept_header
|
|
61
67
|
accepts
|
|
@@ -64,13 +70,14 @@ module ActionDispatch
|
|
|
64
70
|
else
|
|
65
71
|
[Mime::HTML]
|
|
66
72
|
end
|
|
73
|
+
end
|
|
67
74
|
end
|
|
68
75
|
|
|
69
76
|
# Sets the \variant for template.
|
|
70
77
|
def variant=(variant)
|
|
71
78
|
if variant.is_a?(Symbol)
|
|
72
79
|
@variant = [variant]
|
|
73
|
-
elsif variant.is_a?(Array) && variant.any? && variant.all?{ |v| v.is_a?(Symbol) }
|
|
80
|
+
elsif variant.nil? || variant.is_a?(Array) && variant.any? && variant.all?{ |v| v.is_a?(Symbol) }
|
|
74
81
|
@variant = variant
|
|
75
82
|
else
|
|
76
83
|
raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols, not a #{variant.class}. " \
|
|
@@ -45,8 +45,8 @@ module Mime
|
|
|
45
45
|
#
|
|
46
46
|
# respond_to do |format|
|
|
47
47
|
# format.html
|
|
48
|
-
# format.ics { render text: post.to_ics, mime_type: Mime::Type["text/calendar"] }
|
|
49
|
-
# format.xml { render xml: @
|
|
48
|
+
# format.ics { render text: @post.to_ics, mime_type: Mime::Type["text/calendar"] }
|
|
49
|
+
# format.xml { render xml: @post }
|
|
50
50
|
# end
|
|
51
51
|
# end
|
|
52
52
|
# end
|
|
@@ -56,7 +56,7 @@ module ActionDispatch
|
|
|
56
56
|
elsif value.is_a?(Array)
|
|
57
57
|
value = value.map { |v| v.is_a?(Hash) ? call(v) : v }
|
|
58
58
|
elsif blocks.any?
|
|
59
|
-
key = key.dup
|
|
59
|
+
key = key.dup if key.duplicable?
|
|
60
60
|
value = value.dup if value.duplicable?
|
|
61
61
|
blocks.each { |b| b.call(key, value) }
|
|
62
62
|
end
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
require 'active_support/core_ext/hash/keys'
|
|
2
2
|
require 'active_support/core_ext/hash/indifferent_access'
|
|
3
|
+
require 'active_support/deprecation'
|
|
3
4
|
|
|
4
5
|
module ActionDispatch
|
|
5
6
|
module Http
|
|
6
7
|
module Parameters
|
|
7
|
-
|
|
8
|
-
super
|
|
9
|
-
@symbolized_path_params = nil
|
|
10
|
-
end
|
|
8
|
+
PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
|
|
11
9
|
|
|
12
10
|
# Returns both GET and POST \parameters in a single hash.
|
|
13
11
|
def parameters
|
|
@@ -18,55 +16,42 @@ module ActionDispatch
|
|
|
18
16
|
query_parameters.dup
|
|
19
17
|
end
|
|
20
18
|
params.merge!(path_parameters)
|
|
21
|
-
params.with_indifferent_access
|
|
22
19
|
end
|
|
23
20
|
end
|
|
24
21
|
alias :params :parameters
|
|
25
22
|
|
|
26
23
|
def path_parameters=(parameters) #:nodoc:
|
|
27
|
-
@
|
|
28
|
-
@env
|
|
29
|
-
@env["action_dispatch.request.path_parameters"] = parameters
|
|
24
|
+
@env.delete('action_dispatch.request.parameters')
|
|
25
|
+
@env[PARAMETERS_KEY] = parameters
|
|
30
26
|
end
|
|
31
27
|
|
|
32
|
-
# The same as <tt>path_parameters</tt> with explicitly symbolized keys.
|
|
33
28
|
def symbolized_path_parameters
|
|
34
|
-
|
|
29
|
+
ActiveSupport::Deprecation.warn(
|
|
30
|
+
'`symbolized_path_parameters` is deprecated. Please use `path_parameters`.'
|
|
31
|
+
)
|
|
32
|
+
path_parameters
|
|
35
33
|
end
|
|
36
34
|
|
|
37
35
|
# Returns a hash with the \parameters used to form the \path of the request.
|
|
38
36
|
# Returned hash keys are strings:
|
|
39
37
|
#
|
|
40
38
|
# {'action' => 'my_action', 'controller' => 'my_controller'}
|
|
41
|
-
#
|
|
42
|
-
# See <tt>symbolized_path_parameters</tt> for symbolized keys.
|
|
43
39
|
def path_parameters
|
|
44
|
-
@env[
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def reset_parameters #:nodoc:
|
|
48
|
-
@env.delete("action_dispatch.request.parameters")
|
|
40
|
+
@env[PARAMETERS_KEY] ||= {}
|
|
49
41
|
end
|
|
50
42
|
|
|
51
43
|
private
|
|
52
44
|
|
|
53
|
-
# Convert nested Hash to HashWithIndifferentAccess
|
|
54
|
-
# and UTF-8 encode both keys and values in nested Hash.
|
|
45
|
+
# Convert nested Hash to HashWithIndifferentAccess.
|
|
55
46
|
#
|
|
56
|
-
# TODO: Validate that the characters are UTF-8. If they aren't,
|
|
57
|
-
# you'll get a weird error down the road, but our form handling
|
|
58
|
-
# should really prevent that from happening
|
|
59
47
|
def normalize_encode_params(params)
|
|
60
48
|
case params
|
|
61
|
-
when String
|
|
62
|
-
params.force_encoding(Encoding::UTF_8).encode!
|
|
63
49
|
when Hash
|
|
64
50
|
if params.has_key?(:tempfile)
|
|
65
51
|
UploadedFile.new(params)
|
|
66
52
|
else
|
|
67
53
|
params.each_with_object({}) do |(key, val), new_hash|
|
|
68
|
-
|
|
69
|
-
new_hash[new_key] = if val.is_a?(Array)
|
|
54
|
+
new_hash[key] = if val.is_a?(Array)
|
|
70
55
|
val.map! { |el| normalize_encode_params(el) }
|
|
71
56
|
else
|
|
72
57
|
normalize_encode_params(val)
|
|
@@ -23,7 +23,7 @@ module ActionDispatch
|
|
|
23
23
|
autoload :Session, 'action_dispatch/request/session'
|
|
24
24
|
autoload :Utils, 'action_dispatch/request/utils'
|
|
25
25
|
|
|
26
|
-
LOCALHOST = Regexp.union [/^127
|
|
26
|
+
LOCALHOST = Regexp.union [/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/]
|
|
27
27
|
|
|
28
28
|
ENV_METHODS = %w[ AUTH_TYPE GATEWAY_INTERFACE
|
|
29
29
|
PATH_TRANSLATED REMOTE_HOST
|
|
@@ -53,6 +53,17 @@ module ActionDispatch
|
|
|
53
53
|
@uuid = nil
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
def check_path_parameters!
|
|
57
|
+
# If any of the path parameters has an invalid encoding then
|
|
58
|
+
# raise since it's likely to trigger errors further on.
|
|
59
|
+
path_parameters.each do |key, value|
|
|
60
|
+
next unless value.respond_to?(:valid_encoding?)
|
|
61
|
+
unless value.valid_encoding?
|
|
62
|
+
raise ActionController::BadRequest, "Invalid parameter: #{key} => #{value}"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
56
67
|
def key?(key)
|
|
57
68
|
@env.key?(key)
|
|
58
69
|
end
|
|
@@ -64,6 +75,7 @@ module ActionDispatch
|
|
|
64
75
|
# Ordered Collections Protocol (WebDAV) (http://www.ietf.org/rfc/rfc3648.txt)
|
|
65
76
|
# Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (http://www.ietf.org/rfc/rfc3744.txt)
|
|
66
77
|
# Web Distributed Authoring and Versioning (WebDAV) SEARCH (http://www.ietf.org/rfc/rfc5323.txt)
|
|
78
|
+
# Calendar Extensions to WebDAV (http://www.ietf.org/rfc/rfc4791.txt)
|
|
67
79
|
# PATCH Method for HTTP (http://www.ietf.org/rfc/rfc5789.txt)
|
|
68
80
|
RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
|
|
69
81
|
RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
|
|
@@ -71,9 +83,10 @@ module ActionDispatch
|
|
|
71
83
|
RFC3648 = %w(ORDERPATCH)
|
|
72
84
|
RFC3744 = %w(ACL)
|
|
73
85
|
RFC5323 = %w(SEARCH)
|
|
86
|
+
RFC4791 = %w(MKCALENDAR)
|
|
74
87
|
RFC5789 = %w(PATCH)
|
|
75
88
|
|
|
76
|
-
HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789
|
|
89
|
+
HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789
|
|
77
90
|
|
|
78
91
|
HTTP_METHOD_LOOKUP = {}
|
|
79
92
|
|
|
@@ -92,6 +105,12 @@ module ActionDispatch
|
|
|
92
105
|
@request_method ||= check_method(env["REQUEST_METHOD"])
|
|
93
106
|
end
|
|
94
107
|
|
|
108
|
+
def request_method=(request_method) #:nodoc:
|
|
109
|
+
if check_method(request_method)
|
|
110
|
+
@request_method = env["REQUEST_METHOD"] = request_method
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
95
114
|
# Returns a symbol form of the #request_method
|
|
96
115
|
def request_method_symbol
|
|
97
116
|
HTTP_METHOD_LOOKUP[request_method]
|
|
@@ -152,6 +171,13 @@ module ActionDispatch
|
|
|
152
171
|
Http::Headers.new(@env)
|
|
153
172
|
end
|
|
154
173
|
|
|
174
|
+
# Returns a +String+ with the last requested path including their params.
|
|
175
|
+
#
|
|
176
|
+
# # get '/foo'
|
|
177
|
+
# request.original_fullpath # => '/foo'
|
|
178
|
+
#
|
|
179
|
+
# # get '/foo?bar'
|
|
180
|
+
# request.original_fullpath # => '/foo?bar'
|
|
155
181
|
def original_fullpath
|
|
156
182
|
@original_fullpath ||= (env["ORIGINAL_FULLPATH"] || fullpath)
|
|
157
183
|
end
|
|
@@ -189,8 +215,8 @@ module ActionDispatch
|
|
|
189
215
|
end
|
|
190
216
|
|
|
191
217
|
# Returns true if the "X-Requested-With" header contains "XMLHttpRequest"
|
|
192
|
-
# (case-insensitive)
|
|
193
|
-
#
|
|
218
|
+
# (case-insensitive), which may need to be manually added depending on the
|
|
219
|
+
# choice of JavaScript libraries and frameworks.
|
|
194
220
|
def xml_http_request?
|
|
195
221
|
@env['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/i
|
|
196
222
|
end
|
|
@@ -205,7 +231,7 @@ module ActionDispatch
|
|
|
205
231
|
@remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
|
|
206
232
|
end
|
|
207
233
|
|
|
208
|
-
# Returns the unique request id, which is based
|
|
234
|
+
# Returns the unique request id, which is based on either the X-Request-Id header that can
|
|
209
235
|
# be generated by a firewall, load balancer, or web server or by the RequestId middleware
|
|
210
236
|
# (which sets the action_dispatch.request_id environment variable).
|
|
211
237
|
#
|
|
@@ -271,16 +297,16 @@ module ActionDispatch
|
|
|
271
297
|
|
|
272
298
|
# Override Rack's GET method to support indifferent access
|
|
273
299
|
def GET
|
|
274
|
-
@env["action_dispatch.request.query_parameters"] ||= Utils.deep_munge(
|
|
275
|
-
rescue
|
|
300
|
+
@env["action_dispatch.request.query_parameters"] ||= Utils.deep_munge(normalize_encode_params(super || {}))
|
|
301
|
+
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
|
276
302
|
raise ActionController::BadRequest.new(:query, e)
|
|
277
303
|
end
|
|
278
304
|
alias :query_parameters :GET
|
|
279
305
|
|
|
280
306
|
# Override Rack's POST method to support indifferent access
|
|
281
307
|
def POST
|
|
282
|
-
@env["action_dispatch.request.request_parameters"] ||= Utils.deep_munge(
|
|
283
|
-
rescue
|
|
308
|
+
@env["action_dispatch.request.request_parameters"] ||= Utils.deep_munge(normalize_encode_params(super || {}))
|
|
309
|
+
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
|
284
310
|
raise ActionController::BadRequest.new(:request, e)
|
|
285
311
|
end
|
|
286
312
|
alias :request_parameters :POST
|
|
@@ -302,7 +328,7 @@ module ActionDispatch
|
|
|
302
328
|
# Extracted into ActionDispatch::Request::Utils.deep_munge, but kept here for backwards compatibility.
|
|
303
329
|
def deep_munge(hash)
|
|
304
330
|
ActiveSupport::Deprecation.warn(
|
|
305
|
-
|
|
331
|
+
'This method has been extracted into `ActionDispatch::Request::Utils.deep_munge`. Please start using that instead.'
|
|
306
332
|
)
|
|
307
333
|
|
|
308
334
|
Utils.deep_munge(hash)
|
|
@@ -315,7 +341,7 @@ module ActionDispatch
|
|
|
315
341
|
|
|
316
342
|
private
|
|
317
343
|
def check_method(name)
|
|
318
|
-
HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS.
|
|
344
|
+
HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
|
|
319
345
|
name
|
|
320
346
|
end
|
|
321
347
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
require 'active_support/core_ext/module/attribute_accessors'
|
|
2
|
+
require 'active_support/core_ext/string/filters'
|
|
3
|
+
require 'active_support/deprecation'
|
|
2
4
|
require 'action_dispatch/http/filter_redirect'
|
|
3
5
|
require 'monitor'
|
|
4
6
|
|
|
@@ -97,6 +99,9 @@ module ActionDispatch # :nodoc:
|
|
|
97
99
|
x
|
|
98
100
|
end
|
|
99
101
|
|
|
102
|
+
def abort
|
|
103
|
+
end
|
|
104
|
+
|
|
100
105
|
def close
|
|
101
106
|
@response.commit!
|
|
102
107
|
@closed = true
|
|
@@ -207,18 +212,6 @@ module ActionDispatch # :nodoc:
|
|
|
207
212
|
end
|
|
208
213
|
alias_method :status_message, :message
|
|
209
214
|
|
|
210
|
-
def respond_to?(method, include_private = false)
|
|
211
|
-
if method.to_s == 'to_path'
|
|
212
|
-
stream.respond_to?(method)
|
|
213
|
-
else
|
|
214
|
-
super
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def to_path
|
|
219
|
-
stream.to_path
|
|
220
|
-
end
|
|
221
|
-
|
|
222
215
|
# Returns the content of the response as a string. This contains the contents
|
|
223
216
|
# of any calls to <tt>render</tt>.
|
|
224
217
|
def body
|
|
@@ -271,13 +264,39 @@ module ActionDispatch # :nodoc:
|
|
|
271
264
|
stream.close if stream.respond_to?(:close)
|
|
272
265
|
end
|
|
273
266
|
|
|
267
|
+
def abort
|
|
268
|
+
if stream.respond_to?(:abort)
|
|
269
|
+
stream.abort
|
|
270
|
+
elsif stream.respond_to?(:close)
|
|
271
|
+
# `stream.close` should really be reserved for a close from the
|
|
272
|
+
# other direction, but we must fall back to it for
|
|
273
|
+
# compatibility.
|
|
274
|
+
stream.close
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
274
278
|
# Turns the Response into a Rack-compatible array of the status, headers,
|
|
275
|
-
# and body.
|
|
279
|
+
# and body. Allows explict splatting:
|
|
280
|
+
#
|
|
281
|
+
# status, headers, body = *response
|
|
276
282
|
def to_a
|
|
277
283
|
rack_response @status, @header.to_hash
|
|
278
284
|
end
|
|
279
285
|
alias prepare! to_a
|
|
280
|
-
|
|
286
|
+
|
|
287
|
+
# Be super clear that a response object is not an Array. Defining this
|
|
288
|
+
# would make implicit splatting work, but it also makes adding responses
|
|
289
|
+
# as arrays work, and "flattening" responses, cascading to the rack body!
|
|
290
|
+
# Not sensible behavior.
|
|
291
|
+
def to_ary
|
|
292
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
|
293
|
+
`ActionDispatch::Response#to_ary` no longer performs implicit conversion
|
|
294
|
+
to an array. Please use `response.to_a` instead, or a splat like `status,
|
|
295
|
+
headers, body = *response`.
|
|
296
|
+
MSG
|
|
297
|
+
|
|
298
|
+
to_a
|
|
299
|
+
end
|
|
281
300
|
|
|
282
301
|
# Returns the response cookies, converted to a Hash of (name => value) pairs
|
|
283
302
|
#
|
|
@@ -296,9 +315,6 @@ module ActionDispatch # :nodoc:
|
|
|
296
315
|
cookies
|
|
297
316
|
end
|
|
298
317
|
|
|
299
|
-
def _status_code
|
|
300
|
-
@status
|
|
301
|
-
end
|
|
302
318
|
private
|
|
303
319
|
|
|
304
320
|
def before_committed
|
|
@@ -337,6 +353,42 @@ module ActionDispatch # :nodoc:
|
|
|
337
353
|
!@sending_file && @charset != false
|
|
338
354
|
end
|
|
339
355
|
|
|
356
|
+
class RackBody
|
|
357
|
+
def initialize(response)
|
|
358
|
+
@response = response
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def each(*args, &block)
|
|
362
|
+
@response.each(*args, &block)
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def close
|
|
366
|
+
# Rack "close" maps to Response#abort, and *not* Response#close
|
|
367
|
+
# (which is used when the controller's finished writing)
|
|
368
|
+
@response.abort
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def body
|
|
372
|
+
@response.body
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def respond_to?(method, include_private = false)
|
|
376
|
+
if method.to_s == 'to_path'
|
|
377
|
+
@response.stream.respond_to?(method)
|
|
378
|
+
else
|
|
379
|
+
super
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def to_path
|
|
384
|
+
@response.stream.to_path
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def to_ary
|
|
388
|
+
nil
|
|
389
|
+
end
|
|
390
|
+
end
|
|
391
|
+
|
|
340
392
|
def rack_response(status, header)
|
|
341
393
|
assign_default_content_type_and_charset!(header)
|
|
342
394
|
handle_conditional_get!
|
|
@@ -347,7 +399,7 @@ module ActionDispatch # :nodoc:
|
|
|
347
399
|
header.delete CONTENT_TYPE
|
|
348
400
|
[status, header, []]
|
|
349
401
|
else
|
|
350
|
-
[status, header,
|
|
402
|
+
[status, header, RackBody.new(self)]
|
|
351
403
|
end
|
|
352
404
|
end
|
|
353
405
|
end
|