actionpack 7.1.3 → 7.2.3
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 +121 -465
- data/README.rdoc +1 -1
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +93 -100
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +66 -64
- data/lib/abstract_controller/collector.rb +7 -7
- data/lib/abstract_controller/deprecator.rb +2 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +71 -84
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -12
- data/lib/abstract_controller/translation.rb +15 -7
- data/lib/abstract_controller/url_for.rb +8 -6
- data/lib/abstract_controller.rb +2 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +75 -72
- data/lib/action_controller/base.rb +198 -126
- data/lib/action_controller/caching.rb +15 -12
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +20 -17
- data/lib/action_controller/log_subscriber.rb +3 -1
- data/lib/action_controller/metal/allow_browser.rb +123 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +187 -174
- data/lib/action_controller/metal/content_security_policy.rb +25 -24
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +64 -55
- data/lib/action_controller/metal/default_headers.rb +5 -3
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
- data/lib/action_controller/metal/exceptions.rb +11 -9
- data/lib/action_controller/metal/flash.rb +12 -10
- data/lib/action_controller/metal/head.rb +12 -10
- data/lib/action_controller/metal/helpers.rb +63 -55
- data/lib/action_controller/metal/http_authentication.rb +211 -206
- data/lib/action_controller/metal/implicit_render.rb +17 -15
- data/lib/action_controller/metal/instrumentation.rb +15 -12
- data/lib/action_controller/metal/live.rb +117 -108
- data/lib/action_controller/metal/logging.rb +6 -4
- data/lib/action_controller/metal/mime_responds.rb +151 -142
- data/lib/action_controller/metal/parameter_encoding.rb +34 -32
- data/lib/action_controller/metal/params_wrapper.rb +57 -59
- data/lib/action_controller/metal/permissions_policy.rb +13 -12
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +112 -85
- data/lib/action_controller/metal/renderers.rb +50 -49
- data/lib/action_controller/metal/rendering.rb +104 -76
- data/lib/action_controller/metal/request_forgery_protection.rb +165 -134
- data/lib/action_controller/metal/rescue.rb +11 -9
- data/lib/action_controller/metal/streaming.rb +138 -136
- data/lib/action_controller/metal/strong_parameters.rb +525 -483
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +17 -15
- data/lib/action_controller/metal.rb +86 -60
- data/lib/action_controller/railtie.rb +3 -0
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +41 -36
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +148 -129
- data/lib/action_controller.rb +10 -3
- data/lib/action_dispatch/constants.rb +8 -0
- data/lib/action_dispatch/deprecator.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +27 -26
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +61 -42
- data/lib/action_dispatch/http/filter_parameters.rb +18 -9
- data/lib/action_dispatch/http/filter_redirect.rb +22 -1
- data/lib/action_dispatch/http/headers.rb +22 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +35 -41
- data/lib/action_dispatch/http/mime_type.rb +31 -24
- data/lib/action_dispatch/http/mime_types.rb +2 -0
- data/lib/action_dispatch/http/parameters.rb +11 -9
- data/lib/action_dispatch/http/permissions_policy.rb +20 -44
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +96 -76
- data/lib/action_dispatch/http/response.rb +88 -62
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +77 -75
- data/lib/action_dispatch/journey/formatter.rb +21 -9
- data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +14 -12
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +6 -5
- data/lib/action_dispatch/journey/parser.rb +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +2 -0
- data/lib/action_dispatch/journey/path/pattern.rb +4 -1
- data/lib/action_dispatch/journey/route.rb +9 -7
- data/lib/action_dispatch/journey/router/utils.rb +16 -15
- data/lib/action_dispatch/journey/router.rb +4 -2
- data/lib/action_dispatch/journey/routes.rb +4 -2
- data/lib/action_dispatch/journey/scanner.rb +4 -2
- data/lib/action_dispatch/journey/visitors.rb +2 -0
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +2 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
- data/lib/action_dispatch/middleware/callbacks.rb +3 -1
- data/lib/action_dispatch/middleware/cookies.rb +119 -104
- data/lib/action_dispatch/middleware/debug_exceptions.rb +16 -6
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +2 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +9 -14
- data/lib/action_dispatch/middleware/executor.rb +13 -2
- data/lib/action_dispatch/middleware/flash.rb +63 -51
- data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
- data/lib/action_dispatch/middleware/public_exceptions.rb +13 -7
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +76 -72
- data/lib/action_dispatch/middleware/request_id.rb +14 -9
- data/lib/action_dispatch/middleware/server_timing.rb +4 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +13 -8
- data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +31 -21
- data/lib/action_dispatch/middleware/ssl.rb +43 -40
- data/lib/action_dispatch/middleware/stack.rb +11 -10
- data/lib/action_dispatch/middleware/static.rb +33 -31
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +2 -4
- data/lib/action_dispatch/request/session.rb +23 -21
- data/lib/action_dispatch/request/utils.rb +2 -0
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +6 -4
- data/lib/action_dispatch/routing/mapper.rb +673 -637
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +37 -32
- data/lib/action_dispatch/routing/route_set.rb +60 -46
- data/lib/action_dispatch/routing/routes_proxy.rb +6 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +10 -3
- data/lib/action_dispatch/system_testing/driver.rb +3 -1
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +32 -21
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +9 -7
- data/lib/action_dispatch/testing/assertions/response.rb +26 -23
- data/lib/action_dispatch/testing/assertions/routing.rb +153 -84
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +222 -222
- data/lib/action_dispatch/testing/request_encoder.rb +11 -9
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +11 -8
- data/lib/action_dispatch/testing/test_request.rb +3 -1
- data/lib/action_dispatch/testing/test_response.rb +27 -26
- data/lib/action_dispatch.rb +25 -27
- data/lib/action_pack/gem_version.rb +4 -2
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +50 -16
|
@@ -1,38 +1,40 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "active_support/core_ext/module/attribute_accessors"
|
|
4
6
|
require "action_dispatch/http/filter_redirect"
|
|
5
7
|
require "action_dispatch/http/cache"
|
|
6
8
|
require "monitor"
|
|
7
9
|
|
|
8
10
|
module ActionDispatch # :nodoc:
|
|
9
|
-
#
|
|
11
|
+
# # Action Dispatch Response
|
|
10
12
|
#
|
|
11
13
|
# Represents an HTTP response generated by a controller action. Use it to
|
|
12
14
|
# retrieve the current state of the response, or customize the response. It can
|
|
13
|
-
# either represent a real HTTP response (i.e. one that is meant to be sent
|
|
14
|
-
#
|
|
15
|
-
#
|
|
15
|
+
# either represent a real HTTP response (i.e. one that is meant to be sent back
|
|
16
|
+
# to the web browser) or a TestResponse (i.e. one that is generated from
|
|
17
|
+
# integration tests).
|
|
16
18
|
#
|
|
17
|
-
# The
|
|
18
|
-
# ActionController::Metal#response. ActionController::Metal also provides a
|
|
19
|
-
#
|
|
19
|
+
# The Response object for the current request is exposed on controllers as
|
|
20
|
+
# ActionController::Metal#response. ActionController::Metal also provides a few
|
|
21
|
+
# additional methods that delegate to attributes of the Response such as
|
|
20
22
|
# ActionController::Metal#headers.
|
|
21
23
|
#
|
|
22
|
-
# Integration tests will likely also want to inspect responses in
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
24
|
+
# Integration tests will likely also want to inspect responses in more detail.
|
|
25
|
+
# Methods such as Integration::RequestHelpers#get and
|
|
26
|
+
# Integration::RequestHelpers#post return instances of TestResponse (which
|
|
27
|
+
# inherits from Response) for this purpose.
|
|
26
28
|
#
|
|
27
29
|
# For example, the following demo integration test prints the body of the
|
|
28
30
|
# controller response to the console:
|
|
29
31
|
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
32
|
+
# class DemoControllerTest < ActionDispatch::IntegrationTest
|
|
33
|
+
# def test_print_root_path_to_console
|
|
34
|
+
# get('/')
|
|
35
|
+
# puts response.body
|
|
36
|
+
# end
|
|
37
|
+
# end
|
|
36
38
|
class Response
|
|
37
39
|
begin
|
|
38
40
|
# For `Rack::Headers` (Rack 3+):
|
|
@@ -44,6 +46,20 @@ module ActionDispatch # :nodoc:
|
|
|
44
46
|
Headers = ::Rack::Utils::HeaderHash
|
|
45
47
|
end
|
|
46
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
|
+
|
|
47
63
|
# To be deprecated:
|
|
48
64
|
Header = Headers
|
|
49
65
|
|
|
@@ -55,17 +71,17 @@ module ActionDispatch # :nodoc:
|
|
|
55
71
|
|
|
56
72
|
# The headers for the response.
|
|
57
73
|
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
74
|
+
# header["Content-Type"] # => "text/plain"
|
|
75
|
+
# header["Content-Type"] = "application/json"
|
|
76
|
+
# header["Content-Type"] # => "application/json"
|
|
61
77
|
#
|
|
62
|
-
# Also aliased as
|
|
78
|
+
# Also aliased as `headers`.
|
|
63
79
|
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
80
|
+
# headers["Content-Type"] # => "text/plain"
|
|
81
|
+
# headers["Content-Type"] = "application/json"
|
|
82
|
+
# headers["Content-Type"] # => "application/json"
|
|
67
83
|
#
|
|
68
|
-
# Also aliased as
|
|
84
|
+
# Also aliased as `header` for compatibility.
|
|
69
85
|
attr_reader :headers
|
|
70
86
|
|
|
71
87
|
alias_method :header, :headers
|
|
@@ -229,18 +245,30 @@ module ActionDispatch # :nodoc:
|
|
|
229
245
|
def committed?; synchronize { @committed }; end
|
|
230
246
|
def sent?; synchronize { @sent }; end
|
|
231
247
|
|
|
248
|
+
##
|
|
249
|
+
# :method: location
|
|
250
|
+
#
|
|
251
|
+
# Location of the response.
|
|
252
|
+
|
|
253
|
+
##
|
|
254
|
+
# :method: location=
|
|
255
|
+
#
|
|
256
|
+
# :call-seq: location=(location)
|
|
257
|
+
#
|
|
258
|
+
# Sets the location of the response
|
|
259
|
+
|
|
232
260
|
# Sets the HTTP status code.
|
|
233
261
|
def status=(status)
|
|
234
|
-
@status =
|
|
262
|
+
@status = Response.rack_status_code(status)
|
|
235
263
|
end
|
|
236
264
|
|
|
237
|
-
# Sets the HTTP response's content MIME type. For example, in the controller
|
|
238
|
-
#
|
|
265
|
+
# Sets the HTTP response's content MIME type. For example, in the controller you
|
|
266
|
+
# could write this:
|
|
239
267
|
#
|
|
240
|
-
#
|
|
268
|
+
# response.content_type = "text/plain"
|
|
241
269
|
#
|
|
242
|
-
# If a character set has been defined for this response (see charset=) then
|
|
243
|
-
#
|
|
270
|
+
# If a character set has been defined for this response (see #charset=) then the
|
|
271
|
+
# character set information will also be included in the content type
|
|
244
272
|
# information.
|
|
245
273
|
def content_type=(content_type)
|
|
246
274
|
return unless content_type
|
|
@@ -267,11 +295,11 @@ module ActionDispatch # :nodoc:
|
|
|
267
295
|
end
|
|
268
296
|
end
|
|
269
297
|
|
|
270
|
-
# Sets the HTTP character set. In case of
|
|
271
|
-
#
|
|
298
|
+
# Sets the HTTP character set. In case of `nil` parameter it sets the charset to
|
|
299
|
+
# `default_charset`.
|
|
272
300
|
#
|
|
273
|
-
#
|
|
274
|
-
#
|
|
301
|
+
# response.charset = 'utf-16' # => 'utf-16'
|
|
302
|
+
# response.charset = nil # => 'utf-8'
|
|
275
303
|
def charset=(charset)
|
|
276
304
|
content_type = parsed_content_type_header.mime_type
|
|
277
305
|
if false == charset
|
|
@@ -281,8 +309,8 @@ module ActionDispatch # :nodoc:
|
|
|
281
309
|
end
|
|
282
310
|
end
|
|
283
311
|
|
|
284
|
-
# The charset of the response. HTML wants to know the encoding of the
|
|
285
|
-
#
|
|
312
|
+
# The charset of the response. HTML wants to know the encoding of the content
|
|
313
|
+
# you're giving them, so we need to send that along.
|
|
286
314
|
def charset
|
|
287
315
|
header_info = parsed_content_type_header
|
|
288
316
|
header_info.charset || self.class.default_charset
|
|
@@ -293,26 +321,26 @@ module ActionDispatch # :nodoc:
|
|
|
293
321
|
@status
|
|
294
322
|
end
|
|
295
323
|
|
|
296
|
-
# Returns a string to ensure compatibility with
|
|
324
|
+
# Returns a string to ensure compatibility with `Net::HTTPResponse`.
|
|
297
325
|
def code
|
|
298
326
|
@status.to_s
|
|
299
327
|
end
|
|
300
328
|
|
|
301
329
|
# Returns the corresponding message for the current HTTP status code:
|
|
302
330
|
#
|
|
303
|
-
#
|
|
304
|
-
#
|
|
331
|
+
# response.status = 200
|
|
332
|
+
# response.message # => "OK"
|
|
305
333
|
#
|
|
306
|
-
#
|
|
307
|
-
#
|
|
334
|
+
# response.status = 404
|
|
335
|
+
# response.message # => "Not Found"
|
|
308
336
|
#
|
|
309
337
|
def message
|
|
310
338
|
Rack::Utils::HTTP_STATUS_CODES[@status]
|
|
311
339
|
end
|
|
312
340
|
alias_method :status_message, :message
|
|
313
341
|
|
|
314
|
-
# Returns the content of the response as a string. This contains the contents
|
|
315
|
-
#
|
|
342
|
+
# Returns the content of the response as a string. This contains the contents of
|
|
343
|
+
# any calls to `render`.
|
|
316
344
|
def body
|
|
317
345
|
@stream.body
|
|
318
346
|
end
|
|
@@ -332,9 +360,9 @@ module ActionDispatch # :nodoc:
|
|
|
332
360
|
end
|
|
333
361
|
end
|
|
334
362
|
|
|
335
|
-
# Avoid having to pass an open file handle as the response body.
|
|
336
|
-
#
|
|
337
|
-
#
|
|
363
|
+
# Avoid having to pass an open file handle as the response body. Rack::Sendfile
|
|
364
|
+
# will usually intercept the response and uses the path directly, so there is no
|
|
365
|
+
# reason to open the file.
|
|
338
366
|
class FileBody # :nodoc:
|
|
339
367
|
attr_reader :to_path
|
|
340
368
|
|
|
@@ -356,7 +384,7 @@ module ActionDispatch # :nodoc:
|
|
|
356
384
|
end
|
|
357
385
|
end
|
|
358
386
|
|
|
359
|
-
# Send the file stored at
|
|
387
|
+
# Send the file stored at `path` as the response body.
|
|
360
388
|
def send_file(path)
|
|
361
389
|
commit!
|
|
362
390
|
@stream = FileBody.new(path)
|
|
@@ -383,17 +411,16 @@ module ActionDispatch # :nodoc:
|
|
|
383
411
|
if stream.respond_to?(:abort)
|
|
384
412
|
stream.abort
|
|
385
413
|
elsif stream.respond_to?(:close)
|
|
386
|
-
# `stream.close` should really be reserved for a close from the
|
|
387
|
-
#
|
|
388
|
-
# compatibility.
|
|
414
|
+
# `stream.close` should really be reserved for a close from the other direction,
|
|
415
|
+
# but we must fall back to it for compatibility.
|
|
389
416
|
stream.close
|
|
390
417
|
end
|
|
391
418
|
end
|
|
392
419
|
|
|
393
|
-
# Turns the Response into a Rack-compatible array of the status, headers,
|
|
394
|
-
#
|
|
420
|
+
# Turns the Response into a Rack-compatible array of the status, headers, and
|
|
421
|
+
# body. Allows explicit splatting:
|
|
395
422
|
#
|
|
396
|
-
#
|
|
423
|
+
# status, headers, body = *response
|
|
397
424
|
def to_a
|
|
398
425
|
commit!
|
|
399
426
|
rack_response @status, @headers.to_hash
|
|
@@ -402,7 +429,7 @@ module ActionDispatch # :nodoc:
|
|
|
402
429
|
|
|
403
430
|
# Returns the response cookies, converted to a Hash of (name => value) pairs
|
|
404
431
|
#
|
|
405
|
-
#
|
|
432
|
+
# assert_equal 'AuthorOfNewPage', r.cookies['author']
|
|
406
433
|
def cookies
|
|
407
434
|
cookies = {}
|
|
408
435
|
if header = get_header(SET_COOKIE)
|
|
@@ -456,11 +483,10 @@ module ActionDispatch # :nodoc:
|
|
|
456
483
|
end
|
|
457
484
|
|
|
458
485
|
def before_sending
|
|
459
|
-
# Normally we've already committed by now, but it's possible
|
|
460
|
-
#
|
|
461
|
-
#
|
|
462
|
-
#
|
|
463
|
-
# our last chance.
|
|
486
|
+
# Normally we've already committed by now, but it's possible (e.g., if the
|
|
487
|
+
# controller action tries to read back its own response) to get here before
|
|
488
|
+
# that. In that case, we must force an "early" commit: we're about to freeze the
|
|
489
|
+
# headers, so this is our last chance.
|
|
464
490
|
commit! unless committed?
|
|
465
491
|
|
|
466
492
|
@request.commit_cookie_jar! unless committed?
|
|
@@ -488,8 +514,8 @@ module ActionDispatch # :nodoc:
|
|
|
488
514
|
end
|
|
489
515
|
|
|
490
516
|
def close
|
|
491
|
-
# Rack "close" maps to Response#abort, and
|
|
492
|
-
#
|
|
517
|
+
# Rack "close" maps to Response#abort, and **not** Response#close (which is used
|
|
518
|
+
# when the controller's finished writing)
|
|
493
519
|
@response.abort
|
|
494
520
|
end
|
|
495
521
|
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module ActionDispatch
|
|
4
6
|
module Http
|
|
5
|
-
#
|
|
7
|
+
# # Action Dispatch HTTP UploadedFile
|
|
6
8
|
#
|
|
7
9
|
# Models uploaded files.
|
|
8
10
|
#
|
|
9
|
-
# The actual file is accessible via the
|
|
10
|
-
#
|
|
11
|
+
# The actual file is accessible via the `tempfile` accessor, though some of its
|
|
12
|
+
# interface is available directly for convenience.
|
|
11
13
|
#
|
|
12
|
-
# Uploaded files are temporary files whose lifespan is one request. When
|
|
13
|
-
#
|
|
14
|
-
#
|
|
14
|
+
# Uploaded files are temporary files whose lifespan is one request. When the
|
|
15
|
+
# object is finalized Ruby unlinks the file, so there is no need to clean them
|
|
16
|
+
# with a separate maintenance task.
|
|
15
17
|
class UploadedFile
|
|
16
18
|
# The basename of the file in the client.
|
|
17
19
|
attr_accessor :original_filename
|
|
@@ -19,8 +21,8 @@ module ActionDispatch
|
|
|
19
21
|
# A string with the MIME type of the file.
|
|
20
22
|
attr_accessor :content_type
|
|
21
23
|
|
|
22
|
-
# A
|
|
23
|
-
#
|
|
24
|
+
# A `Tempfile` object with the actual uploaded file. Note that some of its
|
|
25
|
+
# interface is available directly.
|
|
24
26
|
attr_accessor :tempfile
|
|
25
27
|
|
|
26
28
|
# A string with the headers of the multipart request.
|
|
@@ -57,42 +59,42 @@ module ActionDispatch
|
|
|
57
59
|
end
|
|
58
60
|
end
|
|
59
61
|
|
|
60
|
-
# Shortcut for
|
|
62
|
+
# Shortcut for `tempfile.read`.
|
|
61
63
|
def read(length = nil, buffer = nil)
|
|
62
64
|
@tempfile.read(length, buffer)
|
|
63
65
|
end
|
|
64
66
|
|
|
65
|
-
# Shortcut for
|
|
67
|
+
# Shortcut for `tempfile.open`.
|
|
66
68
|
def open
|
|
67
69
|
@tempfile.open
|
|
68
70
|
end
|
|
69
71
|
|
|
70
|
-
# Shortcut for
|
|
72
|
+
# Shortcut for `tempfile.close`.
|
|
71
73
|
def close(unlink_now = false)
|
|
72
74
|
@tempfile.close(unlink_now)
|
|
73
75
|
end
|
|
74
76
|
|
|
75
|
-
# Shortcut for
|
|
77
|
+
# Shortcut for `tempfile.path`.
|
|
76
78
|
def path
|
|
77
79
|
@tempfile.path
|
|
78
80
|
end
|
|
79
81
|
|
|
80
|
-
# Shortcut for
|
|
82
|
+
# Shortcut for `tempfile.to_path`.
|
|
81
83
|
def to_path
|
|
82
84
|
@tempfile.to_path
|
|
83
85
|
end
|
|
84
86
|
|
|
85
|
-
# Shortcut for
|
|
87
|
+
# Shortcut for `tempfile.rewind`.
|
|
86
88
|
def rewind
|
|
87
89
|
@tempfile.rewind
|
|
88
90
|
end
|
|
89
91
|
|
|
90
|
-
# Shortcut for
|
|
92
|
+
# Shortcut for `tempfile.size`.
|
|
91
93
|
def size
|
|
92
94
|
@tempfile.size
|
|
93
95
|
end
|
|
94
96
|
|
|
95
|
-
# Shortcut for
|
|
97
|
+
# Shortcut for `tempfile.eof?`.
|
|
96
98
|
def eof?
|
|
97
99
|
@tempfile.eof?
|
|
98
100
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "active_support/core_ext/module/attribute_accessors"
|
|
4
6
|
|
|
5
7
|
module ActionDispatch
|
|
@@ -15,20 +17,20 @@ module ActionDispatch
|
|
|
15
17
|
class << self
|
|
16
18
|
# Returns the domain part of a host given the domain level.
|
|
17
19
|
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
20
|
+
# # Top-level domain example
|
|
21
|
+
# extract_domain('www.example.com', 1) # => "example.com"
|
|
22
|
+
# # Second-level domain example
|
|
23
|
+
# extract_domain('dev.www.example.co.uk', 2) # => "example.co.uk"
|
|
22
24
|
def extract_domain(host, tld_length)
|
|
23
25
|
extract_domain_from(host, tld_length) if named_host?(host)
|
|
24
26
|
end
|
|
25
27
|
|
|
26
28
|
# Returns the subdomains of a host as an Array given the domain level.
|
|
27
29
|
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
30
|
+
# # Top-level domain example
|
|
31
|
+
# extract_subdomains('www.example.com', 1) # => ["www"]
|
|
32
|
+
# # Second-level domain example
|
|
33
|
+
# extract_subdomains('dev.www.example.co.uk', 2) # => ["dev", "www"]
|
|
32
34
|
def extract_subdomains(host, tld_length)
|
|
33
35
|
if named_host?(host)
|
|
34
36
|
extract_subdomains_from(host, tld_length)
|
|
@@ -39,10 +41,10 @@ module ActionDispatch
|
|
|
39
41
|
|
|
40
42
|
# Returns the subdomains of a host as a String given the domain level.
|
|
41
43
|
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
44
|
+
# # Top-level domain example
|
|
45
|
+
# extract_subdomain('www.example.com', 1) # => "www"
|
|
46
|
+
# # Second-level domain example
|
|
47
|
+
# extract_subdomain('dev.www.example.co.uk', 2) # => "dev.www"
|
|
46
48
|
def extract_subdomain(host, tld_length)
|
|
47
49
|
extract_subdomains(host, tld_length).join(".")
|
|
48
50
|
end
|
|
@@ -184,33 +186,33 @@ module ActionDispatch
|
|
|
184
186
|
|
|
185
187
|
# Returns the complete URL used for this request.
|
|
186
188
|
#
|
|
187
|
-
#
|
|
188
|
-
#
|
|
189
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
|
190
|
+
# req.url # => "http://example.com"
|
|
189
191
|
def url
|
|
190
192
|
protocol + host_with_port + fullpath
|
|
191
193
|
end
|
|
192
194
|
|
|
193
195
|
# Returns 'https://' if this is an SSL request and 'http://' otherwise.
|
|
194
196
|
#
|
|
195
|
-
#
|
|
196
|
-
#
|
|
197
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
|
198
|
+
# req.protocol # => "http://"
|
|
197
199
|
#
|
|
198
|
-
#
|
|
199
|
-
#
|
|
200
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on'
|
|
201
|
+
# req.protocol # => "https://"
|
|
200
202
|
def protocol
|
|
201
203
|
@protocol ||= ssl? ? "https://" : "http://"
|
|
202
204
|
end
|
|
203
205
|
|
|
204
|
-
# Returns the
|
|
206
|
+
# Returns the host and port for this request, such as "example.com:8080".
|
|
205
207
|
#
|
|
206
|
-
#
|
|
207
|
-
#
|
|
208
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
|
209
|
+
# req.raw_host_with_port # => "example.com"
|
|
208
210
|
#
|
|
209
|
-
#
|
|
210
|
-
#
|
|
211
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
|
212
|
+
# req.raw_host_with_port # => "example.com:80"
|
|
211
213
|
#
|
|
212
|
-
#
|
|
213
|
-
#
|
|
214
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
215
|
+
# req.raw_host_with_port # => "example.com:8080"
|
|
214
216
|
def raw_host_with_port
|
|
215
217
|
if forwarded = x_forwarded_host.presence
|
|
216
218
|
forwarded.split(/,\s?/).last
|
|
@@ -221,35 +223,35 @@ module ActionDispatch
|
|
|
221
223
|
|
|
222
224
|
# Returns the host for this request, such as "example.com".
|
|
223
225
|
#
|
|
224
|
-
#
|
|
225
|
-
#
|
|
226
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
227
|
+
# req.host # => "example.com"
|
|
226
228
|
def host
|
|
227
229
|
raw_host_with_port.sub(/:\d+$/, "")
|
|
228
230
|
end
|
|
229
231
|
|
|
230
|
-
# Returns a
|
|
231
|
-
# "example.com:8080". Port is only included if it is not a default port
|
|
232
|
-
#
|
|
232
|
+
# Returns a host:port string for this request, such as "example.com" or
|
|
233
|
+
# "example.com:8080". Port is only included if it is not a default port (80 or
|
|
234
|
+
# 443)
|
|
233
235
|
#
|
|
234
|
-
#
|
|
235
|
-
#
|
|
236
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
|
237
|
+
# req.host_with_port # => "example.com"
|
|
236
238
|
#
|
|
237
|
-
#
|
|
238
|
-
#
|
|
239
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
|
240
|
+
# req.host_with_port # => "example.com"
|
|
239
241
|
#
|
|
240
|
-
#
|
|
241
|
-
#
|
|
242
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
243
|
+
# req.host_with_port # => "example.com:8080"
|
|
242
244
|
def host_with_port
|
|
243
245
|
"#{host}#{port_string}"
|
|
244
246
|
end
|
|
245
247
|
|
|
246
248
|
# Returns the port number of this request as an integer.
|
|
247
249
|
#
|
|
248
|
-
#
|
|
249
|
-
#
|
|
250
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com'
|
|
251
|
+
# req.port # => 80
|
|
250
252
|
#
|
|
251
|
-
#
|
|
252
|
-
#
|
|
253
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
254
|
+
# req.port # => 8080
|
|
253
255
|
def port
|
|
254
256
|
@port ||= if raw_host_with_port =~ /:(\d+)$/
|
|
255
257
|
$1.to_i
|
|
@@ -258,10 +260,10 @@ module ActionDispatch
|
|
|
258
260
|
end
|
|
259
261
|
end
|
|
260
262
|
|
|
261
|
-
# Returns the standard
|
|
263
|
+
# Returns the standard port number for this request's protocol.
|
|
262
264
|
#
|
|
263
|
-
#
|
|
264
|
-
#
|
|
265
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
266
|
+
# req.standard_port # => 80
|
|
265
267
|
def standard_port
|
|
266
268
|
if "https://" == protocol
|
|
267
269
|
443
|
|
@@ -270,70 +272,70 @@ module ActionDispatch
|
|
|
270
272
|
end
|
|
271
273
|
end
|
|
272
274
|
|
|
273
|
-
# Returns whether this request is using the standard port
|
|
275
|
+
# Returns whether this request is using the standard port.
|
|
274
276
|
#
|
|
275
|
-
#
|
|
276
|
-
#
|
|
277
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
|
278
|
+
# req.standard_port? # => true
|
|
277
279
|
#
|
|
278
|
-
#
|
|
279
|
-
#
|
|
280
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
281
|
+
# req.standard_port? # => false
|
|
280
282
|
def standard_port?
|
|
281
283
|
port == standard_port
|
|
282
284
|
end
|
|
283
285
|
|
|
284
|
-
# Returns a number
|
|
285
|
-
#
|
|
286
|
+
# Returns a number port suffix like 8080 if the port number of this request is
|
|
287
|
+
# not the default HTTP port 80 or HTTPS port 443.
|
|
286
288
|
#
|
|
287
|
-
#
|
|
288
|
-
#
|
|
289
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
|
290
|
+
# req.optional_port # => nil
|
|
289
291
|
#
|
|
290
|
-
#
|
|
291
|
-
#
|
|
292
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
293
|
+
# req.optional_port # => 8080
|
|
292
294
|
def optional_port
|
|
293
295
|
standard_port? ? nil : port
|
|
294
296
|
end
|
|
295
297
|
|
|
296
|
-
# Returns a string
|
|
297
|
-
#
|
|
298
|
+
# Returns a string port suffix, including colon, like ":8080" if the port number
|
|
299
|
+
# of this request is not the default HTTP port 80 or HTTPS port 443.
|
|
298
300
|
#
|
|
299
|
-
#
|
|
300
|
-
#
|
|
301
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:80'
|
|
302
|
+
# req.port_string # => ""
|
|
301
303
|
#
|
|
302
|
-
#
|
|
303
|
-
#
|
|
304
|
+
# req = ActionDispatch::Request.new 'HTTP_HOST' => 'example.com:8080'
|
|
305
|
+
# req.port_string # => ":8080"
|
|
304
306
|
def port_string
|
|
305
307
|
standard_port? ? "" : ":#{port}"
|
|
306
308
|
end
|
|
307
309
|
|
|
308
|
-
# Returns the requested port, such as 8080, based on SERVER_PORT
|
|
310
|
+
# Returns the requested port, such as 8080, based on SERVER_PORT.
|
|
309
311
|
#
|
|
310
|
-
#
|
|
311
|
-
#
|
|
312
|
+
# req = ActionDispatch::Request.new 'SERVER_PORT' => '80'
|
|
313
|
+
# req.server_port # => 80
|
|
312
314
|
#
|
|
313
|
-
#
|
|
314
|
-
#
|
|
315
|
+
# req = ActionDispatch::Request.new 'SERVER_PORT' => '8080'
|
|
316
|
+
# req.server_port # => 8080
|
|
315
317
|
def server_port
|
|
316
318
|
get_header("SERVER_PORT").to_i
|
|
317
319
|
end
|
|
318
320
|
|
|
319
|
-
# Returns the
|
|
320
|
-
# a different
|
|
321
|
+
# Returns the domain part of a host, such as "rubyonrails.org" in
|
|
322
|
+
# "www.rubyonrails.org". You can specify a different `tld_length`, such as 2 to
|
|
323
|
+
# catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
|
|
321
324
|
def domain(tld_length = @@tld_length)
|
|
322
325
|
ActionDispatch::Http::URL.extract_domain(host, tld_length)
|
|
323
326
|
end
|
|
324
327
|
|
|
325
|
-
# Returns all the
|
|
326
|
-
#
|
|
327
|
-
#
|
|
328
|
-
#
|
|
328
|
+
# Returns all the subdomains as an array, so `["dev", "www"]` would be returned
|
|
329
|
+
# for "dev.www.rubyonrails.org". You can specify a different `tld_length`, such
|
|
330
|
+
# as 2 to catch `["www"]` instead of `["www", "rubyonrails"]` in
|
|
331
|
+
# "www.rubyonrails.co.uk".
|
|
329
332
|
def subdomains(tld_length = @@tld_length)
|
|
330
333
|
ActionDispatch::Http::URL.extract_subdomains(host, tld_length)
|
|
331
334
|
end
|
|
332
335
|
|
|
333
|
-
# Returns all the
|
|
334
|
-
#
|
|
335
|
-
#
|
|
336
|
-
# in "www.rubyonrails.co.uk".
|
|
336
|
+
# Returns all the subdomains as a string, so `"dev.www"` would be returned for
|
|
337
|
+
# "dev.www.rubyonrails.org". You can specify a different `tld_length`, such as 2
|
|
338
|
+
# to catch `"www"` instead of `"www.rubyonrails"` in "www.rubyonrails.co.uk".
|
|
337
339
|
def subdomain(tld_length = @@tld_length)
|
|
338
340
|
ActionDispatch::Http::URL.extract_subdomain(host, tld_length)
|
|
339
341
|
end
|