actionpack 4.0.1 → 4.2.11.1
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 +402 -1173
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -7
- data/lib/abstract_controller/base.rb +39 -7
- data/lib/abstract_controller/callbacks.rb +32 -53
- data/lib/abstract_controller/collector.rb +11 -1
- data/lib/abstract_controller/helpers.rb +26 -16
- data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
- data/lib/abstract_controller/rendering.rb +57 -127
- data/lib/abstract_controller/url_for.rb +1 -1
- data/lib/abstract_controller.rb +1 -2
- data/lib/action_controller/base.rb +19 -10
- data/lib/action_controller/caching/fragments.rb +7 -1
- data/lib/action_controller/caching.rb +2 -12
- data/lib/action_controller/log_subscriber.rb +29 -20
- data/lib/action_controller/metal/conditional_get.rb +37 -12
- data/lib/action_controller/metal/data_streaming.rb +1 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
- data/lib/action_controller/metal/exceptions.rb +1 -1
- data/lib/action_controller/metal/flash.rb +17 -0
- data/lib/action_controller/metal/force_ssl.rb +2 -2
- data/lib/action_controller/metal/head.rb +8 -6
- data/lib/action_controller/metal/helpers.rb +6 -2
- data/lib/action_controller/metal/http_authentication.rb +45 -23
- data/lib/action_controller/metal/instrumentation.rb +9 -6
- data/lib/action_controller/metal/live.rb +173 -20
- data/lib/action_controller/metal/mime_responds.rb +127 -232
- data/lib/action_controller/metal/params_wrapper.rb +16 -9
- data/lib/action_controller/metal/rack_delegation.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +34 -26
- data/lib/action_controller/metal/renderers.rb +39 -12
- data/lib/action_controller/metal/rendering.rb +41 -14
- data/lib/action_controller/metal/request_forgery_protection.rb +147 -19
- data/lib/action_controller/metal/streaming.rb +19 -21
- data/lib/action_controller/metal/strong_parameters.rb +166 -22
- data/lib/action_controller/metal/testing.rb +0 -1
- data/lib/action_controller/metal/url_for.rb +11 -12
- data/lib/action_controller/metal.rb +14 -8
- data/lib/action_controller/model_naming.rb +1 -1
- data/lib/action_controller/railtie.rb +5 -1
- data/lib/action_controller/test_case.rb +160 -94
- data/lib/action_controller.rb +2 -18
- data/lib/action_dispatch/http/cache.rb +5 -4
- data/lib/action_dispatch/http/filter_parameters.rb +2 -2
- data/lib/action_dispatch/http/filter_redirect.rb +5 -4
- data/lib/action_dispatch/http/headers.rb +46 -10
- data/lib/action_dispatch/http/mime_negotiation.rb +31 -4
- data/lib/action_dispatch/http/mime_type.rb +25 -26
- data/lib/action_dispatch/http/mime_types.rb +1 -0
- data/lib/action_dispatch/http/parameter_filter.rb +1 -1
- data/lib/action_dispatch/http/parameters.rb +25 -41
- data/lib/action_dispatch/http/request.rb +49 -32
- data/lib/action_dispatch/http/response.rb +127 -25
- data/lib/action_dispatch/http/upload.rb +9 -21
- data/lib/action_dispatch/http/url.rb +97 -70
- data/lib/action_dispatch/journey/formatter.rb +35 -19
- data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -33
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
- data/lib/action_dispatch/journey/nodes/node.rb +4 -0
- data/lib/action_dispatch/journey/parser.rb +51 -59
- data/lib/action_dispatch/journey/parser.y +12 -10
- data/lib/action_dispatch/journey/path/pattern.rb +16 -19
- data/lib/action_dispatch/journey/route.rb +8 -19
- data/lib/action_dispatch/journey/router/strexp.rb +9 -6
- data/lib/action_dispatch/journey/router/utils.rb +54 -18
- data/lib/action_dispatch/journey/router.rb +53 -75
- data/lib/action_dispatch/journey/routes.rb +4 -0
- data/lib/action_dispatch/journey/scanner.rb +5 -5
- data/lib/action_dispatch/journey/visitors.rb +81 -60
- data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
- data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
- data/lib/action_dispatch/middleware/callbacks.rb +7 -7
- data/lib/action_dispatch/middleware/cookies.rb +119 -43
- data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -13
- data/lib/action_dispatch/middleware/exception_wrapper.rb +60 -20
- data/lib/action_dispatch/middleware/flash.rb +37 -24
- data/lib/action_dispatch/middleware/params_parser.rb +2 -2
- data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
- data/lib/action_dispatch/middleware/reloader.rb +11 -2
- data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
- data/lib/action_dispatch/middleware/request_id.rb +1 -1
- data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
- data/lib/action_dispatch/middleware/session/cookie_store.rb +8 -7
- data/lib/action_dispatch/middleware/show_exceptions.rb +6 -2
- data/lib/action_dispatch/middleware/ssl.rb +10 -7
- data/lib/action_dispatch/middleware/static.rb +79 -23
- data/lib/action_dispatch/middleware/templates/rescues/{_request_and_response.erb → _request_and_response.html.erb} +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/{routing_error.erb → routing_error.html.erb} +3 -1
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/{unknown_action.erb → unknown_action.html.erb} +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
- data/lib/action_dispatch/railtie.rb +5 -2
- data/lib/action_dispatch/request/session.rb +12 -0
- data/lib/action_dispatch/request/utils.rb +35 -0
- data/lib/action_dispatch/routing/endpoint.rb +10 -0
- data/lib/action_dispatch/routing/inspector.rb +11 -17
- data/lib/action_dispatch/routing/mapper.rb +519 -312
- data/lib/action_dispatch/routing/polymorphic_routes.rb +204 -79
- data/lib/action_dispatch/routing/redirection.rb +51 -26
- data/lib/action_dispatch/routing/route_set.rb +331 -206
- data/lib/action_dispatch/routing/routes_proxy.rb +5 -4
- data/lib/action_dispatch/routing/url_for.rb +19 -5
- data/lib/action_dispatch/routing.rb +9 -6
- data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
- data/lib/action_dispatch/testing/assertions/response.rb +9 -15
- data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
- data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
- data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
- data/lib/action_dispatch/testing/assertions.rb +11 -7
- data/lib/action_dispatch/testing/integration.rb +31 -29
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +1 -5
- data/lib/action_dispatch.rb +5 -8
- data/lib/action_pack/gem_version.rb +15 -0
- data/lib/action_pack/version.rb +4 -7
- data/lib/action_pack.rb +1 -1
- metadata +77 -159
- data/lib/abstract_controller/layouts.rb +0 -423
- data/lib/abstract_controller/view_paths.rb +0 -96
- data/lib/action_controller/deprecated/integration_test.rb +0 -5
- data/lib/action_controller/deprecated.rb +0 -7
- data/lib/action_controller/metal/responder.rb +0 -287
- data/lib/action_controller/record_identifier.rb +0 -31
- data/lib/action_controller/vendor/html-scanner.rb +0 -5
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -24
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -7
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -43
- data/lib/action_view/base.rb +0 -201
- data/lib/action_view/buffers.rb +0 -49
- data/lib/action_view/context.rb +0 -36
- data/lib/action_view/dependency_tracker.rb +0 -93
- data/lib/action_view/digestor.rb +0 -113
- data/lib/action_view/flows.rb +0 -76
- data/lib/action_view/helpers/active_model_helper.rb +0 -49
- data/lib/action_view/helpers/asset_tag_helper.rb +0 -320
- data/lib/action_view/helpers/asset_url_helper.rb +0 -355
- data/lib/action_view/helpers/atom_feed_helper.rb +0 -203
- data/lib/action_view/helpers/cache_helper.rb +0 -196
- data/lib/action_view/helpers/capture_helper.rb +0 -216
- data/lib/action_view/helpers/controller_helper.rb +0 -25
- data/lib/action_view/helpers/csrf_helper.rb +0 -30
- data/lib/action_view/helpers/date_helper.rb +0 -1083
- data/lib/action_view/helpers/debug_helper.rb +0 -39
- data/lib/action_view/helpers/form_helper.rb +0 -1880
- data/lib/action_view/helpers/form_options_helper.rb +0 -838
- data/lib/action_view/helpers/form_tag_helper.rb +0 -785
- data/lib/action_view/helpers/javascript_helper.rb +0 -117
- data/lib/action_view/helpers/number_helper.rb +0 -441
- data/lib/action_view/helpers/output_safety_helper.rb +0 -38
- data/lib/action_view/helpers/record_tag_helper.rb +0 -106
- data/lib/action_view/helpers/rendering_helper.rb +0 -90
- data/lib/action_view/helpers/sanitize_helper.rb +0 -256
- data/lib/action_view/helpers/tag_helper.rb +0 -173
- data/lib/action_view/helpers/tags/base.rb +0 -148
- data/lib/action_view/helpers/tags/check_box.rb +0 -64
- data/lib/action_view/helpers/tags/checkable.rb +0 -16
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -44
- data/lib/action_view/helpers/tags/collection_helpers.rb +0 -84
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -36
- data/lib/action_view/helpers/tags/collection_select.rb +0 -28
- data/lib/action_view/helpers/tags/color_field.rb +0 -25
- data/lib/action_view/helpers/tags/date_field.rb +0 -13
- data/lib/action_view/helpers/tags/date_select.rb +0 -72
- data/lib/action_view/helpers/tags/datetime_field.rb +0 -22
- data/lib/action_view/helpers/tags/datetime_local_field.rb +0 -19
- data/lib/action_view/helpers/tags/datetime_select.rb +0 -8
- data/lib/action_view/helpers/tags/email_field.rb +0 -8
- data/lib/action_view/helpers/tags/file_field.rb +0 -8
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +0 -29
- data/lib/action_view/helpers/tags/hidden_field.rb +0 -8
- data/lib/action_view/helpers/tags/label.rb +0 -66
- data/lib/action_view/helpers/tags/month_field.rb +0 -13
- data/lib/action_view/helpers/tags/number_field.rb +0 -18
- data/lib/action_view/helpers/tags/password_field.rb +0 -12
- data/lib/action_view/helpers/tags/radio_button.rb +0 -31
- data/lib/action_view/helpers/tags/range_field.rb +0 -8
- data/lib/action_view/helpers/tags/search_field.rb +0 -24
- data/lib/action_view/helpers/tags/select.rb +0 -40
- data/lib/action_view/helpers/tags/tel_field.rb +0 -8
- data/lib/action_view/helpers/tags/text_area.rb +0 -18
- data/lib/action_view/helpers/tags/text_field.rb +0 -29
- data/lib/action_view/helpers/tags/time_field.rb +0 -13
- data/lib/action_view/helpers/tags/time_select.rb +0 -8
- data/lib/action_view/helpers/tags/time_zone_select.rb +0 -20
- data/lib/action_view/helpers/tags/url_field.rb +0 -8
- data/lib/action_view/helpers/tags/week_field.rb +0 -13
- data/lib/action_view/helpers/tags.rb +0 -39
- data/lib/action_view/helpers/text_helper.rb +0 -443
- data/lib/action_view/helpers/translation_helper.rb +0 -107
- data/lib/action_view/helpers/url_helper.rb +0 -635
- data/lib/action_view/helpers.rb +0 -58
- data/lib/action_view/locale/en.yml +0 -56
- data/lib/action_view/log_subscriber.rb +0 -30
- data/lib/action_view/lookup_context.rb +0 -241
- data/lib/action_view/model_naming.rb +0 -12
- data/lib/action_view/path_set.rb +0 -77
- data/lib/action_view/railtie.rb +0 -43
- data/lib/action_view/record_identifier.rb +0 -84
- data/lib/action_view/renderer/abstract_renderer.rb +0 -47
- data/lib/action_view/renderer/partial_renderer.rb +0 -492
- data/lib/action_view/renderer/renderer.rb +0 -50
- data/lib/action_view/renderer/streaming_template_renderer.rb +0 -103
- data/lib/action_view/renderer/template_renderer.rb +0 -96
- data/lib/action_view/routing_url_for.rb +0 -107
- data/lib/action_view/tasks/dependencies.rake +0 -17
- data/lib/action_view/template/error.rb +0 -138
- data/lib/action_view/template/handlers/builder.rb +0 -26
- data/lib/action_view/template/handlers/erb.rb +0 -146
- data/lib/action_view/template/handlers/raw.rb +0 -11
- data/lib/action_view/template/handlers.rb +0 -53
- data/lib/action_view/template/resolver.rb +0 -326
- data/lib/action_view/template/text.rb +0 -34
- data/lib/action_view/template/types.rb +0 -57
- data/lib/action_view/template.rb +0 -339
- data/lib/action_view/test_case.rb +0 -270
- data/lib/action_view/testing/resolvers.rb +0 -50
- data/lib/action_view/vendor/html-scanner/html/document.rb +0 -68
- data/lib/action_view/vendor/html-scanner/html/node.rb +0 -532
- data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +0 -188
- data/lib/action_view/vendor/html-scanner/html/selector.rb +0 -830
- data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +0 -107
- data/lib/action_view/vendor/html-scanner/html/version.rb +0 -11
- data/lib/action_view/vendor/html-scanner.rb +0 -20
- data/lib/action_view.rb +0 -93
@@ -3,6 +3,7 @@ require 'active_support/core_ext/module/attribute_accessors'
|
|
3
3
|
require 'active_support/core_ext/object/blank'
|
4
4
|
require 'active_support/key_generator'
|
5
5
|
require 'active_support/message_verifier'
|
6
|
+
require 'active_support/json'
|
6
7
|
|
7
8
|
module ActionDispatch
|
8
9
|
class Request < Rack::Request
|
@@ -23,15 +24,15 @@ module ActionDispatch
|
|
23
24
|
# # This cookie will be deleted when the user's browser is closed.
|
24
25
|
# cookies[:user_name] = "david"
|
25
26
|
#
|
26
|
-
# #
|
27
|
-
# cookies[:lat_lon] = [47.68, -122.37]
|
27
|
+
# # Cookie values are String based. Other data types need to be serialized.
|
28
|
+
# cookies[:lat_lon] = JSON.generate([47.68, -122.37])
|
28
29
|
#
|
29
30
|
# # Sets a cookie that expires in 1 hour.
|
30
31
|
# cookies[:login] = { value: "XJ-122", expires: 1.hour.from_now }
|
31
32
|
#
|
32
33
|
# # Sets a signed cookie, which prevents users from tampering with its value.
|
33
|
-
# # The cookie is signed by your app's
|
34
|
-
# # It can be read using the signed method
|
34
|
+
# # The cookie is signed by your app's `secrets.secret_key_base` value.
|
35
|
+
# # It can be read using the signed method `cookies.signed[:name]`
|
35
36
|
# cookies.signed[:user_id] = current_user.id
|
36
37
|
#
|
37
38
|
# # Sets a "permanent" cookie (which expires in 20 years from now).
|
@@ -42,10 +43,10 @@ module ActionDispatch
|
|
42
43
|
#
|
43
44
|
# Examples of reading:
|
44
45
|
#
|
45
|
-
# cookies[:user_name]
|
46
|
-
# cookies.size
|
47
|
-
# cookies[:lat_lon]
|
48
|
-
# cookies.signed[:login]
|
46
|
+
# cookies[:user_name] # => "david"
|
47
|
+
# cookies.size # => 2
|
48
|
+
# JSON.parse(cookies[:lat_lon]) # => [47.68, -122.37]
|
49
|
+
# cookies.signed[:login] # => "XJ-122"
|
49
50
|
#
|
50
51
|
# Example for deleting:
|
51
52
|
#
|
@@ -63,18 +64,20 @@ module ActionDispatch
|
|
63
64
|
#
|
64
65
|
# The option symbols for setting cookies are:
|
65
66
|
#
|
66
|
-
# * <tt>:value</tt> - The cookie's value
|
67
|
+
# * <tt>:value</tt> - The cookie's value.
|
67
68
|
# * <tt>:path</tt> - The path for which this cookie applies. Defaults to the root
|
68
69
|
# of the application.
|
69
70
|
# * <tt>:domain</tt> - The domain for which this cookie applies so you can
|
70
71
|
# restrict to the domain level. If you use a schema like www.example.com
|
71
72
|
# and want to share session with user.example.com set <tt>:domain</tt>
|
72
73
|
# to <tt>:all</tt>. Make sure to specify the <tt>:domain</tt> option with
|
73
|
-
# <tt>:all</tt> again when deleting cookies.
|
74
|
+
# <tt>:all</tt> or <tt>Array</tt> again when deleting cookies.
|
74
75
|
#
|
75
76
|
# domain: nil # Does not sets cookie domain. (default)
|
76
77
|
# domain: :all # Allow the cookie for the top most level
|
77
|
-
#
|
78
|
+
# # domain and subdomains.
|
79
|
+
# domain: %w(.example.com .example.org) # Allow the cookie
|
80
|
+
# # for concrete domain names.
|
78
81
|
#
|
79
82
|
# * <tt>:expires</tt> - The time at which this cookie expires, as a \Time object.
|
80
83
|
# * <tt>:secure</tt> - Whether this cookie is only transmitted to HTTPS servers.
|
@@ -89,6 +92,8 @@ module ActionDispatch
|
|
89
92
|
ENCRYPTED_SIGNED_COOKIE_SALT = "action_dispatch.encrypted_signed_cookie_salt".freeze
|
90
93
|
SECRET_TOKEN = "action_dispatch.secret_token".freeze
|
91
94
|
SECRET_KEY_BASE = "action_dispatch.secret_key_base".freeze
|
95
|
+
COOKIES_SERIALIZER = "action_dispatch.cookies_serializer".freeze
|
96
|
+
COOKIES_DIGEST = "action_dispatch.cookies_digest".freeze
|
92
97
|
|
93
98
|
# Cookies can typically store 4096 bytes.
|
94
99
|
MAX_COOKIE_SIZE = 4096
|
@@ -117,10 +122,10 @@ module ActionDispatch
|
|
117
122
|
# the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed
|
118
123
|
# cookie was tampered with by the user (or a 3rd party), nil will be returned.
|
119
124
|
#
|
120
|
-
# If +
|
125
|
+
# If +secrets.secret_key_base+ and +secrets.secret_token+ (deprecated) are both set,
|
121
126
|
# legacy cookies signed with the old key generator will be transparently upgraded.
|
122
127
|
#
|
123
|
-
# This jar requires that you set a suitable secret for the verification on your app's +
|
128
|
+
# This jar requires that you set a suitable secret for the verification on your app's +secrets.secret_key_base+.
|
124
129
|
#
|
125
130
|
# Example:
|
126
131
|
#
|
@@ -140,10 +145,10 @@ module ActionDispatch
|
|
140
145
|
# Returns a jar that'll automatically encrypt cookie values before sending them to the client and will decrypt them for read.
|
141
146
|
# If the cookie was tampered with by the user (or a 3rd party), nil will be returned.
|
142
147
|
#
|
143
|
-
# If +
|
148
|
+
# If +secrets.secret_key_base+ and +secrets.secret_token+ (deprecated) are both set,
|
144
149
|
# legacy cookies signed with the old key generator will be transparently upgraded.
|
145
150
|
#
|
146
|
-
# This jar requires that you set a suitable secret for the verification on your app's +
|
151
|
+
# This jar requires that you set a suitable secret for the verification on your app's +secrets.secret_key_base+.
|
147
152
|
#
|
148
153
|
# Example:
|
149
154
|
#
|
@@ -172,15 +177,19 @@ module ActionDispatch
|
|
172
177
|
end
|
173
178
|
end
|
174
179
|
|
175
|
-
|
180
|
+
# Passing the ActiveSupport::MessageEncryptor::NullSerializer downstream
|
181
|
+
# to the Message{Encryptor,Verifier} allows us to handle the
|
182
|
+
# (de)serialization step within the cookie jar, which gives us the
|
183
|
+
# opportunity to detect and migrate legacy cookies.
|
184
|
+
module VerifyAndUpgradeLegacySignedMessage # :nodoc:
|
176
185
|
def initialize(*args)
|
177
186
|
super
|
178
|
-
@legacy_verifier = ActiveSupport::MessageVerifier.new(@options[:secret_token])
|
187
|
+
@legacy_verifier = ActiveSupport::MessageVerifier.new(@options[:secret_token], serializer: ActiveSupport::MessageEncryptor::NullSerializer)
|
179
188
|
end
|
180
189
|
|
181
190
|
def verify_and_upgrade_legacy_signed_message(name, signed_message)
|
182
|
-
@legacy_verifier.verify(signed_message).tap do |value|
|
183
|
-
self[name] = value
|
191
|
+
deserialize(name, @legacy_verifier.verify(signed_message)).tap do |value|
|
192
|
+
self[name] = { value: value }
|
184
193
|
end
|
185
194
|
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
186
195
|
nil
|
@@ -210,7 +219,9 @@ module ActionDispatch
|
|
210
219
|
encrypted_signed_cookie_salt: env[ENCRYPTED_SIGNED_COOKIE_SALT] || '',
|
211
220
|
secret_token: env[SECRET_TOKEN],
|
212
221
|
secret_key_base: env[SECRET_KEY_BASE],
|
213
|
-
upgrade_legacy_signed_cookies: env[SECRET_TOKEN].present? && env[SECRET_KEY_BASE].present
|
222
|
+
upgrade_legacy_signed_cookies: env[SECRET_TOKEN].present? && env[SECRET_KEY_BASE].present?,
|
223
|
+
serializer: env[COOKIES_SERIALIZER],
|
224
|
+
digest: env[COOKIES_DIGEST]
|
214
225
|
}
|
215
226
|
end
|
216
227
|
|
@@ -235,6 +246,15 @@ module ActionDispatch
|
|
235
246
|
@secure = secure
|
236
247
|
@options = options
|
237
248
|
@cookies = {}
|
249
|
+
@committed = false
|
250
|
+
end
|
251
|
+
|
252
|
+
def committed?; @committed; end
|
253
|
+
|
254
|
+
def commit!
|
255
|
+
@committed = true
|
256
|
+
@set_cookies.freeze
|
257
|
+
@delete_cookies.freeze
|
238
258
|
end
|
239
259
|
|
240
260
|
def each(&block)
|
@@ -278,8 +298,8 @@ module ActionDispatch
|
|
278
298
|
end
|
279
299
|
end
|
280
300
|
|
281
|
-
# Sets the cookie named +name+. The second argument may be the
|
282
|
-
# value
|
301
|
+
# Sets the cookie named +name+. The second argument may be the cookie's
|
302
|
+
# value or a hash of options as documented above.
|
283
303
|
def []=(name, options)
|
284
304
|
if options.is_a?(Hash)
|
285
305
|
options.symbolize_keys!
|
@@ -291,7 +311,7 @@ module ActionDispatch
|
|
291
311
|
|
292
312
|
handle_options(options)
|
293
313
|
|
294
|
-
if @cookies[name.to_s] != value
|
314
|
+
if @cookies[name.to_s] != value || options[:expires]
|
295
315
|
@cookies[name.to_s] = value
|
296
316
|
@set_cookies[name.to_s] = options
|
297
317
|
@delete_cookies.delete(name.to_s)
|
@@ -334,8 +354,8 @@ module ActionDispatch
|
|
334
354
|
end
|
335
355
|
|
336
356
|
def recycle! #:nodoc:
|
337
|
-
@set_cookies
|
338
|
-
@delete_cookies
|
357
|
+
@set_cookies = {}
|
358
|
+
@delete_cookies = {}
|
339
359
|
end
|
340
360
|
|
341
361
|
mattr_accessor :always_write_cookie
|
@@ -372,31 +392,83 @@ module ActionDispatch
|
|
372
392
|
end
|
373
393
|
end
|
374
394
|
|
395
|
+
class JsonSerializer # :nodoc:
|
396
|
+
def self.load(value)
|
397
|
+
ActiveSupport::JSON.decode(value)
|
398
|
+
end
|
399
|
+
|
400
|
+
def self.dump(value)
|
401
|
+
ActiveSupport::JSON.encode(value)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
module SerializedCookieJars # :nodoc:
|
406
|
+
MARSHAL_SIGNATURE = "\x04\x08".freeze
|
407
|
+
|
408
|
+
protected
|
409
|
+
def needs_migration?(value)
|
410
|
+
@options[:serializer] == :hybrid && value.start_with?(MARSHAL_SIGNATURE)
|
411
|
+
end
|
412
|
+
|
413
|
+
def serialize(name, value)
|
414
|
+
serializer.dump(value)
|
415
|
+
end
|
416
|
+
|
417
|
+
def deserialize(name, value)
|
418
|
+
if value
|
419
|
+
if needs_migration?(value)
|
420
|
+
Marshal.load(value).tap do |v|
|
421
|
+
self[name] = { value: v }
|
422
|
+
end
|
423
|
+
else
|
424
|
+
serializer.load(value)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
def serializer
|
430
|
+
serializer = @options[:serializer] || :marshal
|
431
|
+
case serializer
|
432
|
+
when :marshal
|
433
|
+
Marshal
|
434
|
+
when :json, :hybrid
|
435
|
+
JsonSerializer
|
436
|
+
else
|
437
|
+
serializer
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
def digest
|
442
|
+
@options[:digest] || 'SHA1'
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
375
446
|
class SignedCookieJar #:nodoc:
|
376
447
|
include ChainedCookieJars
|
448
|
+
include SerializedCookieJars
|
377
449
|
|
378
450
|
def initialize(parent_jar, key_generator, options = {})
|
379
451
|
@parent_jar = parent_jar
|
380
452
|
@options = options
|
381
453
|
secret = key_generator.generate_key(@options[:signed_cookie_salt])
|
382
|
-
@verifier
|
454
|
+
@verifier = ActiveSupport::MessageVerifier.new(secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
|
383
455
|
end
|
384
456
|
|
385
457
|
def [](name)
|
386
458
|
if signed_message = @parent_jar[name]
|
387
|
-
verify(signed_message)
|
459
|
+
deserialize name, verify(signed_message)
|
388
460
|
end
|
389
461
|
end
|
390
462
|
|
391
463
|
def []=(name, options)
|
392
464
|
if options.is_a?(Hash)
|
393
465
|
options.symbolize_keys!
|
394
|
-
options[:value] = @verifier.generate(options[:value])
|
466
|
+
options[:value] = @verifier.generate(serialize(name, options[:value]))
|
395
467
|
else
|
396
|
-
options = { :value => @verifier.generate(options) }
|
468
|
+
options = { :value => @verifier.generate(serialize(name, options)) }
|
397
469
|
end
|
398
470
|
|
399
|
-
raise CookieOverflow if options[:value].
|
471
|
+
raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
|
400
472
|
@parent_jar[name] = options
|
401
473
|
end
|
402
474
|
|
@@ -409,7 +481,7 @@ module ActionDispatch
|
|
409
481
|
end
|
410
482
|
|
411
483
|
# UpgradeLegacySignedCookieJar is used instead of SignedCookieJar if
|
412
|
-
#
|
484
|
+
# secrets.secret_token and secrets.secret_key_base are both set. It reads
|
413
485
|
# legacy cookies signed with the old dummy key generator and re-saves
|
414
486
|
# them using the new key generator to provide a smooth upgrade path.
|
415
487
|
class UpgradeLegacySignedCookieJar < SignedCookieJar #:nodoc:
|
@@ -417,30 +489,31 @@ module ActionDispatch
|
|
417
489
|
|
418
490
|
def [](name)
|
419
491
|
if signed_message = @parent_jar[name]
|
420
|
-
verify(signed_message) || verify_and_upgrade_legacy_signed_message(name, signed_message)
|
492
|
+
deserialize(name, verify(signed_message)) || verify_and_upgrade_legacy_signed_message(name, signed_message)
|
421
493
|
end
|
422
494
|
end
|
423
495
|
end
|
424
496
|
|
425
497
|
class EncryptedCookieJar #:nodoc:
|
426
498
|
include ChainedCookieJars
|
499
|
+
include SerializedCookieJars
|
427
500
|
|
428
501
|
def initialize(parent_jar, key_generator, options = {})
|
429
502
|
if ActiveSupport::LegacyKeyGenerator === key_generator
|
430
|
-
raise "You didn't set
|
503
|
+
raise "You didn't set secrets.secret_key_base, which is required for this cookie jar. " +
|
431
504
|
"Read the upgrade documentation to learn more about this new config option."
|
432
505
|
end
|
433
506
|
|
434
507
|
@parent_jar = parent_jar
|
435
508
|
@options = options
|
436
|
-
secret = key_generator.generate_key(@options[:encrypted_cookie_salt])
|
509
|
+
secret = key_generator.generate_key(@options[:encrypted_cookie_salt])[0, ActiveSupport::MessageEncryptor.key_len]
|
437
510
|
sign_secret = key_generator.generate_key(@options[:encrypted_signed_cookie_salt])
|
438
|
-
@encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret)
|
511
|
+
@encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
|
439
512
|
end
|
440
513
|
|
441
514
|
def [](name)
|
442
515
|
if encrypted_message = @parent_jar[name]
|
443
|
-
decrypt_and_verify(encrypted_message)
|
516
|
+
deserialize name, decrypt_and_verify(encrypted_message)
|
444
517
|
end
|
445
518
|
end
|
446
519
|
|
@@ -450,9 +523,10 @@ module ActionDispatch
|
|
450
523
|
else
|
451
524
|
options = { :value => options }
|
452
525
|
end
|
453
|
-
options[:value] = @encryptor.encrypt_and_sign(options[:value])
|
454
526
|
|
455
|
-
|
527
|
+
options[:value] = @encryptor.encrypt_and_sign(serialize(name, options[:value]))
|
528
|
+
|
529
|
+
raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
|
456
530
|
@parent_jar[name] = options
|
457
531
|
end
|
458
532
|
|
@@ -465,7 +539,7 @@ module ActionDispatch
|
|
465
539
|
end
|
466
540
|
|
467
541
|
# UpgradeLegacyEncryptedCookieJar is used by ActionDispatch::Session::CookieStore
|
468
|
-
# instead of EncryptedCookieJar if
|
542
|
+
# instead of EncryptedCookieJar if secrets.secret_token and secrets.secret_key_base
|
469
543
|
# are both set. It reads legacy cookies signed with the old dummy key generator and
|
470
544
|
# encrypts and re-saves them using the new key generator to provide a smooth upgrade path.
|
471
545
|
class UpgradeLegacyEncryptedCookieJar < EncryptedCookieJar #:nodoc:
|
@@ -473,7 +547,7 @@ module ActionDispatch
|
|
473
547
|
|
474
548
|
def [](name)
|
475
549
|
if encrypted_or_signed_message = @parent_jar[name]
|
476
|
-
decrypt_and_verify(encrypted_or_signed_message) || verify_and_upgrade_legacy_signed_message(name, encrypted_or_signed_message)
|
550
|
+
deserialize(name, decrypt_and_verify(encrypted_or_signed_message)) || verify_and_upgrade_legacy_signed_message(name, encrypted_or_signed_message)
|
477
551
|
end
|
478
552
|
end
|
479
553
|
end
|
@@ -486,9 +560,11 @@ module ActionDispatch
|
|
486
560
|
status, headers, body = @app.call(env)
|
487
561
|
|
488
562
|
if cookie_jar = env['action_dispatch.cookies']
|
489
|
-
cookie_jar.
|
490
|
-
|
491
|
-
|
563
|
+
unless cookie_jar.committed?
|
564
|
+
cookie_jar.write(headers)
|
565
|
+
if headers[HTTP_HEADER].respond_to?(:join)
|
566
|
+
headers[HTTP_HEADER] = headers[HTTP_HEADER].join("\n")
|
567
|
+
end
|
492
568
|
end
|
493
569
|
end
|
494
570
|
|
@@ -34,27 +34,46 @@ module ActionDispatch
|
|
34
34
|
log_error(env, wrapper)
|
35
35
|
|
36
36
|
if env['action_dispatch.show_detailed_exceptions']
|
37
|
+
request = Request.new(env)
|
38
|
+
traces = wrapper.traces
|
39
|
+
|
40
|
+
trace_to_show = 'Application Trace'
|
41
|
+
if traces[trace_to_show].empty? && wrapper.rescue_template != 'routing_error'
|
42
|
+
trace_to_show = 'Full Trace'
|
43
|
+
end
|
44
|
+
|
45
|
+
if source_to_show = traces[trace_to_show].first
|
46
|
+
source_to_show_id = source_to_show[:id]
|
47
|
+
end
|
48
|
+
|
37
49
|
template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
|
38
|
-
:request
|
39
|
-
:
|
40
|
-
:
|
41
|
-
:
|
42
|
-
:
|
43
|
-
:
|
44
|
-
:
|
45
|
-
:
|
46
|
-
:
|
50
|
+
request: request,
|
51
|
+
exception: wrapper.exception,
|
52
|
+
traces: traces,
|
53
|
+
show_source_idx: source_to_show_id,
|
54
|
+
trace_to_show: trace_to_show,
|
55
|
+
routes_inspector: routes_inspector(exception),
|
56
|
+
source_extracts: wrapper.source_extracts,
|
57
|
+
line_number: wrapper.line_number,
|
58
|
+
file: wrapper.file
|
47
59
|
)
|
48
60
|
file = "rescues/#{wrapper.rescue_template}"
|
49
|
-
|
50
|
-
|
61
|
+
|
62
|
+
if request.xhr?
|
63
|
+
body = template.render(template: file, layout: false, formats: [:text])
|
64
|
+
format = "text/plain"
|
65
|
+
else
|
66
|
+
body = template.render(template: file, layout: 'rescues/layout')
|
67
|
+
format = "text/html"
|
68
|
+
end
|
69
|
+
render(wrapper.status_code, body, format)
|
51
70
|
else
|
52
71
|
raise exception
|
53
72
|
end
|
54
73
|
end
|
55
74
|
|
56
|
-
def render(status, body)
|
57
|
-
[status, {'Content-Type' => "
|
75
|
+
def render(status, body, format)
|
76
|
+
[status, {'Content-Type' => "#{format}; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
|
58
77
|
end
|
59
78
|
|
60
79
|
def log_error(env, wrapper)
|
@@ -1,21 +1,22 @@
|
|
1
1
|
require 'action_controller/metal/exceptions'
|
2
|
-
require 'active_support/core_ext/
|
2
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
3
3
|
|
4
4
|
module ActionDispatch
|
5
5
|
class ExceptionWrapper
|
6
6
|
cattr_accessor :rescue_responses
|
7
7
|
@@rescue_responses = Hash.new(:internal_server_error)
|
8
8
|
@@rescue_responses.merge!(
|
9
|
-
'ActionController::RoutingError'
|
10
|
-
'AbstractController::ActionNotFound'
|
11
|
-
'ActionController::MethodNotAllowed'
|
12
|
-
'ActionController::UnknownHttpMethod'
|
13
|
-
'ActionController::NotImplemented'
|
14
|
-
'ActionController::UnknownFormat'
|
15
|
-
'ActionController::InvalidAuthenticityToken'
|
16
|
-
'
|
17
|
-
'
|
18
|
-
'ActionController::
|
9
|
+
'ActionController::RoutingError' => :not_found,
|
10
|
+
'AbstractController::ActionNotFound' => :not_found,
|
11
|
+
'ActionController::MethodNotAllowed' => :method_not_allowed,
|
12
|
+
'ActionController::UnknownHttpMethod' => :method_not_allowed,
|
13
|
+
'ActionController::NotImplemented' => :not_implemented,
|
14
|
+
'ActionController::UnknownFormat' => :not_acceptable,
|
15
|
+
'ActionController::InvalidAuthenticityToken' => :unprocessable_entity,
|
16
|
+
'ActionController::InvalidCrossOriginRequest' => :unprocessable_entity,
|
17
|
+
'ActionDispatch::ParamsParser::ParseError' => :bad_request,
|
18
|
+
'ActionController::BadRequest' => :bad_request,
|
19
|
+
'ActionController::ParameterMissing' => :bad_request
|
19
20
|
)
|
20
21
|
|
21
22
|
cattr_accessor :rescue_templates
|
@@ -32,6 +33,8 @@ module ActionDispatch
|
|
32
33
|
def initialize(env, exception)
|
33
34
|
@env = env
|
34
35
|
@exception = original_exception(exception)
|
36
|
+
|
37
|
+
expand_backtrace if exception.is_a?(SyntaxError) || exception.try(:original_exception).try(:is_a?, SyntaxError)
|
35
38
|
end
|
36
39
|
|
37
40
|
def rescue_template
|
@@ -54,21 +57,52 @@ module ActionDispatch
|
|
54
57
|
clean_backtrace(:all)
|
55
58
|
end
|
56
59
|
|
60
|
+
def traces
|
61
|
+
appplication_trace_with_ids = []
|
62
|
+
framework_trace_with_ids = []
|
63
|
+
full_trace_with_ids = []
|
64
|
+
|
65
|
+
full_trace.each_with_index do |trace, idx|
|
66
|
+
trace_with_id = { id: idx, trace: trace }
|
67
|
+
|
68
|
+
if application_trace.include?(trace)
|
69
|
+
appplication_trace_with_ids << trace_with_id
|
70
|
+
else
|
71
|
+
framework_trace_with_ids << trace_with_id
|
72
|
+
end
|
73
|
+
|
74
|
+
full_trace_with_ids << trace_with_id
|
75
|
+
end
|
76
|
+
|
77
|
+
{
|
78
|
+
"Application Trace" => appplication_trace_with_ids,
|
79
|
+
"Framework Trace" => framework_trace_with_ids,
|
80
|
+
"Full Trace" => full_trace_with_ids
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
57
84
|
def self.status_code_for_exception(class_name)
|
58
85
|
Rack::Utils.status_code(@@rescue_responses[class_name])
|
59
86
|
end
|
60
87
|
|
61
|
-
def
|
62
|
-
|
63
|
-
file, line
|
64
|
-
|
65
|
-
|
66
|
-
|
88
|
+
def source_extracts
|
89
|
+
backtrace.map do |trace|
|
90
|
+
file, line = trace.split(":")
|
91
|
+
line_number = line.to_i
|
92
|
+
|
93
|
+
{
|
94
|
+
code: source_fragment(file, line_number),
|
95
|
+
line_number: line_number
|
96
|
+
}
|
67
97
|
end
|
68
98
|
end
|
69
99
|
|
70
100
|
private
|
71
101
|
|
102
|
+
def backtrace
|
103
|
+
Array(@exception.backtrace)
|
104
|
+
end
|
105
|
+
|
72
106
|
def original_exception(exception)
|
73
107
|
if registered_original_exception?(exception)
|
74
108
|
exception.original_exception
|
@@ -83,9 +117,9 @@ module ActionDispatch
|
|
83
117
|
|
84
118
|
def clean_backtrace(*args)
|
85
119
|
if backtrace_cleaner
|
86
|
-
backtrace_cleaner.clean(
|
120
|
+
backtrace_cleaner.clean(backtrace, *args)
|
87
121
|
else
|
88
|
-
|
122
|
+
backtrace
|
89
123
|
end
|
90
124
|
end
|
91
125
|
|
@@ -96,7 +130,7 @@ module ActionDispatch
|
|
96
130
|
def source_fragment(path, line)
|
97
131
|
return unless Rails.respond_to?(:root) && Rails.root
|
98
132
|
full_path = Rails.root.join(path)
|
99
|
-
if File.
|
133
|
+
if File.exist?(full_path)
|
100
134
|
File.open(full_path, "r") do |file|
|
101
135
|
start = [line - 3, 0].max
|
102
136
|
lines = file.each_line.drop(start).take(6)
|
@@ -104,5 +138,11 @@ module ActionDispatch
|
|
104
138
|
end
|
105
139
|
end
|
106
140
|
end
|
141
|
+
|
142
|
+
def expand_backtrace
|
143
|
+
@exception.backtrace.unshift(
|
144
|
+
@exception.to_s.split("\n")
|
145
|
+
).flatten!
|
146
|
+
end
|
107
147
|
end
|
108
148
|
end
|