actionpack 4.2.10 → 7.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +86 -600
- data/MIT-LICENSE +1 -1
- data/README.rdoc +13 -14
- data/lib/abstract_controller/asset_paths.rb +5 -1
- data/lib/abstract_controller/base.rb +166 -136
- data/lib/abstract_controller/caching/fragments.rb +149 -0
- data/lib/abstract_controller/caching.rb +68 -0
- data/lib/abstract_controller/callbacks.rb +126 -57
- data/lib/abstract_controller/collector.rb +13 -15
- data/lib/abstract_controller/deprecator.rb +9 -0
- data/lib/abstract_controller/error.rb +8 -0
- data/lib/abstract_controller/helpers.rb +181 -132
- data/lib/abstract_controller/logger.rb +5 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +10 -3
- data/lib/abstract_controller/rendering.rb +56 -56
- data/lib/abstract_controller/translation.rb +29 -15
- data/lib/abstract_controller/url_for.rb +15 -11
- data/lib/abstract_controller.rb +21 -5
- data/lib/action_controller/api/api_rendering.rb +18 -0
- data/lib/action_controller/api.rb +154 -0
- data/lib/action_controller/base.rb +219 -155
- data/lib/action_controller/caching.rb +28 -68
- data/lib/action_controller/deprecator.rb +9 -0
- data/lib/action_controller/form_builder.rb +55 -0
- data/lib/action_controller/log_subscriber.rb +35 -22
- data/lib/action_controller/metal/allow_browser.rb +119 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
- data/lib/action_controller/metal/conditional_get.rb +259 -122
- data/lib/action_controller/metal/content_security_policy.rb +86 -0
- data/lib/action_controller/metal/cookies.rb +9 -5
- data/lib/action_controller/metal/data_streaming.rb +87 -104
- data/lib/action_controller/metal/default_headers.rb +21 -0
- data/lib/action_controller/metal/etag_with_flash.rb +22 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +35 -26
- data/lib/action_controller/metal/exceptions.rb +71 -24
- data/lib/action_controller/metal/flash.rb +26 -19
- data/lib/action_controller/metal/head.rb +45 -36
- data/lib/action_controller/metal/helpers.rb +80 -64
- data/lib/action_controller/metal/http_authentication.rb +297 -244
- data/lib/action_controller/metal/implicit_render.rb +57 -9
- data/lib/action_controller/metal/instrumentation.rb +76 -64
- data/lib/action_controller/metal/live.rb +238 -176
- data/lib/action_controller/metal/logging.rb +22 -0
- data/lib/action_controller/metal/mime_responds.rb +177 -166
- data/lib/action_controller/metal/parameter_encoding.rb +84 -0
- data/lib/action_controller/metal/params_wrapper.rb +145 -118
- data/lib/action_controller/metal/permissions_policy.rb +38 -0
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +203 -64
- data/lib/action_controller/metal/renderers.rb +108 -65
- data/lib/action_controller/metal/rendering.rb +216 -56
- data/lib/action_controller/metal/request_forgery_protection.rb +496 -163
- data/lib/action_controller/metal/rescue.rb +19 -21
- data/lib/action_controller/metal/streaming.rb +179 -138
- data/lib/action_controller/metal/strong_parameters.rb +1058 -382
- data/lib/action_controller/metal/testing.rb +11 -17
- data/lib/action_controller/metal/url_for.rb +37 -21
- data/lib/action_controller/metal.rb +236 -138
- data/lib/action_controller/railtie.rb +89 -11
- data/lib/action_controller/railties/helpers.rb +5 -1
- data/lib/action_controller/renderer.rb +161 -0
- data/lib/action_controller/template_assertions.rb +13 -0
- data/lib/action_controller/test_case.rb +425 -497
- data/lib/action_controller.rb +44 -22
- data/lib/action_dispatch/constants.rb +34 -0
- data/lib/action_dispatch/deprecator.rb +9 -0
- data/lib/action_dispatch/http/cache.rb +119 -63
- data/lib/action_dispatch/http/content_disposition.rb +47 -0
- data/lib/action_dispatch/http/content_security_policy.rb +364 -0
- data/lib/action_dispatch/http/filter_parameters.rb +36 -34
- data/lib/action_dispatch/http/filter_redirect.rb +24 -12
- data/lib/action_dispatch/http/headers.rb +66 -31
- data/lib/action_dispatch/http/mime_negotiation.rb +106 -75
- data/lib/action_dispatch/http/mime_type.rb +196 -136
- data/lib/action_dispatch/http/mime_types.rb +25 -7
- data/lib/action_dispatch/http/parameters.rb +97 -45
- data/lib/action_dispatch/http/permissions_policy.rb +187 -0
- data/lib/action_dispatch/http/rack_cache.rb +6 -0
- data/lib/action_dispatch/http/request.rb +299 -170
- data/lib/action_dispatch/http/response.rb +311 -160
- data/lib/action_dispatch/http/upload.rb +52 -23
- data/lib/action_dispatch/http/url.rb +201 -125
- data/lib/action_dispatch/journey/formatter.rb +110 -50
- data/lib/action_dispatch/journey/gtg/builder.rb +37 -50
- data/lib/action_dispatch/journey/gtg/simulator.rb +20 -17
- data/lib/action_dispatch/journey/gtg/transition_table.rb +96 -36
- data/lib/action_dispatch/journey/nfa/dot.rb +5 -14
- data/lib/action_dispatch/journey/nodes/node.rb +100 -20
- data/lib/action_dispatch/journey/parser.rb +19 -17
- data/lib/action_dispatch/journey/parser.y +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +14 -4
- data/lib/action_dispatch/journey/path/pattern.rb +79 -63
- data/lib/action_dispatch/journey/route.rb +108 -44
- data/lib/action_dispatch/journey/router/utils.rb +41 -29
- data/lib/action_dispatch/journey/router.rb +64 -57
- data/lib/action_dispatch/journey/routes.rb +23 -21
- data/lib/action_dispatch/journey/scanner.rb +28 -17
- data/lib/action_dispatch/journey/visitors.rb +100 -54
- data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
- data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
- data/lib/action_dispatch/journey.rb +7 -5
- data/lib/action_dispatch/log_subscriber.rb +25 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
- data/lib/action_dispatch/middleware/callbacks.rb +7 -6
- data/lib/action_dispatch/middleware/cookies.rb +471 -328
- data/lib/action_dispatch/middleware/debug_exceptions.rb +149 -66
- data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
- data/lib/action_dispatch/middleware/debug_view.rb +73 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +275 -73
- data/lib/action_dispatch/middleware/executor.rb +32 -0
- data/lib/action_dispatch/middleware/flash.rb +143 -101
- data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +36 -27
- data/lib/action_dispatch/middleware/reloader.rb +10 -92
- data/lib/action_dispatch/middleware/remote_ip.rb +133 -107
- data/lib/action_dispatch/middleware/request_id.rb +29 -15
- data/lib/action_dispatch/middleware/server_timing.rb +78 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +49 -27
- data/lib/action_dispatch/middleware/session/cache_store.rb +33 -16
- data/lib/action_dispatch/middleware/session/cookie_store.rb +86 -80
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +66 -36
- data/lib/action_dispatch/middleware/ssl.rb +134 -36
- data/lib/action_dispatch/middleware/stack.rb +109 -44
- data/lib/action_dispatch/middleware/static.rb +159 -90
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +7 -24
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +139 -15
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +6 -6
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +9 -9
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +7 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +125 -93
- data/lib/action_dispatch/railtie.rb +44 -16
- data/lib/action_dispatch/request/session.rb +159 -69
- data/lib/action_dispatch/request/utils.rb +97 -23
- data/lib/action_dispatch/routing/endpoint.rb +11 -2
- data/lib/action_dispatch/routing/inspector.rb +195 -106
- data/lib/action_dispatch/routing/mapper.rb +1338 -955
- data/lib/action_dispatch/routing/polymorphic_routes.rb +234 -201
- data/lib/action_dispatch/routing/redirection.rb +78 -51
- data/lib/action_dispatch/routing/route_set.rb +460 -374
- data/lib/action_dispatch/routing/routes_proxy.rb +36 -12
- data/lib/action_dispatch/routing/url_for.rb +172 -124
- data/lib/action_dispatch/routing.rb +159 -158
- data/lib/action_dispatch/system_test_case.rb +206 -0
- data/lib/action_dispatch/system_testing/browser.rb +84 -0
- data/lib/action_dispatch/system_testing/driver.rb +85 -0
- data/lib/action_dispatch/system_testing/server.rb +33 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
- data/lib/action_dispatch/testing/assertion_response.rb +48 -0
- data/lib/action_dispatch/testing/assertions/response.rb +71 -39
- data/lib/action_dispatch/testing/assertions/routing.rb +228 -103
- data/lib/action_dispatch/testing/assertions.rb +9 -6
- data/lib/action_dispatch/testing/integration.rb +486 -306
- data/lib/action_dispatch/testing/request_encoder.rb +60 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +35 -22
- data/lib/action_dispatch/testing/test_request.rb +29 -34
- data/lib/action_dispatch/testing/test_response.rb +48 -15
- data/lib/action_dispatch.rb +82 -40
- data/lib/action_pack/gem_version.rb +8 -4
- data/lib/action_pack/version.rb +6 -2
- data/lib/action_pack.rb +21 -18
- metadata +146 -56
- data/lib/action_controller/caching/fragments.rb +0 -103
- data/lib/action_controller/metal/force_ssl.rb +0 -97
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/http/parameter_filter.rb +0 -72
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +0 -27
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,6 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
# :markup: markdown
|
4
|
+
|
5
|
+
require "action_controller/metal/exceptions"
|
6
|
+
require "action_dispatch/http/content_disposition"
|
7
|
+
|
8
|
+
module ActionController # :nodoc:
|
9
|
+
# # Action Controller Data Streaming
|
10
|
+
#
|
4
11
|
# Methods for sending arbitrary data and for streaming files to the browser,
|
5
12
|
# instead of rendering.
|
6
13
|
module DataStreaming
|
@@ -8,132 +15,120 @@ module ActionController #:nodoc:
|
|
8
15
|
|
9
16
|
include ActionController::Rendering
|
10
17
|
|
11
|
-
DEFAULT_SEND_FILE_TYPE =
|
12
|
-
DEFAULT_SEND_FILE_DISPOSITION =
|
18
|
+
DEFAULT_SEND_FILE_TYPE = "application/octet-stream" # :nodoc:
|
19
|
+
DEFAULT_SEND_FILE_DISPOSITION = "attachment" # :nodoc:
|
13
20
|
|
14
|
-
|
15
|
-
# Sends the file. This uses a server-appropriate method (such as X-Sendfile)
|
16
|
-
# via the Rack::Sendfile middleware. The header to use is set via
|
17
|
-
#
|
18
|
-
#
|
21
|
+
private
|
22
|
+
# Sends the file. This uses a server-appropriate method (such as `X-Sendfile`)
|
23
|
+
# via the `Rack::Sendfile` middleware. The header to use is set via
|
24
|
+
# `config.action_dispatch.x_sendfile_header`. Your server can also configure
|
25
|
+
# this for you by setting the `X-Sendfile-Type` header.
|
19
26
|
#
|
20
|
-
# Be careful to sanitize the path parameter if it is coming from a web
|
21
|
-
#
|
22
|
-
#
|
27
|
+
# Be careful to sanitize the path parameter if it is coming from a web page.
|
28
|
+
# `send_file(params[:path])` allows a malicious user to download any file on
|
29
|
+
# your server.
|
23
30
|
#
|
24
31
|
# Options:
|
25
|
-
# *
|
26
|
-
#
|
27
|
-
# *
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
# *
|
33
|
-
#
|
34
|
-
# *
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
32
|
+
# * `:filename` - suggests a filename for the browser to use. Defaults to
|
33
|
+
# `File.basename(path)`.
|
34
|
+
# * `:type` - specifies an HTTP content type. You can specify either a string
|
35
|
+
# or a symbol for a registered type with `Mime::Type.register`, for example
|
36
|
+
# `:json`. If omitted, the type will be inferred from the file extension
|
37
|
+
# specified in `:filename`. If no content type is registered for the
|
38
|
+
# extension, the default type `application/octet-stream` will be used.
|
39
|
+
# * `:disposition` - specifies whether the file will be shown inline or
|
40
|
+
# downloaded. Valid values are `"inline"` and `"attachment"` (default).
|
41
|
+
# * `:status` - specifies the status code to send with the response. Defaults
|
42
|
+
# to 200.
|
43
|
+
# * `:url_based_filename` - set to `true` if you want the browser to guess the
|
44
|
+
# filename from the URL, which is necessary for i18n filenames on certain
|
45
|
+
# browsers (setting `:filename` overrides this option).
|
46
|
+
#
|
47
|
+
#
|
48
|
+
# The default `Content-Type` and `Content-Disposition` headers are set to
|
49
|
+
# download arbitrary binary files in as many browsers as possible. IE versions
|
50
|
+
# 4, 5, 5.5, and 6 are all known to have a variety of quirks (especially when
|
51
|
+
# downloading over SSL).
|
43
52
|
#
|
44
53
|
# Simple download:
|
45
54
|
#
|
46
|
-
#
|
55
|
+
# send_file '/path/to.zip'
|
47
56
|
#
|
48
57
|
# Show a JPEG in the browser:
|
49
58
|
#
|
50
|
-
#
|
59
|
+
# send_file '/path/to.jpeg', type: 'image/jpeg', disposition: 'inline'
|
51
60
|
#
|
52
61
|
# Show a 404 page in the browser:
|
53
62
|
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
# Also be aware that the document may be cached by proxies and browsers.
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
def send_file(path, options = {})
|
68
|
-
raise MissingFile, "Cannot read file #{path}" unless File.file?(path)
|
63
|
+
# send_file '/path/to/404.html', type: 'text/html; charset=utf-8', disposition: 'inline', status: 404
|
64
|
+
#
|
65
|
+
# You can use other `Content-*` HTTP headers to provide additional information
|
66
|
+
# to the client. See MDN for a [list of HTTP
|
67
|
+
# headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).
|
68
|
+
#
|
69
|
+
# Also be aware that the document may be cached by proxies and browsers. The
|
70
|
+
# `Pragma` and `Cache-Control` headers declare how the file may be cached by
|
71
|
+
# intermediaries. They default to require clients to validate with the server
|
72
|
+
# before releasing cached responses. See https://www.mnot.net/cache_docs/ for an
|
73
|
+
# overview of web caching and [RFC
|
74
|
+
# 9111](https://www.rfc-editor.org/rfc/rfc9111.html#name-cache-control) for the
|
75
|
+
# `Cache-Control` header spec.
|
76
|
+
def send_file(path, options = {}) # :doc:
|
77
|
+
raise MissingFile, "Cannot read file #{path}" unless File.file?(path) && File.readable?(path)
|
69
78
|
|
70
79
|
options[:filename] ||= File.basename(path) unless options[:url_based_filename]
|
71
80
|
send_file_headers! options
|
72
81
|
|
73
82
|
self.status = options[:status] || 200
|
74
83
|
self.content_type = options[:content_type] if options.key?(:content_type)
|
75
|
-
|
84
|
+
response.send_file path
|
76
85
|
end
|
77
86
|
|
78
|
-
#
|
79
|
-
#
|
80
|
-
# the
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
def initialize(path)
|
85
|
-
@to_path = path
|
86
|
-
end
|
87
|
-
|
88
|
-
# Stream the file's contents if Rack::Sendfile isn't present.
|
89
|
-
def each
|
90
|
-
File.open(to_path, 'rb') do |file|
|
91
|
-
while chunk = file.read(16384)
|
92
|
-
yield chunk
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Sends the given binary data to the browser. This method is similar to
|
99
|
-
# <tt>render plain: data</tt>, but also allows you to specify whether
|
100
|
-
# the browser should display the response as a file attachment (i.e. in a
|
101
|
-
# download dialog) or as inline data. You may also set the content type,
|
102
|
-
# the apparent file name, and other things.
|
87
|
+
# Sends the given binary data to the browser. This method is similar to `render
|
88
|
+
# plain: data`, but also allows you to specify whether the browser should
|
89
|
+
# display the response as a file attachment (i.e. in a download dialog) or as
|
90
|
+
# inline data. You may also set the content type, the file name, and other
|
91
|
+
# things.
|
103
92
|
#
|
104
93
|
# Options:
|
105
|
-
# *
|
106
|
-
# *
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
# *
|
94
|
+
# * `:filename` - suggests a filename for the browser to use.
|
95
|
+
# * `:type` - specifies an HTTP content type. Defaults to
|
96
|
+
# `application/octet-stream`. You can specify either a string or a symbol
|
97
|
+
# for a registered type with `Mime::Type.register`, for example `:json`. If
|
98
|
+
# omitted, type will be inferred from the file extension specified in
|
99
|
+
# `:filename`. If no content type is registered for the extension, the
|
100
|
+
# default type `application/octet-stream` will be used.
|
101
|
+
# * `:disposition` - specifies whether the file will be shown inline or
|
102
|
+
# downloaded. Valid values are `"inline"` and `"attachment"` (default).
|
103
|
+
# * `:status` - specifies the status code to send with the response. Defaults
|
104
|
+
# to 200.
|
105
|
+
#
|
113
106
|
#
|
114
107
|
# Generic data download:
|
115
108
|
#
|
116
|
-
#
|
109
|
+
# send_data buffer
|
117
110
|
#
|
118
111
|
# Download a dynamically-generated tarball:
|
119
112
|
#
|
120
|
-
#
|
113
|
+
# send_data generate_tgz('dir'), filename: 'dir.tgz'
|
121
114
|
#
|
122
115
|
# Display an image Active Record in the browser:
|
123
116
|
#
|
124
|
-
#
|
117
|
+
# send_data image.data, type: image.content_type, disposition: 'inline'
|
125
118
|
#
|
126
|
-
# See
|
127
|
-
def send_data(data, options = {})
|
119
|
+
# See `send_file` for more information on HTTP `Content-*` headers and caching.
|
120
|
+
def send_data(data, options = {}) # :doc:
|
128
121
|
send_file_headers! options
|
129
|
-
render options.slice(:status, :content_type).merge(:
|
122
|
+
render options.slice(:status, :content_type).merge(body: data)
|
130
123
|
end
|
131
124
|
|
132
|
-
private
|
133
125
|
def send_file_headers!(options)
|
134
126
|
type_provided = options.has_key?(:type)
|
135
127
|
|
136
128
|
content_type = options.fetch(:type, DEFAULT_SEND_FILE_TYPE)
|
129
|
+
self.content_type = content_type
|
130
|
+
response.sending_file = true
|
131
|
+
|
137
132
|
raise ArgumentError, ":type option required" if content_type.nil?
|
138
133
|
|
139
134
|
if content_type.is_a?(Symbol)
|
@@ -143,29 +138,17 @@ module ActionController #:nodoc:
|
|
143
138
|
else
|
144
139
|
if !type_provided && options[:filename]
|
145
140
|
# If type wasn't provided, try guessing from file extension.
|
146
|
-
content_type = Mime::Type.lookup_by_extension(File.extname(options[:filename]).downcase.delete(
|
141
|
+
content_type = Mime::Type.lookup_by_extension(File.extname(options[:filename]).downcase.delete(".")) || content_type
|
147
142
|
end
|
148
143
|
self.content_type = content_type
|
149
144
|
end
|
150
145
|
|
151
146
|
disposition = options.fetch(:disposition, DEFAULT_SEND_FILE_DISPOSITION)
|
152
|
-
|
153
|
-
|
154
|
-
disposition += %(; filename="#{options[:filename]}") if options[:filename]
|
155
|
-
headers['Content-Disposition'] = disposition
|
147
|
+
if disposition
|
148
|
+
headers["Content-Disposition"] = ActionDispatch::Http::ContentDisposition.format(disposition: disposition, filename: options[:filename])
|
156
149
|
end
|
157
150
|
|
158
|
-
headers[
|
159
|
-
|
160
|
-
response.sending_file = true
|
161
|
-
|
162
|
-
# Fix a problem with IE 6.0 on opening downloaded files:
|
163
|
-
# If Cache-Control: no-cache is set (which Rails does by default),
|
164
|
-
# IE removes the file it just downloaded from its cache immediately
|
165
|
-
# after it displays the "open/save" dialog, which means that if you
|
166
|
-
# hit "open" the file isn't there anymore when the application that
|
167
|
-
# is called for handling the download is run, so let's workaround that
|
168
|
-
response.cache_control[:public] ||= false
|
151
|
+
headers["Content-Transfer-Encoding"] = "binary"
|
169
152
|
end
|
170
153
|
end
|
171
154
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
5
|
+
module ActionController
|
6
|
+
# # Action Controller Default Headers
|
7
|
+
#
|
8
|
+
# Allows configuring default headers that will be automatically merged into each
|
9
|
+
# response.
|
10
|
+
module DefaultHeaders
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def make_response!(request)
|
15
|
+
ActionDispatch::Response.create.tap do |res|
|
16
|
+
res.request = request
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
5
|
+
module ActionController
|
6
|
+
# # Action Controller Etag With Flash
|
7
|
+
#
|
8
|
+
# When you're using the flash, it's generally used as a conditional on the view.
|
9
|
+
# This means the content of the view depends on the flash. Which in turn means
|
10
|
+
# that the ETag for a response should be computed with the content of the flash
|
11
|
+
# in mind. This does that by including the content of the flash as a component
|
12
|
+
# in the ETag that's generated for a response.
|
13
|
+
module EtagWithFlash
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
|
16
|
+
include ActionController::ConditionalGet
|
17
|
+
|
18
|
+
included do
|
19
|
+
etag { flash if request.respond_to?(:flash) && !flash.empty? }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,20 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
1
5
|
module ActionController
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
6
|
+
# # Action Controller Etag With Template Digest
|
7
|
+
#
|
8
|
+
# When our views change, they should bubble up into HTTP cache freshness and
|
9
|
+
# bust browser caches. So the template digest for the current action is
|
10
|
+
# automatically included in the ETag.
|
5
11
|
#
|
6
12
|
# Enabled by default for apps that use Action View. Disable by setting
|
7
13
|
#
|
8
|
-
#
|
14
|
+
# config.action_controller.etag_with_template_digest = false
|
9
15
|
#
|
10
|
-
# Override the template to digest by passing
|
11
|
-
#
|
16
|
+
# Override the template to digest by passing `:template` to `fresh_when` and
|
17
|
+
# `stale?` calls. For example:
|
12
18
|
#
|
13
|
-
#
|
14
|
-
#
|
19
|
+
# # We're going to render widgets/show, not posts/show
|
20
|
+
# fresh_when @post, template: 'widgets/show'
|
15
21
|
#
|
16
|
-
#
|
17
|
-
#
|
22
|
+
# # We're not going to render a template, so omit it from the ETag.
|
23
|
+
# fresh_when @post, template: false
|
18
24
|
#
|
19
25
|
module EtagWithTemplateDigest
|
20
26
|
extend ActiveSupport::Concern
|
@@ -22,29 +28,32 @@ module ActionController
|
|
22
28
|
include ActionController::ConditionalGet
|
23
29
|
|
24
30
|
included do
|
25
|
-
class_attribute :etag_with_template_digest
|
26
|
-
self.etag_with_template_digest = true
|
31
|
+
class_attribute :etag_with_template_digest, default: true
|
27
32
|
|
28
|
-
|
29
|
-
|
30
|
-
determine_template_etag(options) if etag_with_template_digest
|
31
|
-
end
|
33
|
+
etag do |options|
|
34
|
+
determine_template_etag(options) if etag_with_template_digest
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
35
38
|
private
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
+
def determine_template_etag(options)
|
40
|
+
if template = pick_template_for_etag(options)
|
41
|
+
lookup_and_digest_template(template)
|
42
|
+
end
|
39
43
|
end
|
40
|
-
end
|
41
44
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
+
# Pick the template digest to include in the ETag. If the `:template` option is
|
46
|
+
# present, use the named template. If `:template` is `nil` or absent, use the
|
47
|
+
# default controller/action template. If `:template` is false, omit the template
|
48
|
+
# digest from the ETag.
|
49
|
+
def pick_template_for_etag(options)
|
50
|
+
unless options[:template] == false
|
51
|
+
options[:template] || lookup_context.find_all(action_name, _prefixes).first&.virtual_path
|
52
|
+
end
|
53
|
+
end
|
45
54
|
|
46
|
-
|
47
|
-
|
48
|
-
|
55
|
+
def lookup_and_digest_template(template)
|
56
|
+
ActionView::Digestor.digest name: template, format: nil, finder: lookup_context
|
57
|
+
end
|
49
58
|
end
|
50
59
|
end
|
@@ -1,59 +1,106 @@
|
|
1
|
-
|
2
|
-
class ActionControllerError < StandardError #:nodoc:
|
3
|
-
end
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
attr_reader :original_exception
|
3
|
+
# :markup: markdown
|
7
4
|
|
8
|
-
|
9
|
-
|
5
|
+
module ActionController
|
6
|
+
class ActionControllerError < StandardError # :nodoc:
|
7
|
+
end
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
class BadRequest < ActionControllerError # :nodoc:
|
10
|
+
def initialize(msg = nil)
|
11
|
+
super(msg)
|
12
|
+
set_backtrace $!.backtrace if $!
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
17
|
-
class RenderError < ActionControllerError
|
16
|
+
class RenderError < ActionControllerError # :nodoc:
|
18
17
|
end
|
19
18
|
|
20
|
-
class RoutingError < ActionControllerError
|
19
|
+
class RoutingError < ActionControllerError # :nodoc:
|
21
20
|
attr_reader :failures
|
22
|
-
def initialize(message, failures=[])
|
21
|
+
def initialize(message, failures = [])
|
23
22
|
super(message)
|
24
23
|
@failures = failures
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
28
|
-
class
|
27
|
+
class UrlGenerationError < ActionControllerError # :nodoc:
|
28
|
+
attr_reader :routes, :route_name, :method_name
|
29
|
+
|
30
|
+
def initialize(message, routes = nil, route_name = nil, method_name = nil)
|
31
|
+
@routes = routes
|
32
|
+
@route_name = route_name
|
33
|
+
@method_name = method_name
|
34
|
+
|
35
|
+
super(message)
|
36
|
+
end
|
37
|
+
|
38
|
+
if defined?(DidYouMean::Correctable) && defined?(DidYouMean::SpellChecker)
|
39
|
+
include DidYouMean::Correctable
|
40
|
+
|
41
|
+
def corrections
|
42
|
+
@corrections ||= begin
|
43
|
+
maybe_these = routes&.named_routes&.helper_names&.grep(/#{route_name}/) || []
|
44
|
+
maybe_these -= [method_name.to_s] # remove exact match
|
45
|
+
|
46
|
+
DidYouMean::SpellChecker.new(dictionary: maybe_these).correct(route_name)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
29
50
|
end
|
30
51
|
|
31
|
-
class MethodNotAllowed < ActionControllerError
|
52
|
+
class MethodNotAllowed < ActionControllerError # :nodoc:
|
32
53
|
def initialize(*allowed_methods)
|
33
|
-
super("Only #{allowed_methods.to_sentence
|
54
|
+
super("Only #{allowed_methods.to_sentence} requests are allowed.")
|
34
55
|
end
|
35
56
|
end
|
36
57
|
|
37
|
-
class NotImplemented < MethodNotAllowed
|
58
|
+
class NotImplemented < MethodNotAllowed # :nodoc:
|
38
59
|
end
|
39
60
|
|
40
|
-
class
|
61
|
+
class MissingFile < ActionControllerError # :nodoc:
|
41
62
|
end
|
42
63
|
|
43
|
-
class
|
64
|
+
class SessionOverflowError < ActionControllerError # :nodoc:
|
65
|
+
DEFAULT_MESSAGE = "Your session data is larger than the data column in which it is to be stored. You must increase the size of your data column if you intend to store large data."
|
66
|
+
|
67
|
+
def initialize(message = nil)
|
68
|
+
super(message || DEFAULT_MESSAGE)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class UnknownHttpMethod < ActionControllerError # :nodoc:
|
44
73
|
end
|
45
74
|
|
46
|
-
class
|
47
|
-
|
75
|
+
class UnknownFormat < ActionControllerError # :nodoc:
|
76
|
+
end
|
77
|
+
|
78
|
+
# Raised when a nested respond_to is triggered and the content types of each are
|
79
|
+
# incompatible. For example:
|
80
|
+
#
|
81
|
+
# respond_to do |outer_type|
|
82
|
+
# outer_type.js do
|
83
|
+
# respond_to do |inner_type|
|
84
|
+
# inner_type.html { render body: "HTML" }
|
85
|
+
# end
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
class RespondToMismatchError < ActionControllerError
|
89
|
+
DEFAULT_MESSAGE = "respond_to was called multiple times and matched with conflicting formats in this action. Please note that you may only call respond_to and match on a single format per action."
|
48
90
|
|
49
91
|
def initialize(message = nil)
|
50
92
|
super(message || DEFAULT_MESSAGE)
|
51
93
|
end
|
52
94
|
end
|
53
95
|
|
54
|
-
class
|
55
|
-
|
96
|
+
class MissingExactTemplate < UnknownFormat # :nodoc:
|
97
|
+
attr_reader :controller, :action_name
|
56
98
|
|
57
|
-
|
99
|
+
def initialize(message, controller, action_name)
|
100
|
+
@controller = controller
|
101
|
+
@action_name = action_name
|
102
|
+
|
103
|
+
super(message)
|
104
|
+
end
|
58
105
|
end
|
59
106
|
end
|
@@ -1,10 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
5
|
+
module ActionController # :nodoc:
|
2
6
|
module Flash
|
3
7
|
extend ActiveSupport::Concern
|
4
8
|
|
5
9
|
included do
|
6
|
-
class_attribute :_flash_types, instance_accessor: false
|
7
|
-
self._flash_types = []
|
10
|
+
class_attribute :_flash_types, instance_accessor: false, default: []
|
8
11
|
|
9
12
|
delegate :flash, to: :request
|
10
13
|
add_flash_types(:alert, :notice)
|
@@ -12,19 +15,19 @@ module ActionController #:nodoc:
|
|
12
15
|
|
13
16
|
module ClassMethods
|
14
17
|
# Creates new flash types. You can pass as many types as you want to create
|
15
|
-
# flash types other than the default
|
16
|
-
#
|
18
|
+
# flash types other than the default `alert` and `notice` in your controllers
|
19
|
+
# and views. For instance:
|
17
20
|
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
21
|
+
# # in application_controller.rb
|
22
|
+
# class ApplicationController < ActionController::Base
|
23
|
+
# add_flash_types :warning
|
24
|
+
# end
|
22
25
|
#
|
23
|
-
#
|
24
|
-
#
|
26
|
+
# # in your controller
|
27
|
+
# redirect_to user_path(@user), warning: "Incomplete profile"
|
25
28
|
#
|
26
|
-
#
|
27
|
-
#
|
29
|
+
# # in your view
|
30
|
+
# <%= warning %>
|
28
31
|
#
|
29
32
|
# This method will automatically define a new method for each of the given
|
30
33
|
# names, and it will be available in your views.
|
@@ -35,26 +38,30 @@ module ActionController #:nodoc:
|
|
35
38
|
define_method(type) do
|
36
39
|
request.flash[type]
|
37
40
|
end
|
38
|
-
helper_method
|
41
|
+
helper_method(type) if respond_to?(:helper_method)
|
39
42
|
|
40
43
|
self._flash_types += [type]
|
41
44
|
end
|
42
45
|
end
|
46
|
+
|
47
|
+
def action_methods # :nodoc:
|
48
|
+
@action_methods ||= super - _flash_types.map(&:to_s).to_set
|
49
|
+
end
|
43
50
|
end
|
44
51
|
|
45
|
-
|
46
|
-
def redirect_to(options = {},
|
52
|
+
private
|
53
|
+
def redirect_to(options = {}, response_options_and_flash = {}) # :doc:
|
47
54
|
self.class._flash_types.each do |flash_type|
|
48
|
-
if type =
|
55
|
+
if type = response_options_and_flash.delete(flash_type)
|
49
56
|
flash[flash_type] = type
|
50
57
|
end
|
51
58
|
end
|
52
59
|
|
53
|
-
if other_flashes =
|
60
|
+
if other_flashes = response_options_and_flash.delete(:flash)
|
54
61
|
flash.update(other_flashes)
|
55
62
|
end
|
56
63
|
|
57
|
-
super(options,
|
64
|
+
super(options, response_options_and_flash)
|
58
65
|
end
|
59
66
|
end
|
60
67
|
end
|