actionpack 7.1.5.1 → 8.1.2
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 +308 -523
- data/README.rdoc +1 -1
- data/lib/abstract_controller/asset_paths.rb +6 -2
- data/lib/abstract_controller/base.rb +104 -105
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +8 -3
- data/lib/abstract_controller/callbacks.rb +70 -62
- 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 +4 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -13
- data/lib/abstract_controller/translation.rb +12 -13
- 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 +76 -72
- data/lib/action_controller/base.rb +199 -126
- data/lib/action_controller/caching.rb +16 -14
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +21 -18
- data/lib/action_controller/log_subscriber.rb +23 -2
- data/lib/action_controller/metal/allow_browser.rb +133 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +217 -175
- 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 +72 -63
- 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 +16 -9
- data/lib/action_controller/metal/flash.rb +13 -14
- data/lib/action_controller/metal/head.rb +15 -11
- data/lib/action_controller/metal/helpers.rb +63 -55
- data/lib/action_controller/metal/http_authentication.rb +209 -201
- data/lib/action_controller/metal/implicit_render.rb +17 -15
- data/lib/action_controller/metal/instrumentation.rb +16 -14
- data/lib/action_controller/metal/live.rb +177 -128
- 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 +22 -12
- data/lib/action_controller/metal/rate_limiting.rb +92 -0
- data/lib/action_controller/metal/redirecting.rb +213 -94
- data/lib/action_controller/metal/renderers.rb +78 -57
- data/lib/action_controller/metal/rendering.rb +111 -77
- data/lib/action_controller/metal/request_forgery_protection.rb +182 -143
- data/lib/action_controller/metal/rescue.rb +20 -9
- data/lib/action_controller/metal/streaming.rb +118 -195
- data/lib/action_controller/metal/strong_parameters.rb +720 -530
- 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 +36 -15
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +41 -36
- data/lib/action_controller/structured_event_subscriber.rb +116 -0
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +160 -131
- data/lib/action_controller.rb +5 -1
- data/lib/action_dispatch/constants.rb +8 -0
- data/lib/action_dispatch/deprecator.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +163 -35
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +54 -39
- data/lib/action_dispatch/http/filter_parameters.rb +14 -8
- 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 +89 -41
- data/lib/action_dispatch/http/mime_type.rb +25 -21
- data/lib/action_dispatch/http/mime_types.rb +3 -0
- data/lib/action_dispatch/http/param_builder.rb +187 -0
- data/lib/action_dispatch/http/param_error.rb +26 -0
- data/lib/action_dispatch/http/parameters.rb +14 -12
- data/lib/action_dispatch/http/permissions_policy.rb +25 -36
- data/lib/action_dispatch/http/query_parser.rb +55 -0
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +141 -92
- data/lib/action_dispatch/http/response.rb +137 -77
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +187 -89
- 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 +34 -11
- data/lib/action_dispatch/journey/gtg/transition_table.rb +47 -53
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +8 -6
- data/lib/action_dispatch/journey/parser.rb +99 -195
- data/lib/action_dispatch/journey/path/pattern.rb +4 -1
- data/lib/action_dispatch/journey/route.rb +54 -38
- data/lib/action_dispatch/journey/router/utils.rb +22 -27
- data/lib/action_dispatch/journey/router.rb +63 -83
- data/lib/action_dispatch/journey/routes.rb +11 -2
- data/lib/action_dispatch/journey/scanner.rb +46 -42
- data/lib/action_dispatch/journey/visitors.rb +57 -23
- data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +7 -1
- 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 +125 -106
- data/lib/action_dispatch/middleware/debug_exceptions.rb +37 -8
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +13 -5
- data/lib/action_dispatch/middleware/exception_wrapper.rb +18 -23
- data/lib/action_dispatch/middleware/executor.rb +19 -4
- 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 +14 -12
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +87 -77
- data/lib/action_dispatch/middleware/request_id.rb +16 -10
- 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 +30 -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 +16 -16
- data/lib/action_dispatch/middleware/ssl.rb +53 -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/_copy_button.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +23 -3
- data/lib/action_dispatch/request/session.rb +24 -21
- data/lib/action_dispatch/request/utils.rb +11 -3
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +85 -60
- data/lib/action_dispatch/routing/mapper.rb +1031 -851
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +47 -39
- data/lib/action_dispatch/routing/route_set.rb +79 -56
- data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +16 -23
- data/lib/action_dispatch/system_testing/driver.rb +2 -0
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +34 -23
- 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 +52 -25
- data/lib/action_dispatch/testing/assertions/routing.rb +168 -87
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +233 -223
- 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 +36 -32
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +36 -32
- data/lib/action_dispatch/journey/parser.y +0 -50
- data/lib/action_dispatch/journey/parser_extras.rb +0 -31
|
@@ -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
|
|
@@ -16,23 +18,9 @@ module ActionDispatch
|
|
|
16
18
|
|
|
17
19
|
included do
|
|
18
20
|
mattr_accessor :ignore_accept_header, default: false
|
|
19
|
-
|
|
20
|
-
def return_only_media_type_on_content_type=(value)
|
|
21
|
-
ActionDispatch.deprecator.warn(
|
|
22
|
-
"`config.action_dispatch.return_only_request_media_type_on_content_type` is deprecated and will" \
|
|
23
|
-
" be removed in Rails 7.2."
|
|
24
|
-
)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def return_only_media_type_on_content_type
|
|
28
|
-
ActionDispatch.deprecator.warn(
|
|
29
|
-
"`config.action_dispatch.return_only_request_media_type_on_content_type` is deprecated and will" \
|
|
30
|
-
" be removed in Rails 7.2."
|
|
31
|
-
)
|
|
32
|
-
end
|
|
33
21
|
end
|
|
34
22
|
|
|
35
|
-
# The MIME type of the HTTP request, such as Mime
|
|
23
|
+
# The MIME type of the HTTP request, such as [Mime](:xml).
|
|
36
24
|
def content_mime_type
|
|
37
25
|
fetch_header("action_dispatch.request.content_type") do |k|
|
|
38
26
|
v = if get_header("CONTENT_TYPE") =~ /^([^,;]*)/
|
|
@@ -66,11 +54,16 @@ module ActionDispatch
|
|
|
66
54
|
end
|
|
67
55
|
end
|
|
68
56
|
|
|
69
|
-
# Returns the MIME type for the
|
|
57
|
+
# Returns the MIME type for the format used in the request.
|
|
58
|
+
#
|
|
59
|
+
# # GET /posts/5.xml
|
|
60
|
+
# request.format # => Mime[:xml]
|
|
70
61
|
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
62
|
+
# # GET /posts/5.xhtml
|
|
63
|
+
# request.format # => Mime[:html]
|
|
64
|
+
#
|
|
65
|
+
# # GET /posts/5
|
|
66
|
+
# request.format # => Mime[:html] or Mime[:js], or request.accepts.first
|
|
74
67
|
#
|
|
75
68
|
def format(_view_path = nil)
|
|
76
69
|
formats.first || Mime::NullType.instance
|
|
@@ -98,7 +91,49 @@ module ActionDispatch
|
|
|
98
91
|
end
|
|
99
92
|
end
|
|
100
93
|
|
|
101
|
-
# Sets the \variant for template.
|
|
94
|
+
# Sets the \variant for the response template.
|
|
95
|
+
#
|
|
96
|
+
# When determining which template to render, Action View will incorporate
|
|
97
|
+
# all variants from the request. For example, if an
|
|
98
|
+
# `ArticlesController#index` action needs to respond to
|
|
99
|
+
# `request.variant = [:ios, :turbo_native]`, it will render the
|
|
100
|
+
# first template file it can find in the following list:
|
|
101
|
+
#
|
|
102
|
+
# - `app/views/articles/index.html+ios.erb`
|
|
103
|
+
# - `app/views/articles/index.html+turbo_native.erb`
|
|
104
|
+
# - `app/views/articles/index.html.erb`
|
|
105
|
+
#
|
|
106
|
+
# Variants add context to the requests that views render appropriately.
|
|
107
|
+
# Variant names are arbitrary, and can communicate anything from the
|
|
108
|
+
# request's platform (`:android`, `:ios`, `:linux`, `:macos`, `:windows`)
|
|
109
|
+
# to its browser (`:chrome`, `:edge`, `:firefox`, `:safari`), to the type
|
|
110
|
+
# of user (`:admin`, `:guest`, `:user`).
|
|
111
|
+
#
|
|
112
|
+
# Note: Adding many new variant templates with similarities to existing
|
|
113
|
+
# template files can make maintaining your view code more difficult.
|
|
114
|
+
#
|
|
115
|
+
# #### Parameters
|
|
116
|
+
#
|
|
117
|
+
# * `variant` - a symbol name or an array of symbol names for variants
|
|
118
|
+
# used to render the response template
|
|
119
|
+
#
|
|
120
|
+
# #### Examples
|
|
121
|
+
#
|
|
122
|
+
# class ApplicationController < ActionController::Base
|
|
123
|
+
# before_action :determine_variants
|
|
124
|
+
#
|
|
125
|
+
# private
|
|
126
|
+
# def determine_variants
|
|
127
|
+
# variants = []
|
|
128
|
+
#
|
|
129
|
+
# # some code to determine the variant(s) to use
|
|
130
|
+
#
|
|
131
|
+
# variants << :ios if request.user_agent.include?("iOS")
|
|
132
|
+
# variants << :turbo_native if request.user_agent.include?("Turbo Native")
|
|
133
|
+
#
|
|
134
|
+
# request.variant = variants
|
|
135
|
+
# end
|
|
136
|
+
# end
|
|
102
137
|
def variant=(variant)
|
|
103
138
|
variant = Array(variant)
|
|
104
139
|
|
|
@@ -109,40 +144,53 @@ module ActionDispatch
|
|
|
109
144
|
end
|
|
110
145
|
end
|
|
111
146
|
|
|
147
|
+
# Returns the \variant for the response template as an instance of
|
|
148
|
+
# ActiveSupport::ArrayInquirer.
|
|
149
|
+
#
|
|
150
|
+
# request.variant = :phone
|
|
151
|
+
# request.variant.phone? # => true
|
|
152
|
+
# request.variant.tablet? # => false
|
|
153
|
+
#
|
|
154
|
+
# request.variant = [:phone, :tablet]
|
|
155
|
+
# request.variant.phone? # => true
|
|
156
|
+
# request.variant.desktop? # => false
|
|
157
|
+
# request.variant.any?(:phone, :desktop) # => true
|
|
158
|
+
# request.variant.any?(:desktop, :watch) # => false
|
|
112
159
|
def variant
|
|
113
160
|
@variant ||= ActiveSupport::ArrayInquirer.new
|
|
114
161
|
end
|
|
115
162
|
|
|
116
|
-
# Sets the
|
|
163
|
+
# Sets the format by string extension, which can be used to force custom formats
|
|
117
164
|
# that are not controlled by the extension.
|
|
118
165
|
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
166
|
+
# class ApplicationController < ActionController::Base
|
|
167
|
+
# before_action :adjust_format_for_iphone
|
|
121
168
|
#
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
#
|
|
169
|
+
# private
|
|
170
|
+
# def adjust_format_for_iphone
|
|
171
|
+
# request.format = :iphone if request.env["HTTP_USER_AGENT"][/iPhone/]
|
|
172
|
+
# end
|
|
173
|
+
# end
|
|
127
174
|
def format=(extension)
|
|
128
175
|
parameters[:format] = extension.to_s
|
|
129
176
|
set_header "action_dispatch.request.formats", [Mime::Type.lookup_by_extension(parameters[:format])]
|
|
130
177
|
end
|
|
131
178
|
|
|
132
|
-
# Sets the
|
|
133
|
-
# to set multiple, ordered formats, which is useful when you want to have a
|
|
179
|
+
# Sets the formats by string extensions. This differs from #format= by allowing
|
|
180
|
+
# you to set multiple, ordered formats, which is useful when you want to have a
|
|
181
|
+
# fallback.
|
|
134
182
|
#
|
|
135
|
-
# In this example, the
|
|
136
|
-
# to the
|
|
183
|
+
# In this example, the `:iphone` format will be used if it's available,
|
|
184
|
+
# otherwise it'll fall back to the `:html` format.
|
|
137
185
|
#
|
|
138
|
-
#
|
|
139
|
-
#
|
|
186
|
+
# class ApplicationController < ActionController::Base
|
|
187
|
+
# before_action :adjust_format_for_iphone_with_html_fallback
|
|
140
188
|
#
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
189
|
+
# private
|
|
190
|
+
# def adjust_format_for_iphone_with_html_fallback
|
|
191
|
+
# request.formats = [ :iphone, :html ] if request.env["HTTP_USER_AGENT"][/iPhone/]
|
|
192
|
+
# end
|
|
193
|
+
# end
|
|
146
194
|
def formats=(extensions)
|
|
147
195
|
parameters[:format] = extensions.first.to_s
|
|
148
196
|
set_header "action_dispatch.request.formats", extensions.collect { |extension|
|
|
@@ -168,8 +216,8 @@ module ActionDispatch
|
|
|
168
216
|
end
|
|
169
217
|
|
|
170
218
|
private
|
|
171
|
-
# We use normal content negotiation unless you include
|
|
172
|
-
#
|
|
219
|
+
# We use normal content negotiation unless you include **/** in your list, in
|
|
220
|
+
# which case we assume you're a browser and send HTML.
|
|
173
221
|
BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
|
|
174
222
|
|
|
175
223
|
def params_readable?
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "singleton"
|
|
4
6
|
|
|
5
7
|
module Mime
|
|
@@ -65,19 +67,20 @@ module Mime
|
|
|
65
67
|
end
|
|
66
68
|
end
|
|
67
69
|
|
|
68
|
-
# Encapsulates the notion of a MIME type. Can be used at render time, for
|
|
70
|
+
# Encapsulates the notion of a MIME type. Can be used at render time, for
|
|
71
|
+
# example, with:
|
|
69
72
|
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
+
# class PostsController < ActionController::Base
|
|
74
|
+
# def show
|
|
75
|
+
# @post = Post.find(params[:id])
|
|
73
76
|
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
77
|
+
# respond_to do |format|
|
|
78
|
+
# format.html
|
|
79
|
+
# format.ics { render body: @post.to_ics, mime_type: Mime::Type.lookup("text/calendar") }
|
|
80
|
+
# format.xml { render xml: @post }
|
|
81
|
+
# end
|
|
78
82
|
# end
|
|
79
83
|
# end
|
|
80
|
-
# end
|
|
81
84
|
class Type
|
|
82
85
|
attr_reader :symbol
|
|
83
86
|
|
|
@@ -173,8 +176,9 @@ module Mime
|
|
|
173
176
|
EXTENSION_LOOKUP[extension.to_s]
|
|
174
177
|
end
|
|
175
178
|
|
|
176
|
-
# Registers an alias that's not used on MIME type lookup, but can be referenced
|
|
177
|
-
# rendering different HTML versions depending on
|
|
179
|
+
# Registers an alias that's not used on MIME type lookup, but can be referenced
|
|
180
|
+
# directly. Especially useful for rendering different HTML versions depending on
|
|
181
|
+
# the user agent, like an iPhone.
|
|
178
182
|
def register_alias(string, symbol, extension_synonyms = [])
|
|
179
183
|
register(string, symbol, [], extension_synonyms, true)
|
|
180
184
|
end
|
|
@@ -224,11 +228,11 @@ module Mime
|
|
|
224
228
|
parse_data_with_trailing_star($1) if accept_header =~ TRAILING_STAR_REGEXP
|
|
225
229
|
end
|
|
226
230
|
|
|
227
|
-
# For an input of
|
|
228
|
-
# Mime[:html], Mime[:css], Mime[:csv], Mime[:js], Mime[:yaml], Mime[:text]]
|
|
231
|
+
# For an input of `'text'`, returns `[Mime[:json], Mime[:xml], Mime[:ics],
|
|
232
|
+
# Mime[:html], Mime[:css], Mime[:csv], Mime[:js], Mime[:yaml], Mime[:text]]`.
|
|
229
233
|
#
|
|
230
|
-
# For an input of
|
|
231
|
-
# Mime[:
|
|
234
|
+
# For an input of `'application'`, returns `[Mime[:html], Mime[:js], Mime[:xml],
|
|
235
|
+
# Mime[:yaml], Mime[:atom], Mime[:json], Mime[:rss], Mime[:url_encoded_form]]`.
|
|
232
236
|
def parse_data_with_trailing_star(type)
|
|
233
237
|
Mime::SET.select { |m| m.match?(type) }
|
|
234
238
|
end
|
|
@@ -237,7 +241,7 @@ module Mime
|
|
|
237
241
|
#
|
|
238
242
|
# To unregister a MIME type:
|
|
239
243
|
#
|
|
240
|
-
#
|
|
244
|
+
# Mime::Type.unregister(:mobile)
|
|
241
245
|
def unregister(symbol)
|
|
242
246
|
symbol = symbol.downcase
|
|
243
247
|
if mime = Mime[symbol]
|
|
@@ -329,7 +333,7 @@ module Mime
|
|
|
329
333
|
def to_ary; end
|
|
330
334
|
def to_a; end
|
|
331
335
|
|
|
332
|
-
def method_missing(method,
|
|
336
|
+
def method_missing(method, ...)
|
|
333
337
|
if method.end_with?("?")
|
|
334
338
|
method[0..-2].downcase.to_sym == to_sym
|
|
335
339
|
else
|
|
@@ -353,9 +357,9 @@ module Mime
|
|
|
353
357
|
def html?; true; end
|
|
354
358
|
end
|
|
355
359
|
|
|
356
|
-
# ALL isn't a real MIME type, so we don't register it for lookup with the
|
|
357
|
-
#
|
|
358
|
-
#
|
|
360
|
+
# ALL isn't a real MIME type, so we don't register it for lookup with the other
|
|
361
|
+
# concrete types. It's a wildcard match that we use for `respond_to` negotiation
|
|
362
|
+
# internals.
|
|
359
363
|
ALL = AllType.instance
|
|
360
364
|
|
|
361
365
|
class NullType
|
|
@@ -376,7 +380,7 @@ module Mime
|
|
|
376
380
|
method.end_with?("?")
|
|
377
381
|
end
|
|
378
382
|
|
|
379
|
-
def method_missing(method,
|
|
383
|
+
def method_missing(method, ...)
|
|
380
384
|
false if method.end_with?("?")
|
|
381
385
|
end
|
|
382
386
|
end
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
# Build list of Mime types for HTTP responses
|
|
4
4
|
# https://www.iana.org/assignments/media-types/
|
|
5
5
|
|
|
6
|
+
# :markup: markdown
|
|
7
|
+
|
|
6
8
|
Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml )
|
|
7
9
|
Mime::Type.register "text/plain", :text, [], %w(txt)
|
|
8
10
|
Mime::Type.register "text/javascript", :js, %w( application/javascript application/x-javascript )
|
|
@@ -11,6 +13,7 @@ Mime::Type.register "text/calendar", :ics
|
|
|
11
13
|
Mime::Type.register "text/csv", :csv
|
|
12
14
|
Mime::Type.register "text/vcard", :vcf
|
|
13
15
|
Mime::Type.register "text/vtt", :vtt, %w(vtt)
|
|
16
|
+
Mime::Type.register "text/markdown", :md, [], %w(md markdown)
|
|
14
17
|
|
|
15
18
|
Mime::Type.register "image/png", :png, [], %w(png)
|
|
16
19
|
Mime::Type.register "image/jpeg", :jpeg, [], %w(jpg jpeg jpe pjpeg)
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActionDispatch
|
|
4
|
+
class ParamBuilder
|
|
5
|
+
# --
|
|
6
|
+
# This implementation is based on Rack::QueryParser,
|
|
7
|
+
# Copyright (C) 2007-2021 Leah Neukirchen <http://leahneukirchen.org/infopage.html>
|
|
8
|
+
|
|
9
|
+
def self.make_default(param_depth_limit)
|
|
10
|
+
new param_depth_limit
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr_reader :param_depth_limit
|
|
14
|
+
|
|
15
|
+
def initialize(param_depth_limit)
|
|
16
|
+
@param_depth_limit = param_depth_limit
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
cattr_accessor :default
|
|
20
|
+
self.default = make_default(100)
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
delegate :from_query_string, :from_pairs, :from_hash, to: :default
|
|
24
|
+
|
|
25
|
+
def ignore_leading_brackets
|
|
26
|
+
ActionDispatch.deprecator.warn <<~MSG
|
|
27
|
+
ActionDispatch::ParamBuilder.ignore_leading_brackets is deprecated and have no effect and will be removed in Rails 8.2.
|
|
28
|
+
MSG
|
|
29
|
+
|
|
30
|
+
@ignore_leading_brackets
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def ignore_leading_brackets=(value)
|
|
34
|
+
ActionDispatch.deprecator.warn <<~MSG
|
|
35
|
+
ActionDispatch::ParamBuilder.ignore_leading_brackets is deprecated and have no effect and will be removed in Rails 8.2.
|
|
36
|
+
MSG
|
|
37
|
+
|
|
38
|
+
@ignore_leading_brackets = value
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def from_query_string(qs, separator: nil, encoding_template: nil)
|
|
43
|
+
from_pairs QueryParser.each_pair(qs, separator), encoding_template: encoding_template
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def from_pairs(pairs, encoding_template: nil)
|
|
47
|
+
params = make_params
|
|
48
|
+
|
|
49
|
+
pairs.each do |k, v|
|
|
50
|
+
if Hash === v
|
|
51
|
+
v = ActionDispatch::Http::UploadedFile.new(v)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
store_nested_param(params, k, v, 0, encoding_template)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
params
|
|
58
|
+
rescue ArgumentError => e
|
|
59
|
+
raise InvalidParameterError, e.message, e.backtrace
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def from_hash(hash, encoding_template: nil)
|
|
63
|
+
# Force encodings from encoding template
|
|
64
|
+
hash = Request::Utils::CustomParamEncoder.encode_for_template(hash, encoding_template)
|
|
65
|
+
|
|
66
|
+
# Assert valid encoding
|
|
67
|
+
Request::Utils.check_param_encoding(hash)
|
|
68
|
+
|
|
69
|
+
# Convert hashes to HWIA (or UploadedFile), and deep-munge nils
|
|
70
|
+
# out of arrays
|
|
71
|
+
hash = Request::Utils.normalize_encode_params(hash)
|
|
72
|
+
|
|
73
|
+
hash
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
def store_nested_param(params, name, v, depth, encoding_template = nil)
|
|
78
|
+
raise ParamsTooDeepError if depth >= param_depth_limit
|
|
79
|
+
|
|
80
|
+
if !name
|
|
81
|
+
# nil name, treat same as empty string (required by tests)
|
|
82
|
+
k = after = ""
|
|
83
|
+
elsif depth == 0
|
|
84
|
+
# Start of parsing, don't treat [] or [ at start of string specially
|
|
85
|
+
if start = name.index("[", 1)
|
|
86
|
+
# Start of parameter nesting, use part before brackets as key
|
|
87
|
+
k = name[0, start]
|
|
88
|
+
after = name[start, name.length]
|
|
89
|
+
else
|
|
90
|
+
# Plain parameter with no nesting
|
|
91
|
+
k = name
|
|
92
|
+
after = ""
|
|
93
|
+
end
|
|
94
|
+
elsif name.start_with?("[]")
|
|
95
|
+
# Array nesting
|
|
96
|
+
k = "[]"
|
|
97
|
+
after = name[2, name.length]
|
|
98
|
+
elsif name.start_with?("[") && (start = name.index("]", 1))
|
|
99
|
+
# Hash nesting, use the part inside brackets as the key
|
|
100
|
+
k = name[1, start - 1]
|
|
101
|
+
after = name[start + 1, name.length]
|
|
102
|
+
else
|
|
103
|
+
# Probably malformed input, nested but not starting with [
|
|
104
|
+
# treat full name as key for backwards compatibility.
|
|
105
|
+
k = name
|
|
106
|
+
after = ""
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
return if k.empty?
|
|
110
|
+
|
|
111
|
+
unless k.valid_encoding?
|
|
112
|
+
raise InvalidParameterError, "Invalid encoding for parameter: #{k}"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
if depth == 0 && String === v
|
|
116
|
+
# We have to wait until we've found the top part of the name,
|
|
117
|
+
# because that's what the encoding template is configured with
|
|
118
|
+
if encoding_template && (designated_encoding = encoding_template[k]) && !v.frozen?
|
|
119
|
+
v.force_encoding(designated_encoding)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# ... and we can't validate the encoding until after we've
|
|
123
|
+
# applied any template override
|
|
124
|
+
unless v.valid_encoding?
|
|
125
|
+
raise InvalidParameterError, "Invalid encoding for parameter: #{v.scrub}"
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
if after == ""
|
|
130
|
+
if k == "[]" && depth != 0
|
|
131
|
+
return (v || !ActionDispatch::Request::Utils.perform_deep_munge) ? [v] : []
|
|
132
|
+
else
|
|
133
|
+
params[k] = v
|
|
134
|
+
end
|
|
135
|
+
elsif after == "["
|
|
136
|
+
params[name] = v
|
|
137
|
+
elsif after == "[]"
|
|
138
|
+
params[k] ||= []
|
|
139
|
+
raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
|
|
140
|
+
params[k] << v if v || !ActionDispatch::Request::Utils.perform_deep_munge
|
|
141
|
+
elsif after.start_with?("[]")
|
|
142
|
+
# Recognize x[][y] (hash inside array) parameters
|
|
143
|
+
unless after[2] == "[" && after.end_with?("]") && (child_key = after[3, after.length - 4]) && !child_key.empty? && !child_key.index("[") && !child_key.index("]")
|
|
144
|
+
# Handle other nested array parameters
|
|
145
|
+
child_key = after[2, after.length]
|
|
146
|
+
end
|
|
147
|
+
params[k] ||= []
|
|
148
|
+
raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
|
|
149
|
+
if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key)
|
|
150
|
+
store_nested_param(params[k].last, child_key, v, depth + 1)
|
|
151
|
+
else
|
|
152
|
+
params[k] << store_nested_param(make_params, child_key, v, depth + 1)
|
|
153
|
+
end
|
|
154
|
+
else
|
|
155
|
+
params[k] ||= make_params
|
|
156
|
+
raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k])
|
|
157
|
+
params[k] = store_nested_param(params[k], after, v, depth + 1)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
params
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def make_params
|
|
164
|
+
ActiveSupport::HashWithIndifferentAccess.new
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def new_depth_limit(param_depth_limit)
|
|
168
|
+
self.class.new @params_class, param_depth_limit
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def params_hash_type?(obj)
|
|
172
|
+
Hash === obj
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def params_hash_has_key?(hash, key)
|
|
176
|
+
return false if key.include?("[]")
|
|
177
|
+
|
|
178
|
+
key.split(/[\[\]]+/).inject(hash) do |h, part|
|
|
179
|
+
next h if part == ""
|
|
180
|
+
return false unless params_hash_type?(h) && h.key?(part)
|
|
181
|
+
h[part]
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
true
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActionDispatch
|
|
4
|
+
class ParamError < ActionDispatch::Http::Parameters::ParseError
|
|
5
|
+
def initialize(message = nil)
|
|
6
|
+
super
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.===(other)
|
|
10
|
+
super || (
|
|
11
|
+
defined?(Rack::Utils::ParameterTypeError) && Rack::Utils::ParameterTypeError === other ||
|
|
12
|
+
defined?(Rack::Utils::InvalidParameterError) && Rack::Utils::InvalidParameterError === other ||
|
|
13
|
+
defined?(Rack::QueryParser::ParamsTooDeepError) && Rack::QueryParser::ParamsTooDeepError === other
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class ParameterTypeError < ParamError
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class InvalidParameterError < ParamError
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class ParamsTooDeepError < ParamError
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module ActionDispatch
|
|
4
6
|
module Http
|
|
5
7
|
module Parameters
|
|
@@ -14,8 +16,8 @@ module ActionDispatch
|
|
|
14
16
|
}
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
# Raised when raw data from the request cannot be parsed by the parser
|
|
18
|
-
#
|
|
19
|
+
# Raised when raw data from the request cannot be parsed by the parser defined
|
|
20
|
+
# for request's content MIME type.
|
|
19
21
|
class ParseError < StandardError
|
|
20
22
|
def initialize(message = $!.message)
|
|
21
23
|
super(message)
|
|
@@ -34,8 +36,8 @@ module ActionDispatch
|
|
|
34
36
|
module ClassMethods
|
|
35
37
|
# Configure the parameter parser for a given MIME type.
|
|
36
38
|
#
|
|
37
|
-
# It accepts a hash where the key is the symbol of the MIME type
|
|
38
|
-
#
|
|
39
|
+
# It accepts a hash where the key is the symbol of the MIME type and the value
|
|
40
|
+
# is a proc.
|
|
39
41
|
#
|
|
40
42
|
# original_parsers = ActionDispatch::Request.parameter_parsers
|
|
41
43
|
# xml_parser = -> (raw_post) { Hash.from_xml(raw_post) || {} }
|
|
@@ -46,7 +48,7 @@ module ActionDispatch
|
|
|
46
48
|
end
|
|
47
49
|
end
|
|
48
50
|
|
|
49
|
-
# Returns both GET and POST
|
|
51
|
+
# Returns both GET and POST parameters in a single hash.
|
|
50
52
|
def parameters
|
|
51
53
|
params = get_header("action_dispatch.request.parameters")
|
|
52
54
|
return params if params
|
|
@@ -63,24 +65,24 @@ module ActionDispatch
|
|
|
63
65
|
alias :params :parameters
|
|
64
66
|
|
|
65
67
|
def path_parameters=(parameters) # :nodoc:
|
|
66
|
-
|
|
68
|
+
@env.delete("action_dispatch.request.parameters")
|
|
67
69
|
|
|
68
70
|
parameters = Request::Utils.set_binary_encoding(self, parameters, parameters[:controller], parameters[:action])
|
|
69
|
-
# If any of the path parameters has an invalid encoding then
|
|
70
|
-
#
|
|
71
|
+
# If any of the path parameters has an invalid encoding then raise since it's
|
|
72
|
+
# likely to trigger errors further on.
|
|
71
73
|
Request::Utils.check_param_encoding(parameters)
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
@env[PARAMETERS_KEY] = parameters
|
|
74
76
|
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
|
75
77
|
raise ActionController::BadRequest.new("Invalid path parameters: #{e.message}")
|
|
76
78
|
end
|
|
77
79
|
|
|
78
|
-
# Returns a hash with the
|
|
80
|
+
# Returns a hash with the parameters used to form the path of the request.
|
|
79
81
|
# Returned hash keys are symbols:
|
|
80
82
|
#
|
|
81
|
-
#
|
|
83
|
+
# { action: "my_action", controller: "my_controller" }
|
|
82
84
|
def path_parameters
|
|
83
|
-
|
|
85
|
+
@env[PARAMETERS_KEY] ||= {}
|
|
84
86
|
end
|
|
85
87
|
|
|
86
88
|
private
|