actionpack 3.2.19 → 4.0.0
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 +7 -0
- data/CHANGELOG.md +850 -401
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -288
- data/lib/abstract_controller/asset_paths.rb +2 -2
- data/lib/abstract_controller/base.rb +39 -37
- data/lib/abstract_controller/callbacks.rb +101 -82
- data/lib/abstract_controller/collector.rb +7 -3
- data/lib/abstract_controller/helpers.rb +25 -13
- data/lib/abstract_controller/layouts.rb +74 -74
- data/lib/abstract_controller/logger.rb +1 -2
- data/lib/abstract_controller/rendering.rb +30 -13
- data/lib/abstract_controller/translation.rb +16 -1
- data/lib/abstract_controller/url_for.rb +6 -6
- data/lib/abstract_controller/view_paths.rb +1 -1
- data/lib/abstract_controller.rb +1 -8
- data/lib/action_controller/base.rb +46 -22
- data/lib/action_controller/caching/fragments.rb +23 -53
- data/lib/action_controller/caching.rb +46 -33
- data/lib/action_controller/deprecated/integration_test.rb +3 -0
- data/lib/action_controller/deprecated.rb +5 -1
- data/lib/action_controller/log_subscriber.rb +16 -8
- data/lib/action_controller/metal/conditional_get.rb +76 -32
- data/lib/action_controller/metal/data_streaming.rb +20 -26
- data/lib/action_controller/metal/exceptions.rb +19 -6
- data/lib/action_controller/metal/flash.rb +24 -9
- data/lib/action_controller/metal/force_ssl.rb +70 -12
- data/lib/action_controller/metal/head.rb +25 -4
- data/lib/action_controller/metal/helpers.rb +5 -9
- data/lib/action_controller/metal/hide_actions.rb +0 -1
- data/lib/action_controller/metal/http_authentication.rb +107 -83
- data/lib/action_controller/metal/implicit_render.rb +1 -1
- data/lib/action_controller/metal/instrumentation.rb +2 -1
- data/lib/action_controller/metal/live.rb +175 -0
- data/lib/action_controller/metal/mime_responds.rb +161 -47
- data/lib/action_controller/metal/params_wrapper.rb +112 -74
- data/lib/action_controller/metal/rack_delegation.rb +9 -3
- data/lib/action_controller/metal/redirecting.rb +15 -20
- data/lib/action_controller/metal/renderers.rb +11 -9
- data/lib/action_controller/metal/rendering.rb +9 -1
- data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
- data/lib/action_controller/metal/responder.rb +20 -19
- data/lib/action_controller/metal/streaming.rb +12 -18
- data/lib/action_controller/metal/strong_parameters.rb +520 -0
- data/lib/action_controller/metal/testing.rb +13 -18
- data/lib/action_controller/metal/url_for.rb +28 -25
- data/lib/action_controller/metal.rb +17 -32
- data/lib/action_controller/model_naming.rb +12 -0
- data/lib/action_controller/railtie.rb +33 -17
- data/lib/action_controller/railties/helpers.rb +22 -0
- data/lib/action_controller/record_identifier.rb +18 -72
- data/lib/action_controller/test_case.rb +251 -131
- data/lib/action_controller/vendor/html-scanner.rb +4 -19
- data/lib/action_controller.rb +15 -6
- data/lib/action_dispatch/http/cache.rb +63 -11
- data/lib/action_dispatch/http/filter_parameters.rb +18 -8
- data/lib/action_dispatch/http/filter_redirect.rb +37 -0
- data/lib/action_dispatch/http/headers.rb +49 -17
- data/lib/action_dispatch/http/mime_negotiation.rb +24 -1
- data/lib/action_dispatch/http/mime_type.rb +154 -100
- data/lib/action_dispatch/http/mime_types.rb +1 -1
- data/lib/action_dispatch/http/parameter_filter.rb +44 -46
- data/lib/action_dispatch/http/parameters.rb +28 -28
- data/lib/action_dispatch/http/rack_cache.rb +2 -3
- data/lib/action_dispatch/http/request.rb +64 -18
- data/lib/action_dispatch/http/response.rb +130 -35
- data/lib/action_dispatch/http/upload.rb +63 -20
- data/lib/action_dispatch/http/url.rb +98 -35
- data/lib/action_dispatch/journey/backwards.rb +5 -0
- data/lib/action_dispatch/journey/formatter.rb +146 -0
- data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
- data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
- data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
- data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
- data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
- data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
- data/lib/action_dispatch/journey/nodes/node.rb +124 -0
- data/lib/action_dispatch/journey/parser.rb +206 -0
- data/lib/action_dispatch/journey/parser.y +47 -0
- data/lib/action_dispatch/journey/parser_extras.rb +23 -0
- data/lib/action_dispatch/journey/path/pattern.rb +196 -0
- data/lib/action_dispatch/journey/route.rb +124 -0
- data/lib/action_dispatch/journey/router/strexp.rb +24 -0
- data/lib/action_dispatch/journey/router/utils.rb +54 -0
- data/lib/action_dispatch/journey/router.rb +166 -0
- data/lib/action_dispatch/journey/routes.rb +75 -0
- data/lib/action_dispatch/journey/scanner.rb +61 -0
- data/lib/action_dispatch/journey/visitors.rb +197 -0
- data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
- data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
- data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
- data/lib/action_dispatch/journey.rb +5 -0
- data/lib/action_dispatch/middleware/callbacks.rb +9 -4
- data/lib/action_dispatch/middleware/cookies.rb +259 -114
- data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
- data/lib/action_dispatch/middleware/exception_wrapper.rb +29 -3
- data/lib/action_dispatch/middleware/flash.rb +58 -58
- data/lib/action_dispatch/middleware/params_parser.rb +14 -29
- data/lib/action_dispatch/middleware/public_exceptions.rb +30 -14
- data/lib/action_dispatch/middleware/reloader.rb +6 -6
- data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
- data/lib/action_dispatch/middleware/request_id.rb +2 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
- data/lib/action_dispatch/middleware/session/cookie_store.rb +82 -28
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
- data/lib/action_dispatch/middleware/ssl.rb +70 -0
- data/lib/action_dispatch/middleware/stack.rb +6 -1
- data/lib/action_dispatch/middleware/static.rb +2 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +7 -9
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +127 -5
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
- data/lib/action_dispatch/railtie.rb +16 -6
- data/lib/action_dispatch/request/session.rb +181 -0
- data/lib/action_dispatch/routing/inspector.rb +240 -0
- data/lib/action_dispatch/routing/mapper.rb +540 -291
- data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
- data/lib/action_dispatch/routing/redirection.rb +46 -29
- data/lib/action_dispatch/routing/route_set.rb +207 -164
- data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
- data/lib/action_dispatch/routing/url_for.rb +48 -33
- data/lib/action_dispatch/routing.rb +48 -83
- data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
- data/lib/action_dispatch/testing/assertions/response.rb +32 -40
- data/lib/action_dispatch/testing/assertions/routing.rb +42 -41
- data/lib/action_dispatch/testing/assertions/selector.rb +17 -22
- data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
- data/lib/action_dispatch/testing/integration.rb +65 -51
- data/lib/action_dispatch/testing/test_process.rb +9 -6
- data/lib/action_dispatch/testing/test_request.rb +7 -3
- data/lib/action_dispatch.rb +21 -15
- data/lib/action_pack/version.rb +7 -6
- data/lib/action_pack.rb +1 -1
- data/lib/action_view/base.rb +15 -34
- data/lib/action_view/buffers.rb +7 -1
- data/lib/action_view/context.rb +4 -4
- data/lib/action_view/dependency_tracker.rb +93 -0
- data/lib/action_view/digestor.rb +85 -0
- data/lib/action_view/flows.rb +1 -4
- data/lib/action_view/helpers/active_model_helper.rb +3 -4
- data/lib/action_view/helpers/asset_tag_helper.rb +215 -352
- data/lib/action_view/helpers/asset_url_helper.rb +355 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
- data/lib/action_view/helpers/cache_helper.rb +150 -18
- data/lib/action_view/helpers/capture_helper.rb +44 -31
- data/lib/action_view/helpers/csrf_helper.rb +0 -2
- data/lib/action_view/helpers/date_helper.rb +269 -248
- data/lib/action_view/helpers/debug_helper.rb +10 -11
- data/lib/action_view/helpers/form_helper.rb +931 -537
- data/lib/action_view/helpers/form_options_helper.rb +341 -166
- data/lib/action_view/helpers/form_tag_helper.rb +190 -90
- data/lib/action_view/helpers/javascript_helper.rb +23 -16
- data/lib/action_view/helpers/number_helper.rb +148 -329
- data/lib/action_view/helpers/output_safety_helper.rb +3 -3
- data/lib/action_view/helpers/record_tag_helper.rb +17 -22
- data/lib/action_view/helpers/rendering_helper.rb +2 -2
- data/lib/action_view/helpers/sanitize_helper.rb +3 -6
- data/lib/action_view/helpers/tag_helper.rb +46 -33
- data/lib/action_view/helpers/tags/base.rb +147 -0
- data/lib/action_view/helpers/tags/check_box.rb +64 -0
- data/lib/action_view/helpers/tags/checkable.rb +16 -0
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
- data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
- data/lib/action_view/helpers/tags/collection_select.rb +28 -0
- data/lib/action_view/helpers/tags/color_field.rb +25 -0
- data/lib/action_view/helpers/tags/date_field.rb +13 -0
- data/lib/action_view/helpers/tags/date_select.rb +72 -0
- data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
- data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
- data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
- data/lib/action_view/helpers/tags/email_field.rb +8 -0
- data/lib/action_view/helpers/tags/file_field.rb +8 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
- data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
- data/lib/action_view/helpers/tags/label.rb +65 -0
- data/lib/action_view/helpers/tags/month_field.rb +13 -0
- data/lib/action_view/helpers/tags/number_field.rb +18 -0
- data/lib/action_view/helpers/tags/password_field.rb +12 -0
- data/lib/action_view/helpers/tags/radio_button.rb +31 -0
- data/lib/action_view/helpers/tags/range_field.rb +8 -0
- data/lib/action_view/helpers/tags/search_field.rb +24 -0
- data/lib/action_view/helpers/tags/select.rb +40 -0
- data/lib/action_view/helpers/tags/tel_field.rb +8 -0
- data/lib/action_view/helpers/tags/text_area.rb +18 -0
- data/lib/action_view/helpers/tags/text_field.rb +29 -0
- data/lib/action_view/helpers/tags/time_field.rb +13 -0
- data/lib/action_view/helpers/tags/time_select.rb +8 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
- data/lib/action_view/helpers/tags/url_field.rb +8 -0
- data/lib/action_view/helpers/tags/week_field.rb +13 -0
- data/lib/action_view/helpers/tags.rb +39 -0
- data/lib/action_view/helpers/text_helper.rb +130 -114
- data/lib/action_view/helpers/translation_helper.rb +32 -16
- data/lib/action_view/helpers/url_helper.rb +211 -270
- data/lib/action_view/helpers.rb +2 -4
- data/lib/action_view/locale/en.yml +1 -105
- data/lib/action_view/log_subscriber.rb +6 -4
- data/lib/action_view/lookup_context.rb +15 -28
- data/lib/action_view/model_naming.rb +12 -0
- data/lib/action_view/path_set.rb +8 -20
- data/lib/action_view/railtie.rb +6 -22
- data/lib/action_view/record_identifier.rb +84 -0
- data/lib/action_view/renderer/abstract_renderer.rb +25 -19
- data/lib/action_view/renderer/partial_renderer.rb +158 -81
- data/lib/action_view/renderer/renderer.rb +8 -12
- data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
- data/lib/action_view/renderer/template_renderer.rb +12 -10
- data/lib/action_view/routing_url_for.rb +107 -0
- data/lib/action_view/template/error.rb +22 -12
- data/lib/action_view/template/handlers/builder.rb +1 -1
- data/lib/action_view/template/handlers/erb.rb +40 -19
- data/lib/action_view/template/handlers/raw.rb +11 -0
- data/lib/action_view/template/handlers.rb +12 -9
- data/lib/action_view/template/resolver.rb +107 -53
- data/lib/action_view/template/text.rb +12 -8
- data/lib/action_view/template/types.rb +57 -0
- data/lib/action_view/template.rb +25 -23
- data/lib/action_view/test_case.rb +67 -42
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +13 -2
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +9 -9
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
- data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
- data/lib/action_view/vendor/html-scanner.rb +20 -0
- data/lib/action_view.rb +17 -8
- metadata +184 -214
- data/lib/action_controller/caching/actions.rb +0 -185
- data/lib/action_controller/caching/pages.rb +0 -187
- data/lib/action_controller/caching/sweeping.rb +0 -97
- data/lib/action_controller/deprecated/performance_test.rb +0 -1
- data/lib/action_controller/metal/compatibility.rb +0 -65
- data/lib/action_controller/metal/session_management.rb +0 -14
- data/lib/action_controller/railties/paths.rb +0 -25
- data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
- data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
- data/lib/action_dispatch/middleware/head.rb +0 -18
- data/lib/action_dispatch/middleware/rescue.rb +0 -26
- data/lib/action_dispatch/testing/performance_test.rb +0 -10
- data/lib/action_view/asset_paths.rb +0 -142
- data/lib/action_view/helpers/asset_paths.rb +0 -7
- data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
- data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
- data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
- data/lib/sprockets/assets.rake +0 -99
- data/lib/sprockets/bootstrap.rb +0 -37
- data/lib/sprockets/compressors.rb +0 -83
- data/lib/sprockets/helpers/isolated_helper.rb +0 -13
- data/lib/sprockets/helpers/rails_helper.rb +0 -182
- data/lib/sprockets/helpers.rb +0 -6
- data/lib/sprockets/railtie.rb +0 -62
- data/lib/sprockets/static_compiler.rb +0 -56
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
require 'securerandom'
|
|
2
2
|
require 'active_support/core_ext/string/access'
|
|
3
|
-
require 'active_support/core_ext/object/blank'
|
|
4
3
|
|
|
5
4
|
module ActionDispatch
|
|
6
5
|
# Makes a unique request id available to the action_dispatch.request_id env variable (which is then accessible through
|
|
@@ -19,10 +18,7 @@ module ActionDispatch
|
|
|
19
18
|
|
|
20
19
|
def call(env)
|
|
21
20
|
env["action_dispatch.request_id"] = external_request_id(env) || internal_request_id
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
headers["X-Request-Id"] = env["action_dispatch.request_id"]
|
|
25
|
-
[ status, headers, body ]
|
|
21
|
+
@app.call(env).tap { |_status, headers, _body| headers["X-Request-Id"] = env["action_dispatch.request_id"] }
|
|
26
22
|
end
|
|
27
23
|
|
|
28
24
|
private
|
|
@@ -33,7 +29,7 @@ module ActionDispatch
|
|
|
33
29
|
end
|
|
34
30
|
|
|
35
31
|
def internal_request_id
|
|
36
|
-
SecureRandom.
|
|
32
|
+
SecureRandom.uuid
|
|
37
33
|
end
|
|
38
34
|
end
|
|
39
35
|
end
|
|
@@ -2,37 +2,31 @@ require 'rack/utils'
|
|
|
2
2
|
require 'rack/request'
|
|
3
3
|
require 'rack/session/abstract/id'
|
|
4
4
|
require 'action_dispatch/middleware/cookies'
|
|
5
|
-
require '
|
|
5
|
+
require 'action_dispatch/request/session'
|
|
6
6
|
|
|
7
7
|
module ActionDispatch
|
|
8
8
|
module Session
|
|
9
9
|
class SessionRestoreError < StandardError #:nodoc:
|
|
10
|
-
|
|
10
|
+
attr_reader :original_exception
|
|
11
|
+
|
|
12
|
+
def initialize(const_error)
|
|
13
|
+
@original_exception = const_error
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
options = @env[Rack::Session::Abstract::ENV_SESSION_OPTIONS_KEY] if @env
|
|
16
|
-
options ||= {}
|
|
17
|
-
@by.send(:destroy_session, @env, options[:id], options) if @by
|
|
18
|
-
options[:id] = nil
|
|
19
|
-
@loaded = false
|
|
15
|
+
super("Session contains objects whose class definition isn't available.\n" +
|
|
16
|
+
"Remember to require the classes for all objects kept in the session.\n" +
|
|
17
|
+
"(Original exception: #{const_error.message} [#{const_error.class}])\n")
|
|
20
18
|
end
|
|
21
19
|
end
|
|
22
20
|
|
|
23
|
-
::Rack::Session::Abstract::SessionHash.send :include, DestroyableSession
|
|
24
|
-
|
|
25
21
|
module Compatibility
|
|
26
22
|
def initialize(app, options = {})
|
|
27
23
|
options[:key] ||= '_session_id'
|
|
28
|
-
# FIXME Rack's secret is not being used
|
|
29
|
-
options[:secret] ||= SecureRandom.hex(30)
|
|
30
24
|
super
|
|
31
25
|
end
|
|
32
26
|
|
|
33
27
|
def generate_sid
|
|
34
28
|
sid = SecureRandom.hex(16)
|
|
35
|
-
sid.encode!(
|
|
29
|
+
sid.encode!(Encoding::UTF_8)
|
|
36
30
|
sid
|
|
37
31
|
end
|
|
38
32
|
|
|
@@ -60,11 +54,8 @@ module ActionDispatch
|
|
|
60
54
|
begin
|
|
61
55
|
# Note that the regexp does not allow $1 to end with a ':'
|
|
62
56
|
$1.constantize
|
|
63
|
-
rescue LoadError, NameError =>
|
|
64
|
-
raise ActionDispatch::Session::SessionRestoreError,
|
|
65
|
-
"Session contains objects whose class definition isn't available.\n" +
|
|
66
|
-
"Remember to require the classes for all objects kept in the session.\n" +
|
|
67
|
-
"(Original exception: #{const_error.message} [#{const_error.class}])\n"
|
|
57
|
+
rescue LoadError, NameError => e
|
|
58
|
+
raise ActionDispatch::Session::SessionRestoreError, e, e.backtrace
|
|
68
59
|
end
|
|
69
60
|
retry
|
|
70
61
|
else
|
|
@@ -73,9 +64,20 @@ module ActionDispatch
|
|
|
73
64
|
end
|
|
74
65
|
end
|
|
75
66
|
|
|
67
|
+
module SessionObject # :nodoc:
|
|
68
|
+
def prepare_session(env)
|
|
69
|
+
Request::Session.create(self, env, @default_options)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def loaded_session?(session)
|
|
73
|
+
!session.is_a?(Request::Session) || session.loaded?
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
76
77
|
class AbstractStore < Rack::Session::Abstract::ID
|
|
77
78
|
include Compatibility
|
|
78
79
|
include StaleSessionCheck
|
|
80
|
+
include SessionObject
|
|
79
81
|
|
|
80
82
|
private
|
|
81
83
|
|
|
@@ -1,53 +1,92 @@
|
|
|
1
1
|
require 'active_support/core_ext/hash/keys'
|
|
2
|
-
require 'active_support/core_ext/object/blank'
|
|
3
2
|
require 'action_dispatch/middleware/session/abstract_store'
|
|
4
3
|
require 'rack/session/cookie'
|
|
5
4
|
|
|
6
5
|
module ActionDispatch
|
|
7
6
|
module Session
|
|
8
|
-
# This cookie-based session store is the Rails default.
|
|
9
|
-
#
|
|
10
|
-
# size limit. Cookie-based sessions are dramatically faster than the
|
|
11
|
-
# alternatives.
|
|
7
|
+
# This cookie-based session store is the Rails default. It is
|
|
8
|
+
# dramatically faster than the alternatives.
|
|
12
9
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
10
|
+
# Sessions typically contain at most a user_id and flash message; both fit
|
|
11
|
+
# within the 4K cookie size limit. A CookieOverflow exception is raised if
|
|
12
|
+
# you attempt to store more than 4K of data.
|
|
15
13
|
#
|
|
16
|
-
#
|
|
14
|
+
# The cookie jar used for storage is automatically configured to be the
|
|
15
|
+
# best possible option given your application's configuration.
|
|
17
16
|
#
|
|
18
|
-
#
|
|
19
|
-
# a user cannot alter his +user_id+ without
|
|
20
|
-
#
|
|
21
|
-
#
|
|
17
|
+
# If you only have secret_token set, your cookies will be signed, but
|
|
18
|
+
# not encrypted. This means a user cannot alter his +user_id+ without
|
|
19
|
+
# knowing your app's secret key, but can easily read his +user_id+. This
|
|
20
|
+
# was the default for Rails 3 apps.
|
|
22
21
|
#
|
|
23
|
-
#
|
|
22
|
+
# If you have secret_key_base set, your cookies will be encrypted. This
|
|
23
|
+
# goes a step further than signed cookies in that encrypted cookies cannot
|
|
24
|
+
# be altered or read by users. This is the default starting in Rails 4.
|
|
24
25
|
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# more than 30 characters.
|
|
26
|
+
# If you have both secret_token and secret_key base set, your cookies will
|
|
27
|
+
# be encrypted, and signed cookies generated by Rails 3 will be
|
|
28
|
+
# transparently read and encrypted to provide a smooth upgrade path.
|
|
29
29
|
#
|
|
30
|
-
#
|
|
30
|
+
# Configure your session store in config/initializers/session_store.rb:
|
|
31
31
|
#
|
|
32
|
-
#
|
|
33
|
-
# integrity defaults to 'SHA1' but may be any digest provided by OpenSSL,
|
|
34
|
-
# such as 'MD5', 'RIPEMD160', 'SHA256', etc.
|
|
32
|
+
# Myapp::Application.config.session_store :cookie_store, key: '_your_app_session'
|
|
35
33
|
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
34
|
+
# Configure your secret key in config/initializers/secret_token.rb:
|
|
35
|
+
#
|
|
36
|
+
# Myapp::Application.config.secret_key_base 'secret key'
|
|
37
|
+
#
|
|
38
|
+
# To generate a secret key for an existing application, run `rake secret`.
|
|
39
|
+
#
|
|
40
|
+
# If you are upgrading an existing Rails 3 app, you should leave your
|
|
41
|
+
# existing secret_token in place and simply add the new secret_key_base.
|
|
42
|
+
# Note that you should wait to set secret_key_base until you have 100% of
|
|
43
|
+
# your userbase on Rails 4 and are reasonably sure you will not need to
|
|
44
|
+
# rollback to Rails 3. This is because cookies signed based on the new
|
|
45
|
+
# secret_key_base in Rails 4 are not backwards compatible with Rails 3.
|
|
46
|
+
# You are free to leave your existing secret_token in place, not set the
|
|
47
|
+
# new secret_key_base, and ignore the deprecation warnings until you are
|
|
48
|
+
# reasonably sure that your upgrade is otherwise complete. Additionally,
|
|
49
|
+
# you should take care to make sure you are not relying on the ability to
|
|
50
|
+
# decode signed cookies generated by your app in external applications or
|
|
51
|
+
# Javascript before upgrading.
|
|
38
52
|
#
|
|
39
53
|
# Note that changing digest or secret invalidates all existing sessions!
|
|
40
|
-
class CookieStore < Rack::Session::
|
|
54
|
+
class CookieStore < Rack::Session::Abstract::ID
|
|
41
55
|
include Compatibility
|
|
42
56
|
include StaleSessionCheck
|
|
57
|
+
include SessionObject
|
|
58
|
+
|
|
59
|
+
def initialize(app, options={})
|
|
60
|
+
super(app, options.merge!(:cookie_only => true))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def destroy_session(env, session_id, options)
|
|
64
|
+
new_sid = generate_sid unless options[:drop]
|
|
65
|
+
# Reset hash and Assign the new session id
|
|
66
|
+
env["action_dispatch.request.unsigned_session_cookie"] = new_sid ? { "session_id" => new_sid } : {}
|
|
67
|
+
new_sid
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def load_session(env)
|
|
71
|
+
stale_session_check! do
|
|
72
|
+
data = unpacked_cookie_data(env)
|
|
73
|
+
data = persistent_session_id!(data)
|
|
74
|
+
[data["session_id"], data]
|
|
75
|
+
end
|
|
76
|
+
end
|
|
43
77
|
|
|
44
78
|
private
|
|
45
79
|
|
|
80
|
+
def extract_session_id(env)
|
|
81
|
+
stale_session_check! do
|
|
82
|
+
unpacked_cookie_data(env)["session_id"]
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
46
86
|
def unpacked_cookie_data(env)
|
|
47
87
|
env["action_dispatch.request.unsigned_session_cookie"] ||= begin
|
|
48
88
|
stale_session_check! do
|
|
49
|
-
|
|
50
|
-
if data = request.cookie_jar.signed[@key]
|
|
89
|
+
if data = get_cookie(env)
|
|
51
90
|
data.stringify_keys!
|
|
52
91
|
end
|
|
53
92
|
data || {}
|
|
@@ -55,13 +94,28 @@ module ActionDispatch
|
|
|
55
94
|
end
|
|
56
95
|
end
|
|
57
96
|
|
|
97
|
+
def persistent_session_id!(data, sid=nil)
|
|
98
|
+
data ||= {}
|
|
99
|
+
data["session_id"] ||= sid || generate_sid
|
|
100
|
+
data
|
|
101
|
+
end
|
|
102
|
+
|
|
58
103
|
def set_session(env, sid, session_data, options)
|
|
59
|
-
session_data
|
|
104
|
+
session_data["session_id"] = sid
|
|
105
|
+
session_data
|
|
60
106
|
end
|
|
61
107
|
|
|
62
108
|
def set_cookie(env, session_id, cookie)
|
|
109
|
+
cookie_jar(env)[@key] = cookie
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def get_cookie(env)
|
|
113
|
+
cookie_jar(env)[@key]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def cookie_jar(env)
|
|
63
117
|
request = ActionDispatch::Request.new(env)
|
|
64
|
-
request.cookie_jar.
|
|
118
|
+
request.cookie_jar.signed_or_encrypted
|
|
65
119
|
end
|
|
66
120
|
end
|
|
67
121
|
end
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
require 'action_dispatch/middleware/session/abstract_store'
|
|
2
|
-
|
|
2
|
+
begin
|
|
3
|
+
require 'rack/session/dalli'
|
|
4
|
+
rescue LoadError => e
|
|
5
|
+
$stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install"
|
|
6
|
+
raise e
|
|
7
|
+
end
|
|
3
8
|
|
|
4
9
|
module ActionDispatch
|
|
5
10
|
module Session
|
|
6
|
-
class MemCacheStore < Rack::Session::
|
|
11
|
+
class MemCacheStore < Rack::Session::Dalli
|
|
7
12
|
include Compatibility
|
|
8
13
|
include StaleSessionCheck
|
|
14
|
+
include SessionObject
|
|
9
15
|
|
|
10
16
|
def initialize(app, options = {})
|
|
11
|
-
require 'memcache'
|
|
12
17
|
options[:expire_after] ||= options[:expires]
|
|
13
18
|
super
|
|
14
19
|
end
|
|
@@ -1,73 +1,40 @@
|
|
|
1
1
|
require 'action_dispatch/http/request'
|
|
2
2
|
require 'action_dispatch/middleware/exception_wrapper'
|
|
3
|
-
require 'active_support/deprecation'
|
|
4
3
|
|
|
5
4
|
module ActionDispatch
|
|
6
5
|
# This middleware rescues any exception returned by the application
|
|
7
6
|
# and calls an exceptions app that will wrap it in a format for the end user.
|
|
8
7
|
#
|
|
9
8
|
# The exceptions app should be passed as parameter on initialization
|
|
10
|
-
# of ShowExceptions.
|
|
9
|
+
# of ShowExceptions. Every time there is an exception, ShowExceptions will
|
|
11
10
|
# store the exception in env["action_dispatch.exception"], rewrite the
|
|
12
11
|
# PATH_INFO to the exception status code and call the rack app.
|
|
13
|
-
#
|
|
12
|
+
#
|
|
14
13
|
# If the application returns a "X-Cascade" pass response, this middleware
|
|
15
14
|
# will send an empty response as result with the correct status code.
|
|
16
15
|
# If any exception happens inside the exceptions app, this middleware
|
|
17
16
|
# catches the exceptions and returns a FAILSAFE_RESPONSE.
|
|
18
17
|
class ShowExceptions
|
|
19
|
-
FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/
|
|
20
|
-
["
|
|
21
|
-
"If you are the administrator of this website, then please read this web "
|
|
22
|
-
"application's log file and/or the web server's log file to find out what "
|
|
23
|
-
"went wrong
|
|
24
|
-
|
|
25
|
-
class << self
|
|
26
|
-
def rescue_responses
|
|
27
|
-
ActiveSupport::Deprecation.warn "ActionDispatch::ShowExceptions.rescue_responses is deprecated. " \
|
|
28
|
-
"Please configure your exceptions using a railtie or in your application config instead."
|
|
29
|
-
ExceptionWrapper.rescue_responses
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def rescue_templates
|
|
33
|
-
ActiveSupport::Deprecation.warn "ActionDispatch::ShowExceptions.rescue_templates is deprecated. " \
|
|
34
|
-
"Please configure your exceptions using a railtie or in your application config instead."
|
|
35
|
-
ExceptionWrapper.rescue_templates
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def initialize(app, exceptions_app = nil)
|
|
40
|
-
if [true, false].include?(exceptions_app)
|
|
41
|
-
ActiveSupport::Deprecation.warn "Passing consider_all_requests_local option to ActionDispatch::ShowExceptions middleware no longer works"
|
|
42
|
-
exceptions_app = nil
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
if exceptions_app.nil?
|
|
46
|
-
raise ArgumentError, "You need to pass an exceptions_app when initializing ActionDispatch::ShowExceptions. " \
|
|
47
|
-
"In case you want to render pages from a public path, you can use ActionDispatch::PublicExceptions.new('path/to/public')"
|
|
48
|
-
end
|
|
18
|
+
FAILSAFE_RESPONSE = [500, { 'Content-Type' => 'text/plain' },
|
|
19
|
+
["500 Internal Server Error\n" \
|
|
20
|
+
"If you are the administrator of this website, then please read this web " \
|
|
21
|
+
"application's log file and/or the web server's log file to find out what " \
|
|
22
|
+
"went wrong."]]
|
|
49
23
|
|
|
24
|
+
def initialize(app, exceptions_app)
|
|
50
25
|
@app = app
|
|
51
26
|
@exceptions_app = exceptions_app
|
|
52
27
|
end
|
|
53
28
|
|
|
54
29
|
def call(env)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
response || render_exception(env, exception)
|
|
30
|
+
@app.call(env)
|
|
31
|
+
rescue Exception => exception
|
|
32
|
+
raise exception if env['action_dispatch.show_exceptions'] == false
|
|
33
|
+
render_exception(env, exception)
|
|
62
34
|
end
|
|
63
35
|
|
|
64
36
|
private
|
|
65
37
|
|
|
66
|
-
# Define this method because some plugins were monkey patching it.
|
|
67
|
-
# Remove this after 3.2 is out with the other deprecations in this class.
|
|
68
|
-
def status_code(*)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
38
|
def render_exception(env, exception)
|
|
72
39
|
wrapper = ExceptionWrapper.new(env, exception)
|
|
73
40
|
status = wrapper.status_code
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module ActionDispatch
|
|
2
|
+
class SSL
|
|
3
|
+
YEAR = 31536000
|
|
4
|
+
|
|
5
|
+
def self.default_hsts_options
|
|
6
|
+
{ :expires => YEAR, :subdomains => false }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize(app, options = {})
|
|
10
|
+
@app = app
|
|
11
|
+
|
|
12
|
+
@hsts = options.fetch(:hsts, {})
|
|
13
|
+
@hsts = {} if @hsts == true
|
|
14
|
+
@hsts = self.class.default_hsts_options.merge(@hsts) if @hsts
|
|
15
|
+
|
|
16
|
+
@host = options[:host]
|
|
17
|
+
@port = options[:port]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call(env)
|
|
21
|
+
request = Request.new(env)
|
|
22
|
+
|
|
23
|
+
if request.ssl?
|
|
24
|
+
status, headers, body = @app.call(env)
|
|
25
|
+
headers = hsts_headers.merge(headers)
|
|
26
|
+
flag_cookies_as_secure!(headers)
|
|
27
|
+
[status, headers, body]
|
|
28
|
+
else
|
|
29
|
+
redirect_to_https(request)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
def redirect_to_https(request)
|
|
35
|
+
url = URI(request.url)
|
|
36
|
+
url.scheme = "https"
|
|
37
|
+
url.host = @host if @host
|
|
38
|
+
url.port = @port if @port
|
|
39
|
+
headers = hsts_headers.merge('Content-Type' => 'text/html',
|
|
40
|
+
'Location' => url.to_s)
|
|
41
|
+
|
|
42
|
+
[301, headers, []]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# http://tools.ietf.org/html/draft-hodges-strict-transport-sec-02
|
|
46
|
+
def hsts_headers
|
|
47
|
+
if @hsts
|
|
48
|
+
value = "max-age=#{@hsts[:expires].to_i}"
|
|
49
|
+
value += "; includeSubDomains" if @hsts[:subdomains]
|
|
50
|
+
{ 'Strict-Transport-Security' => value }
|
|
51
|
+
else
|
|
52
|
+
{}
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def flag_cookies_as_secure!(headers)
|
|
57
|
+
if cookies = headers['Set-Cookie']
|
|
58
|
+
cookies = cookies.split("\n")
|
|
59
|
+
|
|
60
|
+
headers['Set-Cookie'] = cookies.map { |cookie|
|
|
61
|
+
if cookie !~ /;\s+secure(;|$)/
|
|
62
|
+
"#{cookie}; secure"
|
|
63
|
+
else
|
|
64
|
+
cookie
|
|
65
|
+
end
|
|
66
|
+
}.join("\n")
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -75,6 +75,11 @@ module ActionDispatch
|
|
|
75
75
|
middlewares[i]
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
+
def unshift(*args, &block)
|
|
79
|
+
middleware = self.class::Middleware.new(*args, &block)
|
|
80
|
+
middlewares.unshift(middleware)
|
|
81
|
+
end
|
|
82
|
+
|
|
78
83
|
def initialize_copy(other)
|
|
79
84
|
self.middlewares = other.middlewares.dup
|
|
80
85
|
end
|
|
@@ -110,7 +115,7 @@ module ActionDispatch
|
|
|
110
115
|
def build(app = nil, &block)
|
|
111
116
|
app ||= block
|
|
112
117
|
raise "MiddlewareStack#build requires an app" unless app
|
|
113
|
-
middlewares.reverse.inject(app) { |a, e| e.build(a) }
|
|
118
|
+
middlewares.freeze.reverse.inject(app) { |a, e| e.build(a) }
|
|
114
119
|
end
|
|
115
120
|
|
|
116
121
|
protected
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'rack/utils'
|
|
2
|
+
require 'active_support/core_ext/uri'
|
|
2
3
|
|
|
3
4
|
module ActionDispatch
|
|
4
5
|
class FileHandler
|
|
@@ -29,7 +30,7 @@ module ActionDispatch
|
|
|
29
30
|
|
|
30
31
|
def ext
|
|
31
32
|
@ext ||= begin
|
|
32
|
-
ext = ::ActionController::Base.
|
|
33
|
+
ext = ::ActionController::Base.default_static_extension
|
|
33
34
|
"{,#{ext},/index#{ext}}"
|
|
34
35
|
end
|
|
35
36
|
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<% unless @exception.blamed_files.blank? %>
|
|
2
2
|
<% if (hide = @exception.blamed_files.length > 8) %>
|
|
3
|
-
<a href="#" onclick="
|
|
3
|
+
<a href="#" onclick="return toggleTrace()">Toggle blamed files</a>
|
|
4
4
|
<% end %>
|
|
5
|
-
<pre id="blame_trace" <%='style="display:none"' if hide %>><code><%=
|
|
5
|
+
<pre id="blame_trace" <%='style="display:none"' if hide %>><code><%= @exception.describe_blame %></code></pre>
|
|
6
6
|
<% end %>
|
|
7
7
|
|
|
8
8
|
<%
|
|
@@ -12,20 +12,23 @@
|
|
|
12
12
|
|
|
13
13
|
request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
|
|
14
14
|
|
|
15
|
-
def debug_hash(
|
|
16
|
-
|
|
15
|
+
def debug_hash(object)
|
|
16
|
+
object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
|
|
17
17
|
end unless self.class.method_defined?(:debug_hash)
|
|
18
18
|
%>
|
|
19
19
|
|
|
20
20
|
<h2 style="margin-top: 30px">Request</h2>
|
|
21
|
-
<p><b>Parameters</b
|
|
21
|
+
<p><b>Parameters</b>:</p> <pre><%= request_dump %></pre>
|
|
22
22
|
|
|
23
|
-
<
|
|
24
|
-
<div
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<div id="env_dump" style="display:none"><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></div>
|
|
23
|
+
<div class="details">
|
|
24
|
+
<div class="summary"><a href="#" onclick="return toggleSessionDump()">Toggle session dump</a></div>
|
|
25
|
+
<div id="session_dump" style="display:none"><pre><%= debug_hash @request.session %></pre></div>
|
|
26
|
+
</div>
|
|
28
27
|
|
|
28
|
+
<div class="details">
|
|
29
|
+
<div class="summary"><a href="#" onclick="return toggleEnvDump()">Toggle env dump</a></div>
|
|
30
|
+
<div id="env_dump" style="display:none"><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></div>
|
|
31
|
+
</div>
|
|
29
32
|
|
|
30
33
|
<h2 style="margin-top: 30px">Response</h2>
|
|
31
|
-
<p><b>Headers</b
|
|
34
|
+
<p><b>Headers</b>:</p> <pre><%= defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %></pre>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<% if @source_extract %>
|
|
2
|
+
<div class="source">
|
|
3
|
+
<div class="info">
|
|
4
|
+
Extracted source (around line <strong>#<%= @line_number %></strong>):
|
|
5
|
+
</div>
|
|
6
|
+
<div class="data">
|
|
7
|
+
<table cellpadding="0" cellspacing="0" class="lines">
|
|
8
|
+
<tr>
|
|
9
|
+
<td>
|
|
10
|
+
<pre class="line_numbers">
|
|
11
|
+
<% @source_extract.keys.each do |line_number| %>
|
|
12
|
+
<span><%= line_number -%></span>
|
|
13
|
+
<% end %>
|
|
14
|
+
</pre>
|
|
15
|
+
</td>
|
|
16
|
+
<td width="100%">
|
|
17
|
+
<pre>
|
|
18
|
+
<% @source_extract.each do |line, source| -%><div class="line<%= " active" if line == @line_number -%>"><%= source -%></div><% end -%>
|
|
19
|
+
</pre>
|
|
20
|
+
</td>
|
|
21
|
+
</tr>
|
|
22
|
+
</table>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<% end %>
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
<%
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
]
|
|
7
|
-
names = traces.collect {|name, trace| name}
|
|
2
|
+
traces = { "Application Trace" => @application_trace,
|
|
3
|
+
"Framework Trace" => @framework_trace,
|
|
4
|
+
"Full Trace" => @full_trace }
|
|
5
|
+
names = traces.keys
|
|
8
6
|
%>
|
|
9
7
|
|
|
10
8
|
<p><code>Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %></code></p>
|
|
@@ -12,15 +10,15 @@
|
|
|
12
10
|
<div id="traces">
|
|
13
11
|
<% names.each do |name| %>
|
|
14
12
|
<%
|
|
15
|
-
show = "
|
|
16
|
-
hide = (names - [name]).collect {|hide_name| "
|
|
13
|
+
show = "show('#{name.gsub(/\s/, '-')}');"
|
|
14
|
+
hide = (names - [name]).collect {|hide_name| "hide('#{hide_name.gsub(/\s/, '-')}');"}
|
|
17
15
|
%>
|
|
18
16
|
<a href="#" onclick="<%= hide.join %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %>
|
|
19
17
|
<% end %>
|
|
20
18
|
|
|
21
19
|
<% traces.each do |name, trace| %>
|
|
22
20
|
<div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == "Application Trace") ? 'block' : 'none' %>;">
|
|
23
|
-
<pre><code><%=
|
|
21
|
+
<pre><code><%= trace.join "\n" %></code></pre>
|
|
24
22
|
</div>
|
|
25
23
|
<% end %>
|
|
26
24
|
</div>
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
<header>
|
|
2
|
+
<h1>
|
|
3
|
+
<%= @exception.class.to_s %>
|
|
4
|
+
<% if @request.parameters['controller'] %>
|
|
5
|
+
in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
|
|
6
|
+
<% end %>
|
|
7
|
+
</h1>
|
|
8
|
+
</header>
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
<div id="container">
|
|
11
|
+
<h2><%= @exception.message %></h2>
|
|
12
|
+
|
|
13
|
+
<%= render template: "rescues/_source" %>
|
|
14
|
+
<%= render template: "rescues/_trace" %>
|
|
15
|
+
<%= render template: "rescues/_request_and_response" %>
|
|
16
|
+
</div>
|