actionpack 8.0.2.1 → 8.1.0.beta1
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 +251 -141
- data/README.rdoc +1 -1
- data/lib/abstract_controller/asset_paths.rb +4 -2
- data/lib/abstract_controller/base.rb +11 -14
- data/lib/abstract_controller/caching.rb +6 -3
- data/lib/abstract_controller/collector.rb +1 -1
- data/lib/abstract_controller/logger.rb +2 -1
- data/lib/action_controller/base.rb +1 -1
- data/lib/action_controller/caching.rb +1 -2
- data/lib/action_controller/form_builder.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +7 -0
- data/lib/action_controller/metal/allow_browser.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +25 -0
- data/lib/action_controller/metal/data_streaming.rb +1 -3
- data/lib/action_controller/metal/exceptions.rb +5 -0
- data/lib/action_controller/metal/flash.rb +1 -4
- data/lib/action_controller/metal/head.rb +3 -1
- data/lib/action_controller/metal/live.rb +0 -6
- data/lib/action_controller/metal/permissions_policy.rb +9 -0
- data/lib/action_controller/metal/rate_limiting.rb +22 -7
- data/lib/action_controller/metal/redirecting.rb +63 -7
- data/lib/action_controller/metal/renderers.rb +27 -6
- data/lib/action_controller/metal/rendering.rb +8 -2
- data/lib/action_controller/metal/request_forgery_protection.rb +18 -10
- data/lib/action_controller/metal/rescue.rb +9 -0
- data/lib/action_controller/railtie.rb +2 -6
- data/lib/action_controller/renderer.rb +0 -1
- data/lib/action_dispatch/constants.rb +6 -0
- data/lib/action_dispatch/http/cache.rb +111 -1
- data/lib/action_dispatch/http/content_security_policy.rb +13 -1
- data/lib/action_dispatch/http/filter_parameters.rb +5 -3
- data/lib/action_dispatch/http/mime_negotiation.rb +8 -3
- data/lib/action_dispatch/http/mime_types.rb +1 -0
- data/lib/action_dispatch/http/param_builder.rb +28 -27
- data/lib/action_dispatch/http/parameters.rb +3 -3
- data/lib/action_dispatch/http/permissions_policy.rb +4 -0
- data/lib/action_dispatch/http/query_parser.rb +12 -10
- data/lib/action_dispatch/http/request.rb +10 -5
- data/lib/action_dispatch/http/response.rb +65 -17
- data/lib/action_dispatch/http/url.rb +101 -5
- data/lib/action_dispatch/journey/gtg/simulator.rb +33 -12
- data/lib/action_dispatch/journey/gtg/transition_table.rb +29 -39
- data/lib/action_dispatch/journey/nodes/node.rb +2 -1
- data/lib/action_dispatch/journey/route.rb +45 -31
- data/lib/action_dispatch/journey/router/utils.rb +8 -14
- data/lib/action_dispatch/journey/router.rb +59 -81
- data/lib/action_dispatch/journey/routes.rb +7 -0
- data/lib/action_dispatch/journey/visitors.rb +55 -23
- data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
- data/lib/action_dispatch/middleware/cookies.rb +4 -2
- data/lib/action_dispatch/middleware/debug_exceptions.rb +10 -2
- data/lib/action_dispatch/middleware/debug_view.rb +11 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +14 -8
- data/lib/action_dispatch/middleware/executor.rb +12 -2
- data/lib/action_dispatch/middleware/public_exceptions.rb +6 -6
- data/lib/action_dispatch/middleware/session/cache_store.rb +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -2
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
- data/lib/action_dispatch/railtie.rb +10 -2
- data/lib/action_dispatch/routing/inspector.rb +4 -1
- data/lib/action_dispatch/routing/mapper.rb +323 -173
- data/lib/action_dispatch/routing/route_set.rb +3 -6
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +2 -2
- data/lib/action_dispatch/testing/assertion_response.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +14 -0
- data/lib/action_dispatch/testing/assertions/routing.rb +11 -3
- data/lib/action_pack/gem_version.rb +3 -3
- metadata +11 -10
@@ -63,6 +63,114 @@ module ActionDispatch
|
|
63
63
|
success
|
64
64
|
end
|
65
65
|
end
|
66
|
+
|
67
|
+
def cache_control_directives
|
68
|
+
@cache_control_directives ||= CacheControlDirectives.new(get_header("HTTP_CACHE_CONTROL"))
|
69
|
+
end
|
70
|
+
|
71
|
+
# Represents the HTTP Cache-Control header for requests,
|
72
|
+
# providing methods to access various cache control directives
|
73
|
+
# Reference: https://www.rfc-editor.org/rfc/rfc9111.html#name-request-directives
|
74
|
+
class CacheControlDirectives
|
75
|
+
def initialize(cache_control_header)
|
76
|
+
@only_if_cached = false
|
77
|
+
@no_cache = false
|
78
|
+
@no_store = false
|
79
|
+
@no_transform = false
|
80
|
+
@max_age = nil
|
81
|
+
@max_stale = nil
|
82
|
+
@min_fresh = nil
|
83
|
+
@stale_if_error = false
|
84
|
+
parse_directives(cache_control_header)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns true if the only-if-cached directive is present.
|
88
|
+
# This directive indicates that the client only wishes to obtain a
|
89
|
+
# stored response. If a valid stored response is not available,
|
90
|
+
# the server should respond with a 504 (Gateway Timeout) status.
|
91
|
+
def only_if_cached?
|
92
|
+
@only_if_cached
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns true if the no-cache directive is present.
|
96
|
+
# This directive indicates that a cache must not use the response
|
97
|
+
# to satisfy subsequent requests without successful validation on the origin server.
|
98
|
+
def no_cache?
|
99
|
+
@no_cache
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns true if the no-store directive is present.
|
103
|
+
# This directive indicates that a cache must not store any part of the
|
104
|
+
# request or response.
|
105
|
+
def no_store?
|
106
|
+
@no_store
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns true if the no-transform directive is present.
|
110
|
+
# This directive indicates that a cache or proxy must not transform the payload.
|
111
|
+
def no_transform?
|
112
|
+
@no_transform
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns the value of the max-age directive.
|
116
|
+
# This directive indicates that the client is willing to accept a response
|
117
|
+
# whose age is no greater than the specified number of seconds.
|
118
|
+
attr_reader :max_age
|
119
|
+
|
120
|
+
# Returns the value of the max-stale directive.
|
121
|
+
# When max-stale is present with a value, returns that integer value.
|
122
|
+
# When max-stale is present without a value, returns true (unlimited staleness).
|
123
|
+
# When max-stale is not present, returns nil.
|
124
|
+
attr_reader :max_stale
|
125
|
+
|
126
|
+
# Returns true if max-stale directive is present (with or without a value)
|
127
|
+
def max_stale?
|
128
|
+
!@max_stale.nil?
|
129
|
+
end
|
130
|
+
|
131
|
+
# Returns true if max-stale directive is present without a value (unlimited staleness)
|
132
|
+
def max_stale_unlimited?
|
133
|
+
@max_stale == true
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns the value of the min-fresh directive.
|
137
|
+
# This directive indicates that the client is willing to accept a response
|
138
|
+
# whose freshness lifetime is no less than its current age plus the specified time in seconds.
|
139
|
+
attr_reader :min_fresh
|
140
|
+
|
141
|
+
# Returns the value of the stale-if-error directive.
|
142
|
+
# This directive indicates that the client is willing to accept a stale response
|
143
|
+
# if the check for a fresh one fails with an error for the specified number of seconds.
|
144
|
+
attr_reader :stale_if_error
|
145
|
+
|
146
|
+
private
|
147
|
+
def parse_directives(header_value)
|
148
|
+
return unless header_value
|
149
|
+
|
150
|
+
header_value.delete(" ").downcase.split(",").each do |directive|
|
151
|
+
name, value = directive.split("=", 2)
|
152
|
+
|
153
|
+
case name
|
154
|
+
when "max-age"
|
155
|
+
@max_age = value.to_i
|
156
|
+
when "min-fresh"
|
157
|
+
@min_fresh = value.to_i
|
158
|
+
when "stale-if-error"
|
159
|
+
@stale_if_error = value.to_i
|
160
|
+
when "no-cache"
|
161
|
+
@no_cache = true
|
162
|
+
when "no-store"
|
163
|
+
@no_store = true
|
164
|
+
when "no-transform"
|
165
|
+
@no_transform = true
|
166
|
+
when "only-if-cached"
|
167
|
+
@only_if_cached = true
|
168
|
+
when "max-stale"
|
169
|
+
@max_stale = value ? value.to_i : true
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
66
174
|
end
|
67
175
|
|
68
176
|
module Response
|
@@ -142,7 +250,7 @@ module ActionDispatch
|
|
142
250
|
private
|
143
251
|
DATE = "Date"
|
144
252
|
LAST_MODIFIED = "Last-Modified"
|
145
|
-
SPECIAL_KEYS = Set.new(%w[extras no-store no-cache max-age public private must-revalidate])
|
253
|
+
SPECIAL_KEYS = Set.new(%w[extras no-store no-cache max-age public private must-revalidate must-understand])
|
146
254
|
|
147
255
|
def generate_weak_etag(validators)
|
148
256
|
"W/#{generate_strong_etag(validators)}"
|
@@ -187,6 +295,7 @@ module ActionDispatch
|
|
187
295
|
PRIVATE = "private"
|
188
296
|
MUST_REVALIDATE = "must-revalidate"
|
189
297
|
IMMUTABLE = "immutable"
|
298
|
+
MUST_UNDERSTAND = "must-understand"
|
190
299
|
|
191
300
|
def handle_conditional_get!
|
192
301
|
# Normally default cache control setting is handled by ETag middleware. But, if
|
@@ -221,6 +330,7 @@ module ActionDispatch
|
|
221
330
|
|
222
331
|
if control[:no_store]
|
223
332
|
options << PRIVATE if control[:private]
|
333
|
+
options << MUST_UNDERSTAND if control[:must_understand]
|
224
334
|
options << NO_STORE
|
225
335
|
elsif control[:no_cache]
|
226
336
|
options << PUBLIC if control[:public]
|
@@ -171,6 +171,8 @@ module ActionDispatch # :nodoc:
|
|
171
171
|
worker_src: "worker-src"
|
172
172
|
}.freeze
|
173
173
|
|
174
|
+
HASH_SOURCE_ALGORITHM_PREFIXES = ["sha256-", "sha384-", "sha512-"].freeze
|
175
|
+
|
174
176
|
DEFAULT_NONCE_DIRECTIVES = %w[script-src style-src].freeze
|
175
177
|
|
176
178
|
private_constant :MAPPINGS, :DIRECTIVES, :DEFAULT_NONCE_DIRECTIVES
|
@@ -305,7 +307,13 @@ module ActionDispatch # :nodoc:
|
|
305
307
|
case source
|
306
308
|
when Symbol
|
307
309
|
apply_mapping(source)
|
308
|
-
when String
|
310
|
+
when String
|
311
|
+
if hash_source?(source)
|
312
|
+
"'#{source}'"
|
313
|
+
else
|
314
|
+
source
|
315
|
+
end
|
316
|
+
when Proc
|
309
317
|
source
|
310
318
|
else
|
311
319
|
raise ArgumentError, "Invalid content security policy source: #{source.inspect}"
|
@@ -374,5 +382,9 @@ module ActionDispatch # :nodoc:
|
|
374
382
|
def nonce_directive?(directive, nonce_directives)
|
375
383
|
nonce_directives.include?(directive)
|
376
384
|
end
|
385
|
+
|
386
|
+
def hash_source?(source)
|
387
|
+
source.start_with?(*HASH_SOURCE_ALGORITHM_PREFIXES)
|
388
|
+
end
|
377
389
|
end
|
378
390
|
end
|
@@ -17,9 +17,11 @@ module ActionDispatch
|
|
17
17
|
# For more information about filter behavior, see
|
18
18
|
# ActiveSupport::ParameterFilter.
|
19
19
|
module FilterParameters
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
# :stopdoc:
|
21
|
+
ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"]
|
22
|
+
NULL_PARAM_FILTER = ActiveSupport::ParameterFilter.new
|
23
|
+
NULL_ENV_FILTER = ActiveSupport::ParameterFilter.new ENV_MATCH
|
24
|
+
# :startdoc:
|
23
25
|
|
24
26
|
def initialize
|
25
27
|
super
|
@@ -56,9 +56,14 @@ module ActionDispatch
|
|
56
56
|
|
57
57
|
# Returns the MIME type for the format used in the request.
|
58
58
|
#
|
59
|
-
# GET /posts/5.xml
|
60
|
-
#
|
61
|
-
#
|
59
|
+
# # GET /posts/5.xml
|
60
|
+
# request.format # => Mime[:xml]
|
61
|
+
#
|
62
|
+
# # GET /posts/5.xhtml
|
63
|
+
# request.format # => Mime[:html]
|
64
|
+
#
|
65
|
+
# # GET /posts/5
|
66
|
+
# request.format # => Mime[:html] or Mime[:js], or request.accepts.first
|
62
67
|
#
|
63
68
|
def format(_view_path = nil)
|
64
69
|
formats.first || Mime::NullType.instance
|
@@ -13,6 +13,7 @@ Mime::Type.register "text/calendar", :ics
|
|
13
13
|
Mime::Type.register "text/csv", :csv
|
14
14
|
Mime::Type.register "text/vcard", :vcf
|
15
15
|
Mime::Type.register "text/vtt", :vtt, %w(vtt)
|
16
|
+
Mime::Type.register "text/markdown", :md, [], %w(md markdown)
|
16
17
|
|
17
18
|
Mime::Type.register "image/png", :png, [], %w(png)
|
18
19
|
Mime::Type.register "image/jpeg", :jpeg, [], %w(jpg jpeg jpe pjpeg)
|
@@ -16,15 +16,27 @@ module ActionDispatch
|
|
16
16
|
@param_depth_limit = param_depth_limit
|
17
17
|
end
|
18
18
|
|
19
|
-
cattr_accessor :ignore_leading_brackets
|
20
|
-
|
21
|
-
LEADING_BRACKETS_COMPAT = defined?(::Rack::RELEASE) && ::Rack::RELEASE.to_s.start_with?("2.")
|
22
|
-
|
23
19
|
cattr_accessor :default
|
24
20
|
self.default = make_default(100)
|
25
21
|
|
26
22
|
class << self
|
27
23
|
delegate :from_query_string, :from_pairs, :from_hash, to: :default
|
24
|
+
|
25
|
+
def ignore_leading_brackets
|
26
|
+
ActionDispatch.deprecator.warn <<~MSG
|
27
|
+
ActionDispatch::ParamBuilder.ignore_leading_brackets is deprecated and have no effect and will be removed in Rails 8.2.
|
28
|
+
MSG
|
29
|
+
|
30
|
+
@ignore_leading_brackets
|
31
|
+
end
|
32
|
+
|
33
|
+
def ignore_leading_brackets=(value)
|
34
|
+
ActionDispatch.deprecator.warn <<~MSG
|
35
|
+
ActionDispatch::ParamBuilder.ignore_leading_brackets is deprecated and have no effect and will be removed in Rails 8.2.
|
36
|
+
MSG
|
37
|
+
|
38
|
+
@ignore_leading_brackets = value
|
39
|
+
end
|
28
40
|
end
|
29
41
|
|
30
42
|
def from_query_string(qs, separator: nil, encoding_template: nil)
|
@@ -69,30 +81,15 @@ module ActionDispatch
|
|
69
81
|
# nil name, treat same as empty string (required by tests)
|
70
82
|
k = after = ""
|
71
83
|
elsif depth == 0
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
if !ignore_leading_brackets && (k != $& || !after.empty? && !after.start_with?("["))
|
79
|
-
ActionDispatch.deprecator.warn("Skipping over leading brackets in parameter name #{name.inspect} is deprecated and will parse differently in Rails 8.1 or Rack 3.0.")
|
80
|
-
end
|
81
|
-
else
|
82
|
-
k = name
|
83
|
-
after = ""
|
84
|
-
end
|
84
|
+
# Start of parsing, don't treat [] or [ at start of string specially
|
85
|
+
if start = name.index("[", 1)
|
86
|
+
# Start of parameter nesting, use part before brackets as key
|
87
|
+
k = name[0, start]
|
88
|
+
after = name[start, name.length]
|
85
89
|
else
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
k = name[0, start]
|
90
|
-
after = name[start, name.length]
|
91
|
-
else
|
92
|
-
# Plain parameter with no nesting
|
93
|
-
k = name
|
94
|
-
after = ""
|
95
|
-
end
|
90
|
+
# Plain parameter with no nesting
|
91
|
+
k = name
|
92
|
+
after = ""
|
96
93
|
end
|
97
94
|
elsif name.start_with?("[]")
|
98
95
|
# Array nesting
|
@@ -111,6 +108,10 @@ module ActionDispatch
|
|
111
108
|
|
112
109
|
return if k.empty?
|
113
110
|
|
111
|
+
unless k.valid_encoding?
|
112
|
+
raise InvalidParameterError, "Invalid encoding for parameter: #{k}"
|
113
|
+
end
|
114
|
+
|
114
115
|
if depth == 0 && String === v
|
115
116
|
# We have to wait until we've found the top part of the name,
|
116
117
|
# because that's what the encoding template is configured with
|
@@ -65,14 +65,14 @@ module ActionDispatch
|
|
65
65
|
alias :params :parameters
|
66
66
|
|
67
67
|
def path_parameters=(parameters) # :nodoc:
|
68
|
-
|
68
|
+
@env.delete("action_dispatch.request.parameters")
|
69
69
|
|
70
70
|
parameters = Request::Utils.set_binary_encoding(self, parameters, parameters[:controller], parameters[:action])
|
71
71
|
# If any of the path parameters has an invalid encoding then raise since it's
|
72
72
|
# likely to trigger errors further on.
|
73
73
|
Request::Utils.check_param_encoding(parameters)
|
74
74
|
|
75
|
-
|
75
|
+
@env[PARAMETERS_KEY] = parameters
|
76
76
|
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
77
77
|
raise ActionController::BadRequest.new("Invalid path parameters: #{e.message}")
|
78
78
|
end
|
@@ -82,7 +82,7 @@ module ActionDispatch
|
|
82
82
|
#
|
83
83
|
# { action: "my_action", controller: "my_controller" }
|
84
84
|
def path_parameters
|
85
|
-
|
85
|
+
@env[PARAMETERS_KEY] ||= {}
|
86
86
|
end
|
87
87
|
|
88
88
|
private
|
@@ -6,12 +6,21 @@ require "rack"
|
|
6
6
|
module ActionDispatch
|
7
7
|
class QueryParser
|
8
8
|
DEFAULT_SEP = /& */n
|
9
|
-
COMPAT_SEP = /[&;] */n
|
10
9
|
COMMON_SEP = { ";" => /; */n, ";," => /[;,] */n, "&" => /& */n, "&;" => /[&;] */n }
|
11
10
|
|
12
|
-
|
11
|
+
def self.strict_query_string_separator
|
12
|
+
ActionDispatch.deprecator.warn <<~MSG
|
13
|
+
The `strict_query_string_separator` configuration is deprecated have no effect and will be removed in Rails 8.2.
|
14
|
+
MSG
|
15
|
+
@strict_query_string_separator
|
16
|
+
end
|
13
17
|
|
14
|
-
|
18
|
+
def self.strict_query_string_separator=(value)
|
19
|
+
ActionDispatch.deprecator.warn <<~MSG
|
20
|
+
The `strict_query_string_separator` configuration is deprecated have no effect and will be removed in Rails 8.2.
|
21
|
+
MSG
|
22
|
+
@strict_query_string_separator = value
|
23
|
+
end
|
15
24
|
|
16
25
|
#--
|
17
26
|
# Note this departs from WHATWG's specified parsing algorithm by
|
@@ -25,13 +34,6 @@ module ActionDispatch
|
|
25
34
|
splitter =
|
26
35
|
if separator
|
27
36
|
COMMON_SEP[separator] || /[#{separator}] */n
|
28
|
-
elsif strict_query_string_separator
|
29
|
-
DEFAULT_SEP
|
30
|
-
elsif SEMICOLON_COMPAT && s.include?(";")
|
31
|
-
if strict_query_string_separator.nil?
|
32
|
-
ActionDispatch.deprecator.warn("Using semicolon as a query string separator is deprecated and will not be supported in Rails 8.1 or Rack 3.0. Use `&` instead.")
|
33
|
-
end
|
34
|
-
COMPAT_SEP
|
35
37
|
else
|
36
38
|
DEFAULT_SEP
|
37
39
|
end
|
@@ -25,7 +25,6 @@ module ActionDispatch
|
|
25
25
|
include ActionDispatch::Http::FilterParameters
|
26
26
|
include ActionDispatch::Http::URL
|
27
27
|
include ActionDispatch::ContentSecurityPolicy::Request
|
28
|
-
include ActionDispatch::PermissionsPolicy::Request
|
29
28
|
include Rack::Request::Env
|
30
29
|
|
31
30
|
autoload :Session, "action_dispatch/request/session"
|
@@ -139,7 +138,7 @@ module ActionDispatch
|
|
139
138
|
|
140
139
|
# Populate the HTTP method lookup cache.
|
141
140
|
HTTP_METHODS.each { |method|
|
142
|
-
HTTP_METHOD_LOOKUP[method] = method.downcase.
|
141
|
+
HTTP_METHOD_LOOKUP[method] = method.downcase.tap { |m| m.tr!("-", "_") }.to_sym
|
143
142
|
}
|
144
143
|
|
145
144
|
alias raw_request_method request_method # :nodoc:
|
@@ -158,11 +157,17 @@ module ActionDispatch
|
|
158
157
|
#
|
159
158
|
# request.route_uri_pattern # => "/:controller(/:action(/:id))(.:format)"
|
160
159
|
def route_uri_pattern
|
161
|
-
get_header("action_dispatch.route_uri_pattern")
|
160
|
+
unless pattern = get_header("action_dispatch.route_uri_pattern")
|
161
|
+
route = get_header("action_dispatch.route")
|
162
|
+
return if route.nil?
|
163
|
+
pattern = route.path.spec.to_s
|
164
|
+
set_header("action_dispatch.route_uri_pattern", pattern)
|
165
|
+
end
|
166
|
+
pattern
|
162
167
|
end
|
163
168
|
|
164
|
-
def
|
165
|
-
|
169
|
+
def route=(route) # :nodoc:
|
170
|
+
@env["action_dispatch.route"] = route
|
166
171
|
end
|
167
172
|
|
168
173
|
def routes # :nodoc:
|
@@ -46,6 +46,20 @@ module ActionDispatch # :nodoc:
|
|
46
46
|
Headers = ::Rack::Utils::HeaderHash
|
47
47
|
end
|
48
48
|
|
49
|
+
class << self
|
50
|
+
if ActionDispatch::Constants::UNPROCESSABLE_CONTENT == :unprocessable_content
|
51
|
+
def rack_status_code(status) # :nodoc:
|
52
|
+
status = :unprocessable_content if status == :unprocessable_entity
|
53
|
+
Rack::Utils.status_code(status)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
def rack_status_code(status) # :nodoc:
|
57
|
+
status = :unprocessable_entity if status == :unprocessable_content
|
58
|
+
Rack::Utils.status_code(status)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
49
63
|
# To be deprecated:
|
50
64
|
Header = Headers
|
51
65
|
|
@@ -105,10 +119,22 @@ module ActionDispatch # :nodoc:
|
|
105
119
|
@str_body = nil
|
106
120
|
end
|
107
121
|
|
122
|
+
BODY_METHODS = { to_ary: true }
|
123
|
+
|
124
|
+
def respond_to?(method, include_private = false)
|
125
|
+
if BODY_METHODS.key?(method)
|
126
|
+
@buf.respond_to?(method)
|
127
|
+
else
|
128
|
+
super
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
108
132
|
def to_ary
|
109
|
-
@
|
110
|
-
|
111
|
-
|
133
|
+
if @str_body
|
134
|
+
[body]
|
135
|
+
else
|
136
|
+
@buf = @buf.to_ary
|
137
|
+
end
|
112
138
|
end
|
113
139
|
|
114
140
|
def body
|
@@ -245,20 +271,33 @@ module ActionDispatch # :nodoc:
|
|
245
271
|
|
246
272
|
# Sets the HTTP status code.
|
247
273
|
def status=(status)
|
248
|
-
@status =
|
274
|
+
@status = Response.rack_status_code(status)
|
249
275
|
end
|
250
276
|
|
251
277
|
# Sets the HTTP response's content MIME type. For example, in the controller you
|
252
278
|
# could write this:
|
253
279
|
#
|
254
|
-
# response.content_type = "text/
|
280
|
+
# response.content_type = "text/html"
|
281
|
+
#
|
282
|
+
# This method also accepts a symbol with the extension of the MIME type:
|
283
|
+
#
|
284
|
+
# response.content_type = :html
|
255
285
|
#
|
256
286
|
# If a character set has been defined for this response (see #charset=) then the
|
257
287
|
# character set information will also be included in the content type
|
258
288
|
# information.
|
259
289
|
def content_type=(content_type)
|
260
|
-
|
261
|
-
|
290
|
+
case content_type
|
291
|
+
when NilClass
|
292
|
+
return
|
293
|
+
when Symbol
|
294
|
+
mime_type = Mime[content_type]
|
295
|
+
raise ArgumentError, "Unknown MIME type #{content_type}" unless mime_type
|
296
|
+
new_header_info = ContentTypeHeader.new(mime_type.to_s)
|
297
|
+
else
|
298
|
+
new_header_info = parse_content_type(content_type.to_s)
|
299
|
+
end
|
300
|
+
|
262
301
|
prev_header_info = parsed_content_type_header
|
263
302
|
charset = new_header_info.charset || prev_header_info.charset
|
264
303
|
charset ||= self.class.default_charset unless prev_header_info.mime_type
|
@@ -328,7 +367,13 @@ module ActionDispatch # :nodoc:
|
|
328
367
|
# Returns the content of the response as a string. This contains the contents of
|
329
368
|
# any calls to `render`.
|
330
369
|
def body
|
331
|
-
@stream.
|
370
|
+
if @stream.respond_to?(:to_ary)
|
371
|
+
@stream.to_ary.join
|
372
|
+
elsif @stream.respond_to?(:body)
|
373
|
+
@stream.body
|
374
|
+
else
|
375
|
+
@stream
|
376
|
+
end
|
332
377
|
end
|
333
378
|
|
334
379
|
def write(string)
|
@@ -337,11 +382,16 @@ module ActionDispatch # :nodoc:
|
|
337
382
|
|
338
383
|
# Allows you to manually set or override the response body.
|
339
384
|
def body=(body)
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
385
|
+
# Prevent ActionController::Metal::Live::Response from committing the response prematurely.
|
386
|
+
synchronize do
|
387
|
+
if body.respond_to?(:to_str)
|
388
|
+
@stream = build_buffer(self, [body])
|
389
|
+
elsif body.respond_to?(:to_path)
|
390
|
+
@stream = body
|
391
|
+
elsif body.respond_to?(:to_ary)
|
392
|
+
@stream = build_buffer(self, body)
|
393
|
+
else
|
394
|
+
@stream = body
|
345
395
|
end
|
346
396
|
end
|
347
397
|
end
|
@@ -482,10 +532,6 @@ module ActionDispatch # :nodoc:
|
|
482
532
|
Buffer.new response, body
|
483
533
|
end
|
484
534
|
|
485
|
-
def munge_body_object(body)
|
486
|
-
body.respond_to?(:each) ? body : [body]
|
487
|
-
end
|
488
|
-
|
489
535
|
def assign_default_content_type_and_charset!
|
490
536
|
return if media_type
|
491
537
|
|
@@ -499,6 +545,8 @@ module ActionDispatch # :nodoc:
|
|
499
545
|
@response = response
|
500
546
|
end
|
501
547
|
|
548
|
+
attr :response
|
549
|
+
|
502
550
|
def close
|
503
551
|
# Rack "close" maps to Response#abort, and **not** Response#close (which is used
|
504
552
|
# when the controller's finished writing)
|