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
|
@@ -105,12 +105,10 @@ function match(input) {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
if(stdparam_states[state] && default_re.test(token)) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
new_states.push([new_state, null]);
|
|
113
|
-
}
|
|
108
|
+
var new_state = stdparam_states[state];
|
|
109
|
+
highlight_edge(state, new_state);
|
|
110
|
+
highlight_state(new_state);
|
|
111
|
+
new_states.push([new_state, null]);
|
|
114
112
|
}
|
|
115
113
|
}
|
|
116
114
|
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module ActionDispatch
|
|
4
|
-
class LogSubscriber < ActiveSupport::LogSubscriber
|
|
4
|
+
class LogSubscriber < ActiveSupport::LogSubscriber # :nodoc:
|
|
5
|
+
class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
|
|
6
|
+
|
|
5
7
|
def redirect(event)
|
|
6
8
|
payload = event.payload
|
|
7
9
|
|
|
8
10
|
info { "Redirected to #{payload[:location]}" }
|
|
9
11
|
|
|
12
|
+
if ActionDispatch.verbose_redirect_logs
|
|
13
|
+
info { "↳ #{payload[:source_location]}" }
|
|
14
|
+
end
|
|
15
|
+
|
|
10
16
|
info do
|
|
11
17
|
status = payload[:status]
|
|
12
18
|
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module ActionDispatch
|
|
4
|
-
#
|
|
6
|
+
# # Action Dispatch AssumeSSL
|
|
5
7
|
#
|
|
6
|
-
# When proxying through a load balancer that terminates SSL, the forwarded
|
|
7
|
-
# as though it's HTTP instead of HTTPS to the application.
|
|
8
|
-
# security target HTTP instead of HTTPS. This
|
|
9
|
-
#
|
|
8
|
+
# When proxying through a load balancer that terminates SSL, the forwarded
|
|
9
|
+
# request will appear as though it's HTTP instead of HTTPS to the application.
|
|
10
|
+
# This makes redirects and cookie security target HTTP instead of HTTPS. This
|
|
11
|
+
# middleware makes the server assume that the proxy already terminated SSL, and
|
|
12
|
+
# that the request really is HTTPS.
|
|
10
13
|
class AssumeSSL
|
|
11
14
|
def initialize(app)
|
|
12
15
|
@app = app
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "active_support/core_ext/hash/keys"
|
|
4
6
|
require "active_support/key_generator"
|
|
5
7
|
require "active_support/message_verifier"
|
|
@@ -94,97 +96,102 @@ module ActionDispatch
|
|
|
94
96
|
|
|
95
97
|
# Read and write data to cookies through ActionController::Cookies#cookies.
|
|
96
98
|
#
|
|
97
|
-
# When reading cookie data, the data is read from the HTTP request header,
|
|
98
|
-
# When writing cookie data, the data is sent out in the HTTP response
|
|
99
|
+
# When reading cookie data, the data is read from the HTTP request header,
|
|
100
|
+
# Cookie. When writing cookie data, the data is sent out in the HTTP response
|
|
101
|
+
# header, `Set-Cookie`.
|
|
99
102
|
#
|
|
100
103
|
# Examples of writing:
|
|
101
104
|
#
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
#
|
|
105
|
+
# # Sets a simple session cookie.
|
|
106
|
+
# # This cookie will be deleted when the user's browser is closed.
|
|
107
|
+
# cookies[:user_name] = "david"
|
|
105
108
|
#
|
|
106
|
-
#
|
|
107
|
-
#
|
|
109
|
+
# # Cookie values are String-based. Other data types need to be serialized.
|
|
110
|
+
# cookies[:lat_lon] = JSON.generate([47.68, -122.37])
|
|
108
111
|
#
|
|
109
|
-
#
|
|
110
|
-
#
|
|
112
|
+
# # Sets a cookie that expires in 1 hour.
|
|
113
|
+
# cookies[:login] = { value: "XJ-122", expires: 1.hour }
|
|
111
114
|
#
|
|
112
|
-
#
|
|
113
|
-
#
|
|
115
|
+
# # Sets a cookie that expires at a specific time.
|
|
116
|
+
# cookies[:login] = { value: "XJ-122", expires: Time.utc(2020, 10, 15, 5) }
|
|
114
117
|
#
|
|
115
|
-
#
|
|
116
|
-
#
|
|
117
|
-
#
|
|
118
|
+
# # Sets a signed cookie, which prevents users from tampering with its value.
|
|
119
|
+
# cookies.signed[:user_id] = current_user.id
|
|
120
|
+
# # It can be read using the signed method.
|
|
121
|
+
# cookies.signed[:user_id] # => 123
|
|
118
122
|
#
|
|
119
|
-
#
|
|
120
|
-
#
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
+
# # Sets an encrypted cookie value before sending it to the client which
|
|
124
|
+
# # prevent users from reading and tampering with its value.
|
|
125
|
+
# cookies.encrypted[:discount] = 45
|
|
126
|
+
# # It can be read using the encrypted method.
|
|
127
|
+
# cookies.encrypted[:discount] # => 45
|
|
123
128
|
#
|
|
124
|
-
#
|
|
125
|
-
#
|
|
129
|
+
# # Sets a "permanent" cookie (which expires in 20 years from now).
|
|
130
|
+
# cookies.permanent[:login] = "XJ-122"
|
|
126
131
|
#
|
|
127
|
-
#
|
|
128
|
-
#
|
|
132
|
+
# # You can also chain these methods:
|
|
133
|
+
# cookies.signed.permanent[:login] = "XJ-122"
|
|
129
134
|
#
|
|
130
135
|
# Examples of reading:
|
|
131
136
|
#
|
|
132
|
-
#
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
#
|
|
136
|
-
#
|
|
137
|
+
# cookies[:user_name] # => "david"
|
|
138
|
+
# cookies.size # => 2
|
|
139
|
+
# JSON.parse(cookies[:lat_lon]) # => [47.68, -122.37]
|
|
140
|
+
# cookies.signed[:login] # => "XJ-122"
|
|
141
|
+
# cookies.encrypted[:discount] # => 45
|
|
137
142
|
#
|
|
138
143
|
# Example for deleting:
|
|
139
144
|
#
|
|
140
|
-
#
|
|
145
|
+
# cookies.delete :user_name
|
|
141
146
|
#
|
|
142
|
-
# Please note that if you specify a
|
|
147
|
+
# Please note that if you specify a `:domain` when setting a cookie, you must
|
|
148
|
+
# also specify the domain when deleting the cookie:
|
|
143
149
|
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
#
|
|
147
|
-
#
|
|
148
|
-
#
|
|
150
|
+
# cookies[:name] = {
|
|
151
|
+
# value: 'a yummy cookie',
|
|
152
|
+
# expires: 1.year,
|
|
153
|
+
# domain: 'domain.com'
|
|
154
|
+
# }
|
|
149
155
|
#
|
|
150
|
-
#
|
|
156
|
+
# cookies.delete(:name, domain: 'domain.com')
|
|
151
157
|
#
|
|
152
158
|
# The option symbols for setting cookies are:
|
|
153
159
|
#
|
|
154
|
-
# *
|
|
155
|
-
# *
|
|
156
|
-
#
|
|
157
|
-
# *
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
#
|
|
163
|
-
#
|
|
164
|
-
#
|
|
165
|
-
# with a proc.
|
|
160
|
+
# * `:value` - The cookie's value.
|
|
161
|
+
# * `:path` - The path for which this cookie applies. Defaults to the root of
|
|
162
|
+
# the application.
|
|
163
|
+
# * `:domain` - The domain for which this cookie applies so you can restrict
|
|
164
|
+
# to the domain level. If you use a schema like www.example.com and want to
|
|
165
|
+
# share session with user.example.com set `:domain` to `:all`. To support
|
|
166
|
+
# multiple domains, provide an array, and the first domain matching
|
|
167
|
+
# `request.host` will be used. Make sure to specify the `:domain` option
|
|
168
|
+
# with `:all` or `Array` again when deleting cookies. For more flexibility
|
|
169
|
+
# you can set the domain on a per-request basis by specifying `:domain` with
|
|
170
|
+
# a proc.
|
|
166
171
|
#
|
|
167
|
-
#
|
|
168
|
-
#
|
|
169
|
-
#
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
#
|
|
173
|
-
#
|
|
172
|
+
# domain: nil # Does not set cookie domain. (default)
|
|
173
|
+
# domain: :all # Allow the cookie for the top most level
|
|
174
|
+
# # domain and subdomains.
|
|
175
|
+
# domain: %w(.example.com .example.org) # Allow the cookie
|
|
176
|
+
# # for concrete domain names.
|
|
177
|
+
# domain: proc { Tenant.current.cookie_domain } # Set cookie domain dynamically
|
|
178
|
+
# domain: proc { |req| ".sub.#{req.host}" } # Set cookie domain dynamically based on request
|
|
174
179
|
#
|
|
180
|
+
# * `:tld_length` - When using `:domain => :all`, this option can be used to
|
|
181
|
+
# explicitly set the TLD length when using a short (<= 3 character) domain
|
|
182
|
+
# that is being interpreted as part of a TLD. For example, to share cookies
|
|
183
|
+
# between user1.lvh.me and user2.lvh.me, set `:tld_length` to 2.
|
|
184
|
+
# * `:expires` - The time at which this cookie expires, as a Time or
|
|
185
|
+
# ActiveSupport::Duration object.
|
|
186
|
+
# * `:secure` - Whether this cookie is only transmitted to HTTPS servers.
|
|
187
|
+
# Default is `false`.
|
|
188
|
+
# * `:httponly` - Whether this cookie is accessible via scripting or only
|
|
189
|
+
# HTTP. Defaults to `false`.
|
|
190
|
+
# * `:same_site` - The value of the `SameSite` cookie attribute, which
|
|
191
|
+
# determines how this cookie should be restricted in cross-site contexts.
|
|
192
|
+
# Possible values are `nil`, `:none`, `:lax`, and `:strict`. Defaults to
|
|
193
|
+
# `:lax`.
|
|
175
194
|
#
|
|
176
|
-
# * <tt>:tld_length</tt> - When using <tt>:domain => :all</tt>, this option can be used to explicitly
|
|
177
|
-
# set the TLD length when using a short (<= 3 character) domain that is being interpreted as part of a TLD.
|
|
178
|
-
# For example, to share cookies between user1.lvh.me and user2.lvh.me, set <tt>:tld_length</tt> to 2.
|
|
179
|
-
# * <tt>:expires</tt> - The time at which this cookie expires, as a \Time or ActiveSupport::Duration object.
|
|
180
|
-
# * <tt>:secure</tt> - Whether this cookie is only transmitted to HTTPS servers.
|
|
181
|
-
# Default is +false+.
|
|
182
|
-
# * <tt>:httponly</tt> - Whether this cookie is accessible via scripting or
|
|
183
|
-
# only HTTP. Defaults to +false+.
|
|
184
|
-
# * <tt>:same_site</tt> - The value of the +SameSite+ cookie attribute, which
|
|
185
|
-
# determines how this cookie should be restricted in cross-site contexts.
|
|
186
|
-
# Possible values are +nil+, +:none+, +:lax+, and +:strict+. Defaults to
|
|
187
|
-
# +:lax+.
|
|
188
195
|
class Cookies
|
|
189
196
|
HTTP_HEADER = "Set-Cookie"
|
|
190
197
|
GENERATOR_KEY = "action_dispatch.key_generator"
|
|
@@ -208,59 +215,69 @@ module ActionDispatch
|
|
|
208
215
|
# Raised when storing more than 4K of session data.
|
|
209
216
|
CookieOverflow = Class.new StandardError
|
|
210
217
|
|
|
211
|
-
# Include in a cookie jar to allow chaining, e.g.
|
|
218
|
+
# Include in a cookie jar to allow chaining, e.g. `cookies.permanent.signed`.
|
|
212
219
|
module ChainedCookieJars
|
|
213
|
-
# Returns a jar that'll automatically set the assigned cookies to have an
|
|
220
|
+
# Returns a jar that'll automatically set the assigned cookies to have an
|
|
221
|
+
# expiration date 20 years from now. Example:
|
|
214
222
|
#
|
|
215
|
-
#
|
|
216
|
-
#
|
|
223
|
+
# cookies.permanent[:prefers_open_id] = true
|
|
224
|
+
# # => Set-Cookie: prefers_open_id=true; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
|
|
217
225
|
#
|
|
218
|
-
# This jar is only meant for writing. You'll read permanent cookies through the
|
|
226
|
+
# This jar is only meant for writing. You'll read permanent cookies through the
|
|
227
|
+
# regular accessor.
|
|
219
228
|
#
|
|
220
|
-
# This jar allows chaining with the signed jar as well, so you can set
|
|
229
|
+
# This jar allows chaining with the signed jar as well, so you can set
|
|
230
|
+
# permanent, signed cookies. Examples:
|
|
221
231
|
#
|
|
222
|
-
#
|
|
223
|
-
#
|
|
232
|
+
# cookies.permanent.signed[:remember_me] = current_user.id
|
|
233
|
+
# # => Set-Cookie: remember_me=BAhU--848956038e692d7046deab32b7131856ab20e14e; path=/; expires=Sun, 16-Dec-2029 03:24:16 GMT
|
|
224
234
|
def permanent
|
|
225
235
|
@permanent ||= PermanentCookieJar.new(self)
|
|
226
236
|
end
|
|
227
237
|
|
|
228
|
-
# Returns a jar that'll automatically generate a signed representation of cookie
|
|
229
|
-
# the cookie again. This is useful for
|
|
230
|
-
#
|
|
238
|
+
# Returns a jar that'll automatically generate a signed representation of cookie
|
|
239
|
+
# value and verify it when reading from the cookie again. This is useful for
|
|
240
|
+
# creating cookies with values that the user is not supposed to change. If a
|
|
241
|
+
# signed cookie was tampered with by the user (or a 3rd party), `nil` will be
|
|
242
|
+
# returned.
|
|
231
243
|
#
|
|
232
|
-
# This jar requires that you set a suitable secret for the verification on your
|
|
244
|
+
# This jar requires that you set a suitable secret for the verification on your
|
|
245
|
+
# app's `secret_key_base`.
|
|
233
246
|
#
|
|
234
247
|
# Example:
|
|
235
248
|
#
|
|
236
|
-
#
|
|
237
|
-
#
|
|
249
|
+
# cookies.signed[:discount] = 45
|
|
250
|
+
# # => Set-Cookie: discount=BAhpMg==--2c1c6906c90a3bc4fd54a51ffb41dffa4bf6b5f7; path=/
|
|
238
251
|
#
|
|
239
|
-
#
|
|
252
|
+
# cookies.signed[:discount] # => 45
|
|
240
253
|
def signed
|
|
241
254
|
@signed ||= SignedKeyRotatingCookieJar.new(self)
|
|
242
255
|
end
|
|
243
256
|
|
|
244
|
-
# Returns a jar that'll automatically encrypt cookie values before sending them
|
|
245
|
-
#
|
|
257
|
+
# Returns a jar that'll automatically encrypt cookie values before sending them
|
|
258
|
+
# to the client and will decrypt them for read. If the cookie was tampered with
|
|
259
|
+
# by the user (or a 3rd party), `nil` will be returned.
|
|
246
260
|
#
|
|
247
|
-
# If
|
|
248
|
-
# are both set, legacy
|
|
261
|
+
# If `config.action_dispatch.encrypted_cookie_salt` and
|
|
262
|
+
# `config.action_dispatch.encrypted_signed_cookie_salt` are both set, legacy
|
|
263
|
+
# cookies encrypted with HMAC AES-256-CBC will be transparently upgraded.
|
|
249
264
|
#
|
|
250
|
-
# This jar requires that you set a suitable secret for the verification on your
|
|
265
|
+
# This jar requires that you set a suitable secret for the verification on your
|
|
266
|
+
# app's `secret_key_base`.
|
|
251
267
|
#
|
|
252
268
|
# Example:
|
|
253
269
|
#
|
|
254
|
-
#
|
|
255
|
-
#
|
|
270
|
+
# cookies.encrypted[:discount] = 45
|
|
271
|
+
# # => Set-Cookie: discount=DIQ7fw==--K3n//8vvnSbGq9dA--7Xh91HfLpwzbj1czhBiwOg==; path=/
|
|
256
272
|
#
|
|
257
|
-
#
|
|
273
|
+
# cookies.encrypted[:discount] # => 45
|
|
258
274
|
def encrypted
|
|
259
275
|
@encrypted ||= EncryptedKeyRotatingCookieJar.new(self)
|
|
260
276
|
end
|
|
261
277
|
|
|
262
|
-
# Returns the
|
|
263
|
-
# Used by ActionDispatch::Session::CookieStore to
|
|
278
|
+
# Returns the `signed` or `encrypted` jar, preferring `encrypted` if
|
|
279
|
+
# `secret_key_base` is set. Used by ActionDispatch::Session::CookieStore to
|
|
280
|
+
# avoid the need to introduce new cookie stores.
|
|
264
281
|
def signed_or_encrypted
|
|
265
282
|
@signed_or_encrypted ||=
|
|
266
283
|
if request.secret_key_base.present?
|
|
@@ -324,7 +341,7 @@ module ActionDispatch
|
|
|
324
341
|
@cookies.each(&block)
|
|
325
342
|
end
|
|
326
343
|
|
|
327
|
-
# Returns the value of the cookie by
|
|
344
|
+
# Returns the value of the cookie by `name`, or `nil` if no such cookie exists.
|
|
328
345
|
def [](name)
|
|
329
346
|
@cookies[name.to_s]
|
|
330
347
|
end
|
|
@@ -357,8 +374,8 @@ module ActionDispatch
|
|
|
357
374
|
@cookies.map { |k, v| "#{escape(k)}=#{escape(v)}" }.join "; "
|
|
358
375
|
end
|
|
359
376
|
|
|
360
|
-
# Sets the cookie named
|
|
361
|
-
#
|
|
377
|
+
# Sets the cookie named `name`. The second argument may be the cookie's value or
|
|
378
|
+
# a hash of options as documented above.
|
|
362
379
|
def []=(name, options)
|
|
363
380
|
if options.is_a?(Hash)
|
|
364
381
|
options.symbolize_keys!
|
|
@@ -379,11 +396,11 @@ module ActionDispatch
|
|
|
379
396
|
value
|
|
380
397
|
end
|
|
381
398
|
|
|
382
|
-
# Removes the cookie on the client machine by setting the value to an empty
|
|
383
|
-
# and the expiration date in the past. Like
|
|
384
|
-
#
|
|
399
|
+
# Removes the cookie on the client machine by setting the value to an empty
|
|
400
|
+
# string and the expiration date in the past. Like `[]=`, you can pass in an
|
|
401
|
+
# options hash to delete cookies with extra data such as a `:path`.
|
|
385
402
|
#
|
|
386
|
-
# Returns the value of the cookie, or
|
|
403
|
+
# Returns the value of the cookie, or `nil` if the cookie does not exist.
|
|
387
404
|
def delete(name, options = {})
|
|
388
405
|
return unless @cookies.has_key? name.to_s
|
|
389
406
|
|
|
@@ -395,16 +412,16 @@ module ActionDispatch
|
|
|
395
412
|
value
|
|
396
413
|
end
|
|
397
414
|
|
|
398
|
-
# Whether the given cookie is to be deleted by this CookieJar.
|
|
399
|
-
#
|
|
400
|
-
#
|
|
415
|
+
# Whether the given cookie is to be deleted by this CookieJar. Like `[]=`, you
|
|
416
|
+
# can pass in an options hash to test if a deletion applies to a specific
|
|
417
|
+
# `:path`, `:domain` etc.
|
|
401
418
|
def deleted?(name, options = {})
|
|
402
419
|
options.symbolize_keys!
|
|
403
420
|
handle_options(options)
|
|
404
421
|
@delete_cookies[name.to_s] == options
|
|
405
422
|
end
|
|
406
423
|
|
|
407
|
-
# Removes all cookies on the client machine by calling
|
|
424
|
+
# Removes all cookies on the client machine by calling `delete` for each cookie.
|
|
408
425
|
def clear(options = {})
|
|
409
426
|
@cookies.each_key { |k| delete(k, options) }
|
|
410
427
|
end
|
|
@@ -447,8 +464,8 @@ module ActionDispatch
|
|
|
447
464
|
cookie_domain = ""
|
|
448
465
|
dot_splitted_host = request.host.split(".", -1)
|
|
449
466
|
|
|
450
|
-
# Case where request.host is not an IP address or it's an invalid domain
|
|
451
|
-
#
|
|
467
|
+
# Case where request.host is not an IP address or it's an invalid domain (ip
|
|
468
|
+
# confirms to the domain structure we expect so we explicitly check for ip)
|
|
452
469
|
if request.host.match?(/^[\d.]+$/) || dot_splitted_host.include?("") || dot_splitted_host.length == 1
|
|
453
470
|
options[:domain] = nil
|
|
454
471
|
return
|
|
@@ -593,8 +610,10 @@ module ActionDispatch
|
|
|
593
610
|
end
|
|
594
611
|
|
|
595
612
|
def check_for_overflow!(name, options)
|
|
596
|
-
|
|
597
|
-
|
|
613
|
+
total_size = name.to_s.bytesize + options[:value].bytesize
|
|
614
|
+
|
|
615
|
+
if total_size > MAX_COOKIE_SIZE
|
|
616
|
+
raise CookieOverflow, "#{name} cookie overflowed with size #{total_size} bytes"
|
|
598
617
|
end
|
|
599
618
|
end
|
|
600
619
|
end
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "action_dispatch/middleware/exception_wrapper"
|
|
4
6
|
require "action_dispatch/routing/inspector"
|
|
5
7
|
|
|
6
8
|
require "action_view"
|
|
7
9
|
|
|
8
10
|
module ActionDispatch
|
|
9
|
-
#
|
|
11
|
+
# # Action Dispatch DebugExceptions
|
|
10
12
|
#
|
|
11
|
-
# This middleware is responsible for logging exceptions and
|
|
12
|
-
#
|
|
13
|
+
# This middleware is responsible for logging exceptions and showing a debugging
|
|
14
|
+
# page in case the request is local.
|
|
13
15
|
class DebugExceptions
|
|
14
16
|
cattr_reader :interceptors, instance_accessor: false, default: []
|
|
15
17
|
|
|
@@ -63,7 +65,9 @@ module ActionDispatch
|
|
|
63
65
|
content_type = Mime[:text]
|
|
64
66
|
end
|
|
65
67
|
|
|
66
|
-
if
|
|
68
|
+
if request.head?
|
|
69
|
+
render(wrapper.status_code, "", content_type)
|
|
70
|
+
elsif api_request?(content_type)
|
|
67
71
|
render_for_api_request(content_type, wrapper)
|
|
68
72
|
else
|
|
69
73
|
render_for_browser_request(request, wrapper)
|
|
@@ -115,14 +119,15 @@ module ActionDispatch
|
|
|
115
119
|
DebugView.new(
|
|
116
120
|
request: request,
|
|
117
121
|
exception_wrapper: wrapper,
|
|
118
|
-
# Everything should use the wrapper, but we need to pass
|
|
119
|
-
#
|
|
122
|
+
# Everything should use the wrapper, but we need to pass `exception` for legacy
|
|
123
|
+
# code.
|
|
120
124
|
exception: wrapper.exception,
|
|
121
125
|
traces: wrapper.traces,
|
|
122
126
|
show_source_idx: wrapper.source_to_show_id,
|
|
123
127
|
trace_to_show: wrapper.trace_to_show,
|
|
124
128
|
routes_inspector: routes_inspector(wrapper),
|
|
125
129
|
source_extracts: wrapper.source_extracts,
|
|
130
|
+
exception_message_for_copy: compose_exception_message(wrapper).join("\n"),
|
|
126
131
|
)
|
|
127
132
|
end
|
|
128
133
|
|
|
@@ -136,16 +141,40 @@ module ActionDispatch
|
|
|
136
141
|
return unless logger
|
|
137
142
|
return if !log_rescued_responses?(request) && wrapper.rescue_response?
|
|
138
143
|
|
|
144
|
+
message = compose_exception_message(wrapper)
|
|
145
|
+
log_array(logger, message, request)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def compose_exception_message(wrapper)
|
|
139
149
|
trace = wrapper.exception_trace
|
|
140
150
|
|
|
141
151
|
message = []
|
|
142
152
|
message << " "
|
|
143
|
-
|
|
153
|
+
if wrapper.has_cause?
|
|
154
|
+
message << "#{wrapper.exception_class_name} (#{wrapper.message})"
|
|
155
|
+
wrapper.wrapped_causes.each do |wrapped_cause|
|
|
156
|
+
message << "Caused by: #{wrapped_cause.exception_class_name} (#{wrapped_cause.message})"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
message << "\nInformation for: #{wrapper.exception_class_name} (#{wrapper.message}):"
|
|
160
|
+
else
|
|
161
|
+
message << "#{wrapper.exception_class_name} (#{wrapper.message}):"
|
|
162
|
+
end
|
|
163
|
+
|
|
144
164
|
message.concat(wrapper.annotated_source_code)
|
|
145
165
|
message << " "
|
|
146
166
|
message.concat(trace)
|
|
147
167
|
|
|
148
|
-
|
|
168
|
+
if wrapper.has_cause?
|
|
169
|
+
wrapper.wrapped_causes.each do |wrapped_cause|
|
|
170
|
+
message << "\nInformation for cause: #{wrapped_cause.exception_class_name} (#{wrapped_cause.message}):"
|
|
171
|
+
message.concat(wrapped_cause.annotated_source_code)
|
|
172
|
+
message << " "
|
|
173
|
+
message.concat(wrapped_cause.exception_trace)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
message
|
|
149
178
|
end
|
|
150
179
|
|
|
151
180
|
def log_array(logger, lines, request)
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module ActionDispatch
|
|
4
|
-
#
|
|
6
|
+
# # Action Dispatch DebugLocks
|
|
5
7
|
#
|
|
6
8
|
# This middleware can be used to diagnose deadlocks in the autoload interlock.
|
|
7
9
|
#
|
|
8
10
|
# To use it, insert it near the top of the middleware stack, using
|
|
9
|
-
#
|
|
11
|
+
# `config/application.rb`:
|
|
10
12
|
#
|
|
11
13
|
# config.middleware.insert_before Rack::Sendfile, ActionDispatch::DebugLocks
|
|
12
14
|
#
|
|
13
|
-
# After restarting the application and re-triggering the deadlock condition,
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
15
|
+
# After restarting the application and re-triggering the deadlock condition, the
|
|
16
|
+
# route `/rails/locks` will show a summary of all threads currently known to the
|
|
17
|
+
# interlock, which lock level they are holding or awaiting, and their current
|
|
18
|
+
# backtrace.
|
|
17
19
|
#
|
|
18
20
|
# Generally a deadlock will be caused by the interlock conflicting with some
|
|
19
21
|
# other external lock or blocking I/O call. These cannot be automatically
|
|
@@ -46,14 +48,14 @@ module ActionDispatch
|
|
|
46
48
|
private
|
|
47
49
|
def render_details(req)
|
|
48
50
|
threads = ActiveSupport::Dependencies.interlock.raw_state do |raw_threads|
|
|
49
|
-
# The Interlock itself comes to a complete halt as long as this block
|
|
50
|
-
#
|
|
51
|
-
#
|
|
51
|
+
# The Interlock itself comes to a complete halt as long as this block is
|
|
52
|
+
# executing. That gives us a more consistent picture of everything, but creates
|
|
53
|
+
# a pretty strong Observer Effect.
|
|
52
54
|
#
|
|
53
|
-
# Most directly, that means we need to do as little as possible in
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
55
|
+
# Most directly, that means we need to do as little as possible in this block.
|
|
56
|
+
# More widely, it means this middleware should remain a strictly diagnostic tool
|
|
57
|
+
# (to be used when something has gone wrong), and not for any sort of general
|
|
58
|
+
# monitoring.
|
|
57
59
|
|
|
58
60
|
raw_threads.each.with_index do |(thread, info), idx|
|
|
59
61
|
info[:index] = idx
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "pp"
|
|
4
6
|
|
|
5
7
|
require "action_view"
|
|
@@ -13,17 +15,12 @@ module ActionDispatch
|
|
|
13
15
|
paths = RESCUES_TEMPLATE_PATHS.dup
|
|
14
16
|
lookup_context = ActionView::LookupContext.new(paths)
|
|
15
17
|
super(lookup_context, assigns, nil)
|
|
16
|
-
@exception_wrapper = assigns[:exception_wrapper]
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
def compiled_method_container
|
|
20
21
|
self.class
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
def error_highlight_available?
|
|
24
|
-
@exception_wrapper.error_highlight_available?
|
|
25
|
-
end
|
|
26
|
-
|
|
27
24
|
def debug_params(params)
|
|
28
25
|
clean_params = params.clone
|
|
29
26
|
clean_params.delete("action")
|
|
@@ -58,6 +55,17 @@ module ActionDispatch
|
|
|
58
55
|
end
|
|
59
56
|
end
|
|
60
57
|
|
|
58
|
+
def editor_url(location, line: nil)
|
|
59
|
+
if editor = ActiveSupport::Editor.current
|
|
60
|
+
line ||= location&.lineno
|
|
61
|
+
absolute_path = location&.absolute_path
|
|
62
|
+
|
|
63
|
+
if absolute_path && line && File.exist?(absolute_path)
|
|
64
|
+
editor.url_for(absolute_path, line)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
61
69
|
def protect_against_forgery?
|
|
62
70
|
false
|
|
63
71
|
end
|