actionpack 7.0.4.3 → 7.1.3.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 +4 -4
- data/CHANGELOG.md +380 -284
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/abstract_controller/base.rb +20 -11
- data/lib/abstract_controller/caching/fragments.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +31 -6
- data/lib/abstract_controller/deprecator.rb +7 -0
- data/lib/abstract_controller/helpers.rb +75 -28
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -16
- data/lib/abstract_controller/rendering.rb +12 -14
- data/lib/abstract_controller/translation.rb +9 -6
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +6 -0
- data/lib/action_controller/api.rb +6 -4
- data/lib/action_controller/base.rb +3 -17
- data/lib/action_controller/caching.rb +2 -0
- data/lib/action_controller/deprecator.rb +7 -0
- data/lib/action_controller/form_builder.rb +2 -0
- data/lib/action_controller/log_subscriber.rb +16 -4
- data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
- data/lib/action_controller/metal/conditional_get.rb +121 -123
- data/lib/action_controller/metal/content_security_policy.rb +5 -5
- data/lib/action_controller/metal/data_streaming.rb +20 -18
- data/lib/action_controller/metal/default_headers.rb +2 -0
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
- data/lib/action_controller/metal/exceptions.rb +8 -0
- data/lib/action_controller/metal/head.rb +9 -7
- data/lib/action_controller/metal/helpers.rb +3 -14
- data/lib/action_controller/metal/http_authentication.rb +17 -8
- data/lib/action_controller/metal/implicit_render.rb +5 -3
- data/lib/action_controller/metal/instrumentation.rb +8 -1
- data/lib/action_controller/metal/live.rb +25 -1
- data/lib/action_controller/metal/mime_responds.rb +2 -2
- data/lib/action_controller/metal/params_wrapper.rb +4 -2
- data/lib/action_controller/metal/permissions_policy.rb +2 -2
- data/lib/action_controller/metal/redirecting.rb +25 -8
- data/lib/action_controller/metal/renderers.rb +4 -4
- data/lib/action_controller/metal/rendering.rb +114 -9
- data/lib/action_controller/metal/request_forgery_protection.rb +144 -53
- data/lib/action_controller/metal/rescue.rb +6 -3
- data/lib/action_controller/metal/streaming.rb +71 -31
- data/lib/action_controller/metal/strong_parameters.rb +158 -101
- data/lib/action_controller/metal/url_for.rb +9 -4
- data/lib/action_controller/metal.rb +79 -21
- data/lib/action_controller/railtie.rb +24 -10
- data/lib/action_controller/renderer.rb +99 -85
- data/lib/action_controller/test_case.rb +15 -5
- data/lib/action_controller.rb +8 -1
- data/lib/action_dispatch/constants.rb +32 -0
- data/lib/action_dispatch/deprecator.rb +7 -0
- data/lib/action_dispatch/http/cache.rb +8 -10
- data/lib/action_dispatch/http/content_security_policy.rb +14 -9
- data/lib/action_dispatch/http/filter_parameters.rb +14 -28
- data/lib/action_dispatch/http/headers.rb +3 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +22 -22
- data/lib/action_dispatch/http/mime_type.rb +35 -12
- data/lib/action_dispatch/http/mime_types.rb +3 -1
- data/lib/action_dispatch/http/parameters.rb +1 -1
- data/lib/action_dispatch/http/permissions_policy.rb +38 -23
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +63 -30
- data/lib/action_dispatch/http/response.rb +80 -63
- data/lib/action_dispatch/http/upload.rb +15 -2
- data/lib/action_dispatch/journey/formatter.rb +8 -2
- data/lib/action_dispatch/journey/path/pattern.rb +14 -14
- data/lib/action_dispatch/journey/route.rb +3 -2
- data/lib/action_dispatch/journey/router.rb +9 -8
- data/lib/action_dispatch/journey/routes.rb +2 -2
- data/lib/action_dispatch/log_subscriber.rb +23 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -6
- data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -0
- data/lib/action_dispatch/middleware/cookies.rb +85 -102
- data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -25
- data/lib/action_dispatch/middleware/debug_locks.rb +4 -1
- data/lib/action_dispatch/middleware/debug_view.rb +7 -2
- data/lib/action_dispatch/middleware/exception_wrapper.rb +186 -27
- data/lib/action_dispatch/middleware/executor.rb +1 -1
- data/lib/action_dispatch/middleware/flash.rb +7 -0
- data/lib/action_dispatch/middleware/host_authorization.rb +18 -8
- data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
- data/lib/action_dispatch/middleware/reloader.rb +7 -5
- data/lib/action_dispatch/middleware/remote_ip.rb +21 -20
- data/lib/action_dispatch/middleware/request_id.rb +4 -2
- data/lib/action_dispatch/middleware/server_timing.rb +4 -4
- data/lib/action_dispatch/middleware/session/abstract_store.rb +5 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -5
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +25 -18
- data/lib/action_dispatch/middleware/ssl.rb +18 -6
- data/lib/action_dispatch/middleware/stack.rb +7 -2
- data/lib/action_dispatch/middleware/static.rb +14 -10
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -3
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +59 -41
- data/lib/action_dispatch/railtie.rb +14 -4
- data/lib/action_dispatch/request/session.rb +16 -6
- data/lib/action_dispatch/request/utils.rb +8 -3
- data/lib/action_dispatch/routing/inspector.rb +54 -6
- data/lib/action_dispatch/routing/mapper.rb +58 -24
- data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
- data/lib/action_dispatch/routing/redirection.rb +15 -6
- data/lib/action_dispatch/routing/route_set.rb +52 -22
- data/lib/action_dispatch/routing/routes_proxy.rb +10 -15
- data/lib/action_dispatch/routing/url_for.rb +26 -22
- data/lib/action_dispatch/routing.rb +7 -7
- data/lib/action_dispatch/system_test_case.rb +3 -3
- data/lib/action_dispatch/system_testing/browser.rb +20 -19
- data/lib/action_dispatch/system_testing/driver.rb +14 -22
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +27 -16
- data/lib/action_dispatch/testing/assertion_response.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +14 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +67 -28
- data/lib/action_dispatch/testing/assertions.rb +3 -1
- data/lib/action_dispatch/testing/integration.rb +27 -17
- data/lib/action_dispatch/testing/request_encoder.rb +4 -1
- data/lib/action_dispatch/testing/test_process.rb +4 -3
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +23 -9
- data/lib/action_dispatch.rb +37 -4
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_pack.rb +1 -1
- metadata +65 -29
@@ -72,7 +72,7 @@ module ActionDispatch
|
|
72
72
|
|
73
73
|
PASS_NOT_FOUND = Class.new { # :nodoc:
|
74
74
|
def self.action(_); self; end
|
75
|
-
def self.call(_); [404, {
|
75
|
+
def self.call(_); [404, { Constants::X_CASCADE => "pass" }, []]; end
|
76
76
|
def self.action_encoding_template(action); false; end
|
77
77
|
}
|
78
78
|
|
@@ -107,22 +107,21 @@ module ActionDispatch
|
|
107
107
|
has_header? key
|
108
108
|
end
|
109
109
|
|
110
|
-
#
|
111
|
-
# Hypertext Transfer Protocol -- HTTP/1.1 (https://www.ietf.org/rfc/rfc2616.txt)
|
112
|
-
# HTTP Extensions for Distributed Authoring -- WEBDAV (https://www.ietf.org/rfc/rfc2518.txt)
|
113
|
-
# Versioning Extensions to WebDAV (https://www.ietf.org/rfc/rfc3253.txt)
|
114
|
-
# Ordered Collections Protocol (WebDAV) (https://www.ietf.org/rfc/rfc3648.txt)
|
115
|
-
# Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (https://www.ietf.org/rfc/rfc3744.txt)
|
116
|
-
# Web Distributed Authoring and Versioning (WebDAV) SEARCH (https://www.ietf.org/rfc/rfc5323.txt)
|
117
|
-
# Calendar Extensions to WebDAV (https://www.ietf.org/rfc/rfc4791.txt)
|
118
|
-
# PATCH Method for HTTP (https://www.ietf.org/rfc/rfc5789.txt)
|
110
|
+
# HTTP methods from {RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1}[https://www.ietf.org/rfc/rfc2616.txt]
|
119
111
|
RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
|
112
|
+
# HTTP methods from {RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV}[https://www.ietf.org/rfc/rfc2518.txt]
|
120
113
|
RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
|
114
|
+
# HTTP methods from {RFC 3253: Versioning Extensions to WebDAV}[https://www.ietf.org/rfc/rfc3253.txt]
|
121
115
|
RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
|
116
|
+
# HTTP methods from {RFC 3648: WebDAV Ordered Collections Protocol}[https://www.ietf.org/rfc/rfc3648.txt]
|
122
117
|
RFC3648 = %w(ORDERPATCH)
|
118
|
+
# HTTP methods from {RFC 3744: WebDAV Access Control Protocol}[https://www.ietf.org/rfc/rfc3744.txt]
|
123
119
|
RFC3744 = %w(ACL)
|
120
|
+
# HTTP methods from {RFC 5323: WebDAV SEARCH}[https://www.ietf.org/rfc/rfc5323.txt]
|
124
121
|
RFC5323 = %w(SEARCH)
|
122
|
+
# HTTP methods from {RFC 4791: Calendaring Extensions to WebDAV}[https://www.ietf.org/rfc/rfc4791.txt]
|
125
123
|
RFC4791 = %w(MKCALENDAR)
|
124
|
+
# HTTP methods from {RFC 5789: PATCH Method for HTTP}[https://www.ietf.org/rfc/rfc5789.txt]
|
126
125
|
RFC5789 = %w(PATCH)
|
127
126
|
|
128
127
|
HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789
|
@@ -146,6 +145,18 @@ module ActionDispatch
|
|
146
145
|
@request_method ||= check_method(super)
|
147
146
|
end
|
148
147
|
|
148
|
+
# Returns the URI pattern of the matched route for the request,
|
149
|
+
# using the same format as `bin/rails routes`:
|
150
|
+
#
|
151
|
+
# request.route_uri_pattern # => "/:controller(/:action(/:id))(.:format)"
|
152
|
+
def route_uri_pattern
|
153
|
+
get_header("action_dispatch.route_uri_pattern")
|
154
|
+
end
|
155
|
+
|
156
|
+
def route_uri_pattern=(pattern) # :nodoc:
|
157
|
+
set_header("action_dispatch.route_uri_pattern", pattern)
|
158
|
+
end
|
159
|
+
|
149
160
|
def routes # :nodoc:
|
150
161
|
get_header("action_dispatch.routes")
|
151
162
|
end
|
@@ -180,13 +191,6 @@ module ActionDispatch
|
|
180
191
|
get_header "action_dispatch.http_auth_salt"
|
181
192
|
end
|
182
193
|
|
183
|
-
def show_exceptions? # :nodoc:
|
184
|
-
# We're treating `nil` as "unset", and we want the default setting to be
|
185
|
-
# `true`. This logic should be extracted to `env_config` and calculated
|
186
|
-
# once.
|
187
|
-
!(get_header("action_dispatch.show_exceptions") == false)
|
188
|
-
end
|
189
|
-
|
190
194
|
# Returns a symbol form of the #request_method.
|
191
195
|
def request_method_symbol
|
192
196
|
HTTP_METHOD_LOOKUP[request_method]
|
@@ -195,9 +199,20 @@ module ActionDispatch
|
|
195
199
|
# Returns the original value of the environment's REQUEST_METHOD,
|
196
200
|
# even if it was overridden by middleware. See #request_method for
|
197
201
|
# more information.
|
198
|
-
|
199
|
-
|
202
|
+
#
|
203
|
+
# For debugging purposes, when called with arguments this method will
|
204
|
+
# fall back to Object#method
|
205
|
+
def method(*args)
|
206
|
+
if args.empty?
|
207
|
+
@method ||= check_method(
|
208
|
+
get_header("rack.methodoverride.original_method") ||
|
209
|
+
get_header("REQUEST_METHOD")
|
210
|
+
)
|
211
|
+
else
|
212
|
+
super
|
213
|
+
end
|
200
214
|
end
|
215
|
+
ruby2_keywords(:method)
|
201
216
|
|
202
217
|
# Returns a symbol form of the #method.
|
203
218
|
def method_symbol
|
@@ -268,10 +283,11 @@ module ActionDispatch
|
|
268
283
|
|
269
284
|
# Returns the content length of the request as an integer.
|
270
285
|
def content_length
|
286
|
+
return raw_post.bytesize if headers.key?("Transfer-Encoding")
|
271
287
|
super.to_i
|
272
288
|
end
|
273
289
|
|
274
|
-
# Returns true if the
|
290
|
+
# Returns true if the +X-Requested-With+ header contains "XMLHttpRequest"
|
275
291
|
# (case-insensitive), which may need to be manually added depending on the
|
276
292
|
# choice of JavaScript libraries and frameworks.
|
277
293
|
def xml_http_request?
|
@@ -297,7 +313,7 @@ module ActionDispatch
|
|
297
313
|
|
298
314
|
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
|
299
315
|
|
300
|
-
# Returns the unique request id, which is based on either the X-Request-Id header that can
|
316
|
+
# Returns the unique request id, which is based on either the +X-Request-Id+ header that can
|
301
317
|
# be generated by a firewall, load balancer, or web server, or by the RequestId middleware
|
302
318
|
# (which sets the +action_dispatch.request_id+ environment variable).
|
303
319
|
#
|
@@ -322,9 +338,8 @@ module ActionDispatch
|
|
322
338
|
# work with raw requests directly.
|
323
339
|
def raw_post
|
324
340
|
unless has_header? "RAW_POST_DATA"
|
325
|
-
|
326
|
-
|
327
|
-
raw_post_body.rewind if raw_post_body.respond_to?(:rewind)
|
341
|
+
set_header("RAW_POST_DATA", read_body_stream)
|
342
|
+
body_stream.rewind if body_stream.respond_to?(:rewind)
|
328
343
|
end
|
329
344
|
get_header "RAW_POST_DATA"
|
330
345
|
end
|
@@ -341,13 +356,13 @@ module ActionDispatch
|
|
341
356
|
end
|
342
357
|
|
343
358
|
# Determine whether the request body contains form-data by checking
|
344
|
-
# the request Content-Type for one of the media-types:
|
345
|
-
#
|
359
|
+
# the request +Content-Type+ for one of the media-types:
|
360
|
+
# +application/x-www-form-urlencoded+ or +multipart/form-data+. The
|
346
361
|
# list of form-data media types can be modified through the
|
347
362
|
# +FORM_DATA_MEDIA_TYPES+ array.
|
348
363
|
#
|
349
364
|
# A request body is not assumed to contain form-data when no
|
350
|
-
# Content-Type header is provided and the request_method is POST.
|
365
|
+
# +Content-Type+ header is provided and the request_method is POST.
|
351
366
|
def form_data?
|
352
367
|
FORM_DATA_MEDIA_TYPES.include?(media_type)
|
353
368
|
end
|
@@ -358,6 +373,7 @@ module ActionDispatch
|
|
358
373
|
|
359
374
|
def reset_session
|
360
375
|
session.destroy
|
376
|
+
reset_csrf_token
|
361
377
|
end
|
362
378
|
|
363
379
|
def session=(session) # :nodoc:
|
@@ -379,7 +395,7 @@ module ActionDispatch
|
|
379
395
|
Request::Utils.check_param_encoding(rack_query_params)
|
380
396
|
set_header k, Request::Utils.normalize_encode_params(rack_query_params)
|
381
397
|
end
|
382
|
-
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
398
|
+
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError, Rack::QueryParser::ParamsTooDeepError => e
|
383
399
|
raise ActionController::BadRequest.new("Invalid query parameters: #{e.message}")
|
384
400
|
end
|
385
401
|
alias :query_parameters :GET
|
@@ -394,7 +410,7 @@ module ActionDispatch
|
|
394
410
|
Request::Utils.check_param_encoding(pr)
|
395
411
|
self.request_parameters = Request::Utils.normalize_encode_params(pr)
|
396
412
|
end
|
397
|
-
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
413
|
+
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError, Rack::QueryParser::ParamsTooDeepError, EOFError => e
|
398
414
|
raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
|
399
415
|
end
|
400
416
|
alias :request_parameters :POST
|
@@ -429,15 +445,32 @@ module ActionDispatch
|
|
429
445
|
"#<#{self.class.name} #{method} #{original_url.dump} for #{remote_ip}>"
|
430
446
|
end
|
431
447
|
|
448
|
+
def reset_csrf_token
|
449
|
+
controller_instance.reset_csrf_token(self) if controller_instance.respond_to?(:reset_csrf_token)
|
450
|
+
end
|
451
|
+
|
452
|
+
def commit_csrf_token
|
453
|
+
controller_instance.commit_csrf_token(self) if controller_instance.respond_to?(:commit_csrf_token)
|
454
|
+
end
|
455
|
+
|
432
456
|
private
|
433
457
|
def check_method(name)
|
434
|
-
|
458
|
+
if name
|
459
|
+
HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
|
460
|
+
end
|
461
|
+
|
435
462
|
name
|
436
463
|
end
|
437
464
|
|
438
465
|
def default_session
|
439
466
|
Session.disabled(self)
|
440
467
|
end
|
468
|
+
|
469
|
+
def read_body_stream
|
470
|
+
body_stream.rewind if body_stream.respond_to?(:rewind)
|
471
|
+
return body_stream.read if headers.key?("Transfer-Encoding") # Read body stream until EOF if "Transfer-Encoding" is present
|
472
|
+
body_stream.read(content_length)
|
473
|
+
end
|
441
474
|
end
|
442
475
|
end
|
443
476
|
|
@@ -6,23 +6,23 @@ require "action_dispatch/http/cache"
|
|
6
6
|
require "monitor"
|
7
7
|
|
8
8
|
module ActionDispatch # :nodoc:
|
9
|
+
# = Action Dispatch \Response
|
10
|
+
#
|
9
11
|
# Represents an HTTP response generated by a controller action. Use it to
|
10
12
|
# retrieve the current state of the response, or customize the response. It can
|
11
13
|
# either represent a real HTTP response (i.e. one that is meant to be sent
|
12
14
|
# back to the web browser) or a TestResponse (i.e. one that is generated
|
13
15
|
# from integration tests).
|
14
16
|
#
|
15
|
-
# \Response
|
16
|
-
#
|
17
|
-
# methods
|
18
|
-
#
|
19
|
-
# ActionControllerBase#headers instead of Response#headers.
|
17
|
+
# The \Response object for the current request is exposed on controllers as
|
18
|
+
# ActionController::Metal#response. ActionController::Metal also provides a
|
19
|
+
# few additional methods that delegate to attributes of the \Response such as
|
20
|
+
# ActionController::Metal#headers.
|
20
21
|
#
|
21
|
-
#
|
22
|
-
# more detail
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# objects of type TestResponse (which are of course also of type \Response).
|
22
|
+
# Integration tests will likely also want to inspect responses in
|
23
|
+
# more detail. Methods such as Integration::RequestHelpers#get
|
24
|
+
# and Integration::RequestHelpers#post return instances of
|
25
|
+
# TestResponse (which inherits from \Response) for this purpose.
|
26
26
|
#
|
27
27
|
# For example, the following demo integration test prints the body of the
|
28
28
|
# controller response to the console:
|
@@ -34,41 +34,43 @@ module ActionDispatch # :nodoc:
|
|
34
34
|
# end
|
35
35
|
# end
|
36
36
|
class Response
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
raise ActionDispatch::IllegalStateError, "header already sent"
|
46
|
-
end
|
47
|
-
|
48
|
-
super
|
49
|
-
end
|
50
|
-
|
51
|
-
def merge(other)
|
52
|
-
self.class.new @response, __getobj__.merge(other)
|
53
|
-
end
|
54
|
-
|
55
|
-
def to_hash
|
56
|
-
__getobj__.dup
|
57
|
-
end
|
37
|
+
begin
|
38
|
+
# For `Rack::Headers` (Rack 3+):
|
39
|
+
require "rack/headers"
|
40
|
+
Headers = ::Rack::Headers
|
41
|
+
rescue LoadError
|
42
|
+
# For `Rack::Utils::HeaderHash`:
|
43
|
+
require "rack/utils"
|
44
|
+
Headers = ::Rack::Utils::HeaderHash
|
58
45
|
end
|
59
46
|
|
47
|
+
# To be deprecated:
|
48
|
+
Header = Headers
|
49
|
+
|
60
50
|
# The request that the response is responding to.
|
61
51
|
attr_accessor :request
|
62
52
|
|
63
53
|
# The HTTP status code.
|
64
54
|
attr_reader :status
|
65
55
|
|
66
|
-
#
|
67
|
-
|
56
|
+
# The headers for the response.
|
57
|
+
#
|
58
|
+
# header["Content-Type"] # => "text/plain"
|
59
|
+
# header["Content-Type"] = "application/json"
|
60
|
+
# header["Content-Type"] # => "application/json"
|
61
|
+
#
|
62
|
+
# Also aliased as +headers+.
|
63
|
+
#
|
64
|
+
# headers["Content-Type"] # => "text/plain"
|
65
|
+
# headers["Content-Type"] = "application/json"
|
66
|
+
# headers["Content-Type"] # => "application/json"
|
67
|
+
#
|
68
|
+
# Also aliased as +header+ for compatibility.
|
69
|
+
attr_reader :headers
|
68
70
|
|
69
|
-
alias_method :
|
71
|
+
alias_method :header, :headers
|
70
72
|
|
71
|
-
delegate :[], :[]=, to: :@
|
73
|
+
delegate :[], :[]=, to: :@headers
|
72
74
|
|
73
75
|
def each(&block)
|
74
76
|
sending!
|
@@ -79,7 +81,6 @@ module ActionDispatch # :nodoc:
|
|
79
81
|
|
80
82
|
CONTENT_TYPE = "Content-Type"
|
81
83
|
SET_COOKIE = "Set-Cookie"
|
82
|
-
LOCATION = "Location"
|
83
84
|
NO_CONTENT_CODES = [100, 101, 102, 103, 204, 205, 304]
|
84
85
|
|
85
86
|
cattr_accessor :default_charset, default: "utf-8"
|
@@ -102,6 +103,12 @@ module ActionDispatch # :nodoc:
|
|
102
103
|
@str_body = nil
|
103
104
|
end
|
104
105
|
|
106
|
+
def to_ary
|
107
|
+
@buf.respond_to?(:to_ary) ?
|
108
|
+
@buf.to_ary :
|
109
|
+
@buf.each
|
110
|
+
end
|
111
|
+
|
105
112
|
def body
|
106
113
|
@str_body ||= begin
|
107
114
|
buf = +""
|
@@ -117,6 +124,7 @@ module ActionDispatch # :nodoc:
|
|
117
124
|
@response.commit!
|
118
125
|
@buf.push string
|
119
126
|
end
|
127
|
+
alias_method :<<, :write
|
120
128
|
|
121
129
|
def each(&block)
|
122
130
|
if @str_body
|
@@ -146,9 +154,9 @@ module ActionDispatch # :nodoc:
|
|
146
154
|
end
|
147
155
|
end
|
148
156
|
|
149
|
-
def self.create(status = 200,
|
150
|
-
|
151
|
-
new status,
|
157
|
+
def self.create(status = 200, headers = {}, body = [], default_headers: self.default_headers)
|
158
|
+
headers = merge_default_headers(headers, default_headers)
|
159
|
+
new status, headers, body
|
152
160
|
end
|
153
161
|
|
154
162
|
def self.merge_default_headers(original, default)
|
@@ -158,10 +166,14 @@ module ActionDispatch # :nodoc:
|
|
158
166
|
# The underlying body, as a streamable object.
|
159
167
|
attr_reader :stream
|
160
168
|
|
161
|
-
def initialize(status = 200,
|
169
|
+
def initialize(status = 200, headers = nil, body = [])
|
162
170
|
super()
|
163
171
|
|
164
|
-
@
|
172
|
+
@headers = Headers.new
|
173
|
+
|
174
|
+
headers&.each do |key, value|
|
175
|
+
@headers[key] = value
|
176
|
+
end
|
165
177
|
|
166
178
|
self.body, self.status = body, status
|
167
179
|
|
@@ -175,10 +187,10 @@ module ActionDispatch # :nodoc:
|
|
175
187
|
yield self if block_given?
|
176
188
|
end
|
177
189
|
|
178
|
-
def has_header?(key); headers.key? key; end
|
179
|
-
def get_header(key); headers[key]; end
|
180
|
-
def set_header(key, v); headers[key] = v; end
|
181
|
-
def delete_header(key); headers.delete key; end
|
190
|
+
def has_header?(key); @headers.key? key; end
|
191
|
+
def get_header(key); @headers[key]; end
|
192
|
+
def set_header(key, v); @headers[key] = v; end
|
193
|
+
def delete_header(key); @headers.delete key; end
|
182
194
|
|
183
195
|
def await_commit
|
184
196
|
synchronize do
|
@@ -281,7 +293,7 @@ module ActionDispatch # :nodoc:
|
|
281
293
|
@status
|
282
294
|
end
|
283
295
|
|
284
|
-
# Returns a string to ensure compatibility with
|
296
|
+
# Returns a string to ensure compatibility with +Net::HTTPResponse+.
|
285
297
|
def code
|
286
298
|
@status.to_s
|
287
299
|
end
|
@@ -384,7 +396,7 @@ module ActionDispatch # :nodoc:
|
|
384
396
|
# status, headers, body = *response
|
385
397
|
def to_a
|
386
398
|
commit!
|
387
|
-
rack_response @status, @
|
399
|
+
rack_response @status, @headers.to_hash
|
388
400
|
end
|
389
401
|
alias prepare! to_a
|
390
402
|
|
@@ -451,8 +463,7 @@ module ActionDispatch # :nodoc:
|
|
451
463
|
# our last chance.
|
452
464
|
commit! unless committed?
|
453
465
|
|
454
|
-
|
455
|
-
request.commit_cookie_jar! unless committed?
|
466
|
+
@request.commit_cookie_jar! unless committed?
|
456
467
|
end
|
457
468
|
|
458
469
|
def build_buffer(response, body)
|
@@ -476,10 +487,6 @@ module ActionDispatch # :nodoc:
|
|
476
487
|
@response = response
|
477
488
|
end
|
478
489
|
|
479
|
-
def each(*args, &block)
|
480
|
-
@response.each(*args, &block)
|
481
|
-
end
|
482
|
-
|
483
490
|
def close
|
484
491
|
# Rack "close" maps to Response#abort, and *not* Response#close
|
485
492
|
# (which is used when the controller's finished writing)
|
@@ -490,35 +497,45 @@ module ActionDispatch # :nodoc:
|
|
490
497
|
@response.body
|
491
498
|
end
|
492
499
|
|
500
|
+
BODY_METHODS = { to_ary: true, each: true, call: true, to_path: true }
|
501
|
+
|
493
502
|
def respond_to?(method, include_private = false)
|
494
|
-
if method
|
503
|
+
if BODY_METHODS.key?(method)
|
495
504
|
@response.stream.respond_to?(method)
|
496
505
|
else
|
497
506
|
super
|
498
507
|
end
|
499
508
|
end
|
500
509
|
|
501
|
-
def
|
502
|
-
@response.stream.
|
510
|
+
def to_ary
|
511
|
+
@response.stream.to_ary
|
503
512
|
end
|
504
513
|
|
505
|
-
def
|
506
|
-
|
514
|
+
def each(*args, &block)
|
515
|
+
@response.each(*args, &block)
|
516
|
+
end
|
517
|
+
|
518
|
+
def call(*arguments, &block)
|
519
|
+
@response.stream.call(*arguments, &block)
|
520
|
+
end
|
521
|
+
|
522
|
+
def to_path
|
523
|
+
@response.stream.to_path
|
507
524
|
end
|
508
525
|
end
|
509
526
|
|
510
527
|
def handle_no_content!
|
511
528
|
if NO_CONTENT_CODES.include?(@status)
|
512
|
-
@
|
513
|
-
@
|
529
|
+
@headers.delete CONTENT_TYPE
|
530
|
+
@headers.delete "Content-Length"
|
514
531
|
end
|
515
532
|
end
|
516
533
|
|
517
|
-
def rack_response(status,
|
534
|
+
def rack_response(status, headers)
|
518
535
|
if NO_CONTENT_CODES.include?(status)
|
519
|
-
[status,
|
536
|
+
[status, headers, []]
|
520
537
|
else
|
521
|
-
[status,
|
538
|
+
[status, headers, RackBody.new(self)]
|
522
539
|
end
|
523
540
|
end
|
524
541
|
end
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
module ActionDispatch
|
4
4
|
module Http
|
5
|
+
# = Action Dispatch HTTP \UploadedFile
|
6
|
+
#
|
5
7
|
# Models uploaded files.
|
6
8
|
#
|
7
9
|
# The actual file is accessible via the +tempfile+ accessor, though some
|
@@ -28,6 +30,8 @@ module ActionDispatch
|
|
28
30
|
@tempfile = hash[:tempfile]
|
29
31
|
raise(ArgumentError, ":tempfile is required") unless @tempfile
|
30
32
|
|
33
|
+
@content_type = hash[:type]
|
34
|
+
|
31
35
|
if hash[:filename]
|
32
36
|
@original_filename = hash[:filename].dup
|
33
37
|
|
@@ -40,8 +44,17 @@ module ActionDispatch
|
|
40
44
|
@original_filename = nil
|
41
45
|
end
|
42
46
|
|
43
|
-
|
44
|
-
|
47
|
+
if hash[:head]
|
48
|
+
@headers = hash[:head].dup
|
49
|
+
|
50
|
+
begin
|
51
|
+
@headers.encode!(Encoding::UTF_8)
|
52
|
+
rescue EncodingError
|
53
|
+
@headers.force_encoding(Encoding::UTF_8)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
@headers = nil
|
57
|
+
end
|
45
58
|
end
|
46
59
|
|
47
60
|
# Shortcut for +tempfile.read+.
|
@@ -57,6 +57,9 @@ module ActionDispatch
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def generate(name, options, path_parameters)
|
60
|
+
original_options = options.dup
|
61
|
+
path_params = options.delete(:path_params) || {}
|
62
|
+
options = path_params.merge(options)
|
60
63
|
constraints = path_parameters.merge(options)
|
61
64
|
missing_keys = nil
|
62
65
|
|
@@ -70,8 +73,11 @@ module ActionDispatch
|
|
70
73
|
|
71
74
|
missing_keys = missing_keys(route, parameterized_parts)
|
72
75
|
next if missing_keys && !missing_keys.empty?
|
73
|
-
params = options.
|
74
|
-
|
76
|
+
params = options.delete_if do |key, _|
|
77
|
+
# top-level params' normal behavior of generating query_params
|
78
|
+
# should be preserved even if the same key is also a bind_param
|
79
|
+
parameterized_parts.key?(key) || route.defaults.key?(key) ||
|
80
|
+
(path_params.key?(key) && !original_options.key?(key))
|
75
81
|
end
|
76
82
|
|
77
83
|
defaults = route.defaults
|
@@ -183,22 +183,22 @@ module ActionDispatch
|
|
183
183
|
end
|
184
184
|
|
185
185
|
def offsets
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
186
|
+
@offsets ||= begin
|
187
|
+
offsets = [0]
|
188
|
+
|
189
|
+
spec.find_all(&:symbol?).each do |node|
|
190
|
+
node = node.to_sym
|
191
|
+
|
192
|
+
if @requirements.key?(node)
|
193
|
+
re = /#{Regexp.union(@requirements[node])}|/
|
194
|
+
offsets.push((re.match("").length - 1) + offsets.last)
|
195
|
+
else
|
196
|
+
offsets << offsets.last
|
197
|
+
end
|
198
198
|
end
|
199
|
-
end
|
200
199
|
|
201
|
-
|
200
|
+
offsets
|
201
|
+
end
|
202
202
|
end
|
203
203
|
end
|
204
204
|
end
|
@@ -5,7 +5,7 @@ module ActionDispatch
|
|
5
5
|
module Journey
|
6
6
|
class Route
|
7
7
|
attr_reader :app, :path, :defaults, :name, :precedence, :constraints,
|
8
|
-
:internal, :scope_options, :ast
|
8
|
+
:internal, :scope_options, :ast, :source_location
|
9
9
|
|
10
10
|
alias :conditions :constraints
|
11
11
|
|
@@ -53,7 +53,7 @@ module ActionDispatch
|
|
53
53
|
##
|
54
54
|
# +path+ is a path constraint.
|
55
55
|
# +constraints+ is a hash of constraints to be applied to this route.
|
56
|
-
def initialize(name:, app: nil, path:, constraints: {}, required_defaults: [], defaults: {}, request_method_match: nil, precedence: 0, scope_options: {}, internal: false)
|
56
|
+
def initialize(name:, app: nil, path:, constraints: {}, required_defaults: [], defaults: {}, request_method_match: nil, precedence: 0, scope_options: {}, internal: false, source_location: nil)
|
57
57
|
@name = name
|
58
58
|
@app = app
|
59
59
|
@path = path
|
@@ -69,6 +69,7 @@ module ActionDispatch
|
|
69
69
|
@path_formatter = @path.build_formatter
|
70
70
|
@scope_options = scope_options
|
71
71
|
@internal = internal
|
72
|
+
@source_location = source_location
|
72
73
|
|
73
74
|
@ast = @path.ast.root
|
74
75
|
@path.ast.route = self
|
@@ -29,7 +29,7 @@ module ActionDispatch
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def serve(req)
|
32
|
-
find_routes(req)
|
32
|
+
find_routes(req) do |match, parameters, route|
|
33
33
|
set_params = req.path_parameters
|
34
34
|
path_info = req.path_info
|
35
35
|
script_name = req.script_name
|
@@ -46,24 +46,25 @@ module ActionDispatch
|
|
46
46
|
}
|
47
47
|
|
48
48
|
req.path_parameters = tmp_params
|
49
|
+
req.route_uri_pattern = route.path.spec.to_s
|
49
50
|
|
50
|
-
|
51
|
+
_, headers, _ = response = route.app.serve(req)
|
51
52
|
|
52
|
-
if "pass" == headers[
|
53
|
+
if "pass" == headers[Constants::X_CASCADE]
|
53
54
|
req.script_name = script_name
|
54
55
|
req.path_info = path_info
|
55
56
|
req.path_parameters = set_params
|
56
57
|
next
|
57
58
|
end
|
58
59
|
|
59
|
-
return
|
60
|
+
return response
|
60
61
|
end
|
61
62
|
|
62
|
-
[404, {
|
63
|
+
[404, { Constants::X_CASCADE => "pass" }, ["Not Found"]]
|
63
64
|
end
|
64
65
|
|
65
66
|
def recognize(rails_req)
|
66
|
-
find_routes(rails_req)
|
67
|
+
find_routes(rails_req) do |match, parameters, route|
|
67
68
|
unless route.path.anchored
|
68
69
|
rails_req.script_name = match.to_s
|
69
70
|
rails_req.path_info = match.post_match
|
@@ -120,14 +121,14 @@ module ActionDispatch
|
|
120
121
|
|
121
122
|
routes.sort_by!(&:precedence)
|
122
123
|
|
123
|
-
routes.
|
124
|
+
routes.each { |r|
|
124
125
|
match_data = r.path.match(path_info)
|
125
126
|
path_parameters = {}
|
126
127
|
match_data.names.each_with_index { |name, i|
|
127
128
|
val = match_data[i + 1]
|
128
129
|
path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
|
129
130
|
}
|
130
|
-
[match_data, path_parameters, r]
|
131
|
+
yield [match_data, path_parameters, r]
|
131
132
|
}
|
132
133
|
end
|
133
134
|
|