actionpack 4.2.10 → 7.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +86 -600
- data/MIT-LICENSE +1 -1
- data/README.rdoc +13 -14
- data/lib/abstract_controller/asset_paths.rb +5 -1
- data/lib/abstract_controller/base.rb +166 -136
- data/lib/abstract_controller/caching/fragments.rb +149 -0
- data/lib/abstract_controller/caching.rb +68 -0
- data/lib/abstract_controller/callbacks.rb +126 -57
- data/lib/abstract_controller/collector.rb +13 -15
- data/lib/abstract_controller/deprecator.rb +9 -0
- data/lib/abstract_controller/error.rb +8 -0
- data/lib/abstract_controller/helpers.rb +181 -132
- data/lib/abstract_controller/logger.rb +5 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +10 -3
- data/lib/abstract_controller/rendering.rb +56 -56
- data/lib/abstract_controller/translation.rb +29 -15
- data/lib/abstract_controller/url_for.rb +15 -11
- data/lib/abstract_controller.rb +21 -5
- data/lib/action_controller/api/api_rendering.rb +18 -0
- data/lib/action_controller/api.rb +154 -0
- data/lib/action_controller/base.rb +219 -155
- data/lib/action_controller/caching.rb +28 -68
- data/lib/action_controller/deprecator.rb +9 -0
- data/lib/action_controller/form_builder.rb +55 -0
- data/lib/action_controller/log_subscriber.rb +35 -22
- data/lib/action_controller/metal/allow_browser.rb +119 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
- data/lib/action_controller/metal/conditional_get.rb +259 -122
- data/lib/action_controller/metal/content_security_policy.rb +86 -0
- data/lib/action_controller/metal/cookies.rb +9 -5
- data/lib/action_controller/metal/data_streaming.rb +87 -104
- data/lib/action_controller/metal/default_headers.rb +21 -0
- data/lib/action_controller/metal/etag_with_flash.rb +22 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +35 -26
- data/lib/action_controller/metal/exceptions.rb +71 -24
- data/lib/action_controller/metal/flash.rb +26 -19
- data/lib/action_controller/metal/head.rb +45 -36
- data/lib/action_controller/metal/helpers.rb +80 -64
- data/lib/action_controller/metal/http_authentication.rb +297 -244
- data/lib/action_controller/metal/implicit_render.rb +57 -9
- data/lib/action_controller/metal/instrumentation.rb +76 -64
- data/lib/action_controller/metal/live.rb +238 -176
- data/lib/action_controller/metal/logging.rb +22 -0
- data/lib/action_controller/metal/mime_responds.rb +177 -166
- data/lib/action_controller/metal/parameter_encoding.rb +84 -0
- data/lib/action_controller/metal/params_wrapper.rb +145 -118
- data/lib/action_controller/metal/permissions_policy.rb +38 -0
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +203 -64
- data/lib/action_controller/metal/renderers.rb +108 -65
- data/lib/action_controller/metal/rendering.rb +216 -56
- data/lib/action_controller/metal/request_forgery_protection.rb +496 -163
- data/lib/action_controller/metal/rescue.rb +19 -21
- data/lib/action_controller/metal/streaming.rb +179 -138
- data/lib/action_controller/metal/strong_parameters.rb +1058 -382
- data/lib/action_controller/metal/testing.rb +11 -17
- data/lib/action_controller/metal/url_for.rb +37 -21
- data/lib/action_controller/metal.rb +236 -138
- data/lib/action_controller/railtie.rb +89 -11
- data/lib/action_controller/railties/helpers.rb +5 -1
- data/lib/action_controller/renderer.rb +161 -0
- data/lib/action_controller/template_assertions.rb +13 -0
- data/lib/action_controller/test_case.rb +425 -497
- data/lib/action_controller.rb +44 -22
- data/lib/action_dispatch/constants.rb +34 -0
- data/lib/action_dispatch/deprecator.rb +9 -0
- data/lib/action_dispatch/http/cache.rb +119 -63
- data/lib/action_dispatch/http/content_disposition.rb +47 -0
- data/lib/action_dispatch/http/content_security_policy.rb +364 -0
- data/lib/action_dispatch/http/filter_parameters.rb +36 -34
- data/lib/action_dispatch/http/filter_redirect.rb +24 -12
- data/lib/action_dispatch/http/headers.rb +66 -31
- data/lib/action_dispatch/http/mime_negotiation.rb +106 -75
- data/lib/action_dispatch/http/mime_type.rb +196 -136
- data/lib/action_dispatch/http/mime_types.rb +25 -7
- data/lib/action_dispatch/http/parameters.rb +97 -45
- data/lib/action_dispatch/http/permissions_policy.rb +187 -0
- data/lib/action_dispatch/http/rack_cache.rb +6 -0
- data/lib/action_dispatch/http/request.rb +299 -170
- data/lib/action_dispatch/http/response.rb +311 -160
- data/lib/action_dispatch/http/upload.rb +52 -23
- data/lib/action_dispatch/http/url.rb +201 -125
- data/lib/action_dispatch/journey/formatter.rb +110 -50
- data/lib/action_dispatch/journey/gtg/builder.rb +37 -50
- data/lib/action_dispatch/journey/gtg/simulator.rb +20 -17
- data/lib/action_dispatch/journey/gtg/transition_table.rb +96 -36
- data/lib/action_dispatch/journey/nfa/dot.rb +5 -14
- data/lib/action_dispatch/journey/nodes/node.rb +100 -20
- data/lib/action_dispatch/journey/parser.rb +19 -17
- data/lib/action_dispatch/journey/parser.y +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +14 -4
- data/lib/action_dispatch/journey/path/pattern.rb +79 -63
- data/lib/action_dispatch/journey/route.rb +108 -44
- data/lib/action_dispatch/journey/router/utils.rb +41 -29
- data/lib/action_dispatch/journey/router.rb +64 -57
- data/lib/action_dispatch/journey/routes.rb +23 -21
- data/lib/action_dispatch/journey/scanner.rb +28 -17
- data/lib/action_dispatch/journey/visitors.rb +100 -54
- data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
- data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
- data/lib/action_dispatch/journey.rb +7 -5
- data/lib/action_dispatch/log_subscriber.rb +25 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
- data/lib/action_dispatch/middleware/callbacks.rb +7 -6
- data/lib/action_dispatch/middleware/cookies.rb +471 -328
- data/lib/action_dispatch/middleware/debug_exceptions.rb +149 -66
- data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
- data/lib/action_dispatch/middleware/debug_view.rb +73 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +275 -73
- data/lib/action_dispatch/middleware/executor.rb +32 -0
- data/lib/action_dispatch/middleware/flash.rb +143 -101
- data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +36 -27
- data/lib/action_dispatch/middleware/reloader.rb +10 -92
- data/lib/action_dispatch/middleware/remote_ip.rb +133 -107
- data/lib/action_dispatch/middleware/request_id.rb +29 -15
- data/lib/action_dispatch/middleware/server_timing.rb +78 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +49 -27
- data/lib/action_dispatch/middleware/session/cache_store.rb +33 -16
- data/lib/action_dispatch/middleware/session/cookie_store.rb +86 -80
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +66 -36
- data/lib/action_dispatch/middleware/ssl.rb +134 -36
- data/lib/action_dispatch/middleware/stack.rb +109 -44
- data/lib/action_dispatch/middleware/static.rb +159 -90
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +7 -24
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +139 -15
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +6 -6
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +9 -9
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +7 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +125 -93
- data/lib/action_dispatch/railtie.rb +44 -16
- data/lib/action_dispatch/request/session.rb +159 -69
- data/lib/action_dispatch/request/utils.rb +97 -23
- data/lib/action_dispatch/routing/endpoint.rb +11 -2
- data/lib/action_dispatch/routing/inspector.rb +195 -106
- data/lib/action_dispatch/routing/mapper.rb +1338 -955
- data/lib/action_dispatch/routing/polymorphic_routes.rb +234 -201
- data/lib/action_dispatch/routing/redirection.rb +78 -51
- data/lib/action_dispatch/routing/route_set.rb +460 -374
- data/lib/action_dispatch/routing/routes_proxy.rb +36 -12
- data/lib/action_dispatch/routing/url_for.rb +172 -124
- data/lib/action_dispatch/routing.rb +159 -158
- data/lib/action_dispatch/system_test_case.rb +206 -0
- data/lib/action_dispatch/system_testing/browser.rb +84 -0
- data/lib/action_dispatch/system_testing/driver.rb +85 -0
- data/lib/action_dispatch/system_testing/server.rb +33 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
- data/lib/action_dispatch/testing/assertion_response.rb +48 -0
- data/lib/action_dispatch/testing/assertions/response.rb +71 -39
- data/lib/action_dispatch/testing/assertions/routing.rb +228 -103
- data/lib/action_dispatch/testing/assertions.rb +9 -6
- data/lib/action_dispatch/testing/integration.rb +486 -306
- data/lib/action_dispatch/testing/request_encoder.rb +60 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +35 -22
- data/lib/action_dispatch/testing/test_request.rb +29 -34
- data/lib/action_dispatch/testing/test_response.rb +48 -15
- data/lib/action_dispatch.rb +82 -40
- data/lib/action_pack/gem_version.rb +8 -4
- data/lib/action_pack/version.rb +6 -2
- data/lib/action_pack.rb +21 -18
- metadata +146 -56
- data/lib/action_controller/caching/fragments.rb +0 -103
- data/lib/action_controller/metal/force_ssl.rb +0 -97
- data/lib/action_controller/metal/hide_actions.rb +0 -40
- data/lib/action_controller/metal/rack_delegation.rb +0 -32
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/model_naming.rb +0 -12
- data/lib/action_dispatch/http/parameter_filter.rb +0 -72
- data/lib/action_dispatch/journey/backwards.rb +0 -5
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
- data/lib/action_dispatch/journey/router/strexp.rb +0 -27
- data/lib/action_dispatch/middleware/params_parser.rb +0 -60
- data/lib/action_dispatch/middleware/templates/rescues/_source.erb +0 -27
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,123 +1,192 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :markup: markdown
|
4
|
+
|
5
|
+
require "rack/utils"
|
3
6
|
|
4
7
|
module ActionDispatch
|
5
|
-
#
|
6
|
-
# When initialized it can accept an optional 'Cache-Control' header which
|
7
|
-
# will be set when a response containing a file's contents is delivered.
|
8
|
+
# # Action Dispatch Static
|
8
9
|
#
|
9
|
-
# This middleware
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
10
|
+
# This middleware serves static files from disk, if available. If no file is
|
11
|
+
# found, it hands off to the main app.
|
12
|
+
#
|
13
|
+
# In Rails apps, this middleware is configured to serve assets from the
|
14
|
+
# `public/` directory.
|
15
|
+
#
|
16
|
+
# Only GET and HEAD requests are served. POST and other HTTP methods are handed
|
17
|
+
# off to the main app.
|
18
|
+
#
|
19
|
+
# Only files in the root directory are served; path traversal is denied.
|
20
|
+
class Static
|
21
|
+
def initialize(app, path, index: "index", headers: {})
|
22
|
+
@app = app
|
23
|
+
@file_handler = FileHandler.new(path, index: index, headers: headers)
|
24
|
+
end
|
25
|
+
|
26
|
+
def call(env)
|
27
|
+
@file_handler.attempt(env) || @app.call(env)
|
21
28
|
end
|
29
|
+
end
|
22
30
|
|
23
|
-
|
24
|
-
|
25
|
-
|
31
|
+
# # Action Dispatch FileHandler
|
32
|
+
#
|
33
|
+
# This endpoint serves static files from disk using `Rack::Files`.
|
34
|
+
#
|
35
|
+
# URL paths are matched with static files according to expected conventions:
|
36
|
+
# `path`, `path`.html, `path`/index.html.
|
37
|
+
#
|
38
|
+
# Precompressed versions of these files are checked first. Brotli (.br) and gzip
|
39
|
+
# (.gz) files are supported. If `path`.br exists, this endpoint returns that
|
40
|
+
# file with a `content-encoding: br` header.
|
41
|
+
#
|
42
|
+
# If no matching file is found, this endpoint responds `404 Not Found`.
|
43
|
+
#
|
44
|
+
# Pass the `root` directory to search for matching files, an optional `index:
|
45
|
+
# "index"` to change the default `path`/index.html, and optional additional
|
46
|
+
# response headers.
|
47
|
+
class FileHandler
|
48
|
+
# `Accept-Encoding` value -> file extension
|
49
|
+
PRECOMPRESSED = {
|
50
|
+
"br" => ".br",
|
51
|
+
"gzip" => ".gz",
|
52
|
+
"identity" => nil
|
53
|
+
}
|
26
54
|
|
27
|
-
|
28
|
-
|
29
|
-
|
55
|
+
def initialize(root, index: "index", headers: {}, precompressed: %i[ br gzip ], compressible_content_types: /\A(?:text\/|application\/javascript|image\/svg\+xml)/)
|
56
|
+
@root = root.chomp("/").b
|
57
|
+
@index = index
|
30
58
|
|
31
|
-
|
32
|
-
|
33
|
-
begin
|
34
|
-
File.file?(path) && File.readable?(path)
|
35
|
-
rescue SystemCallError
|
36
|
-
false
|
37
|
-
end
|
59
|
+
@precompressed = Array(precompressed).map(&:to_s) | %w[ identity ]
|
60
|
+
@compressible_content_types = compressible_content_types
|
38
61
|
|
39
|
-
|
40
|
-
return ::Rack::Utils.escape(match)
|
41
|
-
end
|
62
|
+
@file_server = ::Rack::Files.new(@root, headers)
|
42
63
|
end
|
43
64
|
|
44
65
|
def call(env)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
if gzip_path && gzip_encoding_accepted?(env)
|
49
|
-
env['PATH_INFO'] = gzip_path
|
50
|
-
status, headers, body = @file_server.call(env)
|
51
|
-
if status == 304
|
52
|
-
return [status, headers, body]
|
53
|
-
end
|
54
|
-
headers['Content-Encoding'] = 'gzip'
|
55
|
-
headers['Content-Type'] = content_type(path)
|
56
|
-
else
|
57
|
-
status, headers, body = @file_server.call(env)
|
58
|
-
end
|
66
|
+
attempt(env) || @file_server.call(env)
|
67
|
+
end
|
59
68
|
|
60
|
-
|
69
|
+
def attempt(env)
|
70
|
+
request = Rack::Request.new env
|
61
71
|
|
62
|
-
|
63
|
-
|
64
|
-
|
72
|
+
if request.get? || request.head?
|
73
|
+
if found = find_file(request.path_info, accept_encoding: request.accept_encoding)
|
74
|
+
serve request, *found
|
75
|
+
end
|
76
|
+
end
|
65
77
|
end
|
66
78
|
|
67
79
|
private
|
68
|
-
def
|
69
|
-
|
80
|
+
def serve(request, filepath, content_headers)
|
81
|
+
original, request.path_info =
|
82
|
+
request.path_info, ::Rack::Utils.escape_path(filepath).b
|
83
|
+
|
84
|
+
@file_server.call(request.env).tap do |status, headers, body|
|
85
|
+
# Omit content-encoding/type/etc headers for 304 Not Modified
|
86
|
+
if status != 304
|
87
|
+
headers.update(content_headers)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
ensure
|
91
|
+
request.path_info = original
|
70
92
|
end
|
71
93
|
|
72
|
-
|
73
|
-
|
94
|
+
# Match a URI path to a static file to be served.
|
95
|
+
#
|
96
|
+
# Used by the `Static` class to negotiate a servable file in the `public/`
|
97
|
+
# directory (see Static#call).
|
98
|
+
#
|
99
|
+
# Checks for `path`, `path`.html, and `path`/index.html files, in that order,
|
100
|
+
# including .br and .gzip compressed extensions.
|
101
|
+
#
|
102
|
+
# If a matching file is found, the path and necessary response headers
|
103
|
+
# (Content-Type, Content-Encoding) are returned.
|
104
|
+
def find_file(path_info, accept_encoding:)
|
105
|
+
each_candidate_filepath(path_info) do |filepath, content_type|
|
106
|
+
if response = try_files(filepath, content_type, accept_encoding: accept_encoding)
|
107
|
+
return response
|
108
|
+
end
|
109
|
+
end
|
74
110
|
end
|
75
111
|
|
76
|
-
def
|
77
|
-
|
112
|
+
def try_files(filepath, content_type, accept_encoding:)
|
113
|
+
headers = { Rack::CONTENT_TYPE => content_type }
|
114
|
+
|
115
|
+
if compressible? content_type
|
116
|
+
try_precompressed_files filepath, headers, accept_encoding: accept_encoding
|
117
|
+
elsif file_readable? filepath
|
118
|
+
[ filepath, headers ]
|
119
|
+
end
|
78
120
|
end
|
79
121
|
|
80
|
-
def
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
122
|
+
def try_precompressed_files(filepath, headers, accept_encoding:)
|
123
|
+
each_precompressed_filepath(filepath) do |content_encoding, precompressed_filepath|
|
124
|
+
if file_readable? precompressed_filepath
|
125
|
+
# Identity encoding is default, so we skip Accept-Encoding negotiation and
|
126
|
+
# needn't set Content-Encoding.
|
127
|
+
#
|
128
|
+
# Vary header is expected when we've found other available encodings that
|
129
|
+
# Accept-Encoding ruled out.
|
130
|
+
if content_encoding == "identity"
|
131
|
+
return precompressed_filepath, headers
|
132
|
+
else
|
133
|
+
headers[ActionDispatch::Constants::VARY] = "accept-encoding"
|
134
|
+
|
135
|
+
if accept_encoding.any? { |enc, _| /\b#{content_encoding}\b/i.match?(enc) }
|
136
|
+
headers[ActionDispatch::Constants::CONTENT_ENCODING] = content_encoding
|
137
|
+
return precompressed_filepath, headers
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
87
141
|
end
|
88
142
|
end
|
89
143
|
|
90
|
-
def
|
91
|
-
|
144
|
+
def file_readable?(path)
|
145
|
+
file_path = File.join(@root, path.b)
|
146
|
+
File.file?(file_path) && File.readable?(file_path)
|
92
147
|
end
|
93
|
-
end
|
94
148
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
# to serve assets from a server's `public/` directory.
|
99
|
-
#
|
100
|
-
# This middleware verifies the path to ensure that only files
|
101
|
-
# living in the root directory can be rendered. A request cannot
|
102
|
-
# produce a directory traversal using this middleware. Only 'GET' and 'HEAD'
|
103
|
-
# requests will result in a file being returned.
|
104
|
-
class Static
|
105
|
-
def initialize(app, path, cache_control=nil)
|
106
|
-
@app = app
|
107
|
-
@file_handler = FileHandler.new(path, cache_control)
|
108
|
-
end
|
149
|
+
def compressible?(content_type)
|
150
|
+
@compressible_content_types.match?(content_type)
|
151
|
+
end
|
109
152
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
if match = @file_handler.match?(path)
|
115
|
-
env["PATH_INFO"] = match
|
116
|
-
return @file_handler.call(env)
|
153
|
+
def each_precompressed_filepath(filepath)
|
154
|
+
@precompressed.each do |content_encoding|
|
155
|
+
precompressed_ext = PRECOMPRESSED.fetch(content_encoding)
|
156
|
+
yield content_encoding, "#{filepath}#{precompressed_ext}"
|
117
157
|
end
|
158
|
+
|
159
|
+
nil
|
118
160
|
end
|
119
161
|
|
120
|
-
|
121
|
-
|
162
|
+
def each_candidate_filepath(path_info)
|
163
|
+
return unless path = clean_path(path_info)
|
164
|
+
|
165
|
+
ext = ::File.extname(path)
|
166
|
+
content_type = ::Rack::Mime.mime_type(ext, nil)
|
167
|
+
yield path, content_type || "text/plain"
|
168
|
+
|
169
|
+
# Tack on .html and /index.html only for paths that don't have an explicit,
|
170
|
+
# resolvable file extension. No need to check for foo.js.html and
|
171
|
+
# foo.js/index.html.
|
172
|
+
unless content_type
|
173
|
+
default_ext = ::ActionController::Base.default_static_extension
|
174
|
+
if ext != default_ext
|
175
|
+
default_content_type = ::Rack::Mime.mime_type(default_ext, "text/plain")
|
176
|
+
|
177
|
+
yield "#{path}#{default_ext}", default_content_type
|
178
|
+
yield "#{path}/#{@index}#{default_ext}", default_content_type
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
nil
|
183
|
+
end
|
184
|
+
|
185
|
+
def clean_path(path_info)
|
186
|
+
path = ::Rack::Utils.unescape_path path_info.chomp("/")
|
187
|
+
if ::Rack::Utils.valid_path? path
|
188
|
+
::Rack::Utils.clean_path_info path
|
189
|
+
end
|
190
|
+
end
|
122
191
|
end
|
123
192
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<% actions = exception_wrapper.actions %>
|
2
|
+
|
3
|
+
<% if actions.any? %>
|
4
|
+
<div class="actions">
|
5
|
+
<% actions.each do |action, _| %>
|
6
|
+
<%= button_to action, ActionDispatch::ActionableExceptions.endpoint, params: {
|
7
|
+
error: exception_wrapper.exception_class_name,
|
8
|
+
action: action,
|
9
|
+
location: request.path
|
10
|
+
} %>
|
11
|
+
<% end %>
|
12
|
+
</div>
|
13
|
+
<% end %>
|
File without changes
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<% if exception_wrapper.has_corrections? %>
|
2
|
+
<div class="exception-message">
|
3
|
+
<%= simple_format h(exception_wrapper.original_message), { class: "message" }, wrapper_tag: "div" %>
|
4
|
+
</div>
|
5
|
+
<%
|
6
|
+
# The 'did_you_mean' gem can raise exceptions when calling #corrections on
|
7
|
+
# the exception. If it does there are no corrections to show.
|
8
|
+
corrections = exception_wrapper.corrections rescue []
|
9
|
+
%>
|
10
|
+
<% if corrections.any? %>
|
11
|
+
<b>Did you mean?</b>
|
12
|
+
<ul>
|
13
|
+
<% corrections.each do |correction| %>
|
14
|
+
<li class="correction"><%= h correction %></li>
|
15
|
+
<% end %>
|
16
|
+
</ul>
|
17
|
+
<% end %>
|
18
|
+
<% else %>
|
19
|
+
<div class="exception-message">
|
20
|
+
<%= simple_format h(exception_wrapper.message), { class: "message" }, wrapper_tag: "div" %>
|
21
|
+
</div>
|
22
|
+
<% end %>
|
@@ -1,34 +1,17 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
<% end %>
|
5
|
-
<pre id="blame_trace" <%='style="display:none"' if hide %>><code><%= @exception.describe_blame %></code></pre>
|
1
|
+
<h2 class="request-heading">Request</h2>
|
2
|
+
<% if params_valid? %>
|
3
|
+
<p><b>Parameters</b>:</p> <pre><%= debug_params(@request.filtered_parameters) %></pre>
|
6
4
|
<% end %>
|
7
5
|
|
8
|
-
<%
|
9
|
-
clean_params = @request.filtered_parameters.clone
|
10
|
-
clean_params.delete("action")
|
11
|
-
clean_params.delete("controller")
|
12
|
-
|
13
|
-
request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
|
14
|
-
|
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
|
-
end unless self.class.method_defined?(:debug_hash)
|
18
|
-
%>
|
19
|
-
|
20
|
-
<h2 style="margin-top: 30px">Request</h2>
|
21
|
-
<p><b>Parameters</b>:</p> <pre><%= request_dump %></pre>
|
22
|
-
|
23
6
|
<div class="details">
|
24
7
|
<div class="summary"><a href="#" onclick="return toggleSessionDump()">Toggle session dump</a></div>
|
25
|
-
<div id="session_dump"
|
8
|
+
<div id="session_dump" class="hidden"><pre><%= debug_hash @request.session %></pre></div>
|
26
9
|
</div>
|
27
10
|
|
28
11
|
<div class="details">
|
29
12
|
<div class="summary"><a href="#" onclick="return toggleEnvDump()">Toggle env dump</a></div>
|
30
|
-
<div id="env_dump"
|
13
|
+
<div id="env_dump" class="hidden"><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></div>
|
31
14
|
</div>
|
32
15
|
|
33
|
-
<h2
|
34
|
-
<p><b>Headers</b>:</p> <pre><%= defined?(@response) ? @response.headers
|
16
|
+
<h2 class="response-heading">Response</h2>
|
17
|
+
<p><b>Headers</b>:</p> <pre><%= debug_headers(defined?(@response) ? @response.headers : {}) %></pre>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<% error_index = local_assigns[:error_index] || 0 %>
|
2
|
+
|
3
|
+
<% source_extracts.each_with_index do |source_extract, index| %>
|
4
|
+
<% if source_extract[:code] %>
|
5
|
+
<div class="source <%= "hidden" if show_source_idx != index %>" id="frame-source-<%= error_index %>-<%= index %>">
|
6
|
+
<div class="info">
|
7
|
+
Extracted source (around line <strong>#<%= source_extract[:line_number] %></strong>):
|
8
|
+
</div>
|
9
|
+
<div class="data">
|
10
|
+
<table cellpadding="0" cellspacing="0" class="lines">
|
11
|
+
<tr>
|
12
|
+
<td>
|
13
|
+
<pre class="line_numbers">
|
14
|
+
<% source_extract[:code].each_key do |line_number| %>
|
15
|
+
<span><%= line_number -%></span>
|
16
|
+
<% end %>
|
17
|
+
</pre>
|
18
|
+
</td>
|
19
|
+
<td width="100%">
|
20
|
+
<pre>
|
21
|
+
<% source_extract[:code].each do |line, source| -%>
|
22
|
+
<div class="line<%= " active" if line == source_extract[:line_number] -%>"><% if source.is_a?(Array) -%><%= source[0] -%><span class="error_highlight"><%= source[1] -%></span><%= source[2] -%>
|
23
|
+
<% else -%>
|
24
|
+
<%= source -%>
|
25
|
+
<% end -%></div><% end -%>
|
26
|
+
</pre>
|
27
|
+
</td>
|
28
|
+
</tr>
|
29
|
+
</table>
|
30
|
+
</div>
|
31
|
+
<%- unless self.error_highlight_available? -%>
|
32
|
+
<p class="error_highlight_tip">Tip: You may want to add <code>gem "error_highlight", ">= 0.4.0"</code> into your Gemfile, which will display the fine-grained error location.</p>
|
33
|
+
<%- end -%>
|
34
|
+
</div>
|
35
|
+
<% end %>
|
36
|
+
<% end %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<% @source_extracts.first(3).each do |source_extract| %>
|
2
|
+
<% if source_extract[:code] %>
|
3
|
+
Extracted source (around line #<%= source_extract[:line_number] %>):
|
4
|
+
|
5
|
+
<% source_extract[:code].each do |line, source| -%>
|
6
|
+
<%= line == source_extract[:line_number] ? "*#{line}" : "##{line}" -%> <%= source -%><% end -%>
|
7
|
+
<% end %>
|
8
|
+
<% end %>
|
@@ -1,52 +1,62 @@
|
|
1
|
-
<% names =
|
1
|
+
<% names = traces.keys %>
|
2
|
+
<% error_index = local_assigns[:error_index] || 0 %>
|
2
3
|
|
3
4
|
<p><code>Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %></code></p>
|
4
5
|
|
5
|
-
<div id="traces">
|
6
|
+
<div id="traces-<%= error_index %>">
|
6
7
|
<% names.each do |name| %>
|
7
8
|
<%
|
8
|
-
show = "show('#{name.gsub(/\s/, '-')}');"
|
9
|
-
hide = (names - [name]).collect {|hide_name| "hide('#{hide_name.gsub(/\s/, '-')}');"}
|
9
|
+
show = "show('#{name.gsub(/\s/, '-')}-#{error_index}');"
|
10
|
+
hide = (names - [name]).collect {|hide_name| "hide('#{hide_name.gsub(/\s/, '-')}-#{error_index}');"}
|
10
11
|
%>
|
11
12
|
<a href="#" onclick="<%= hide.join %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %>
|
12
13
|
<% end %>
|
13
14
|
|
14
|
-
<%
|
15
|
-
<div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name ==
|
16
|
-
<
|
15
|
+
<% traces.each do |name, trace| %>
|
16
|
+
<div id="<%= "#{name.gsub(/\s/, '-')}-#{error_index}" %>" style="display: <%= (name == trace_to_show) ? 'block' : 'none' %>;">
|
17
|
+
<code class="traces">
|
18
|
+
<% trace.each do |frame| %>
|
19
|
+
<a class="trace-frames trace-frames-<%= error_index %>" data-exception-object-id="<%= frame[:exception_object_id] %>" data-frame-id="<%= frame[:id] %>" href="#">
|
20
|
+
<%= frame[:trace] %>
|
21
|
+
</a>
|
22
|
+
<br>
|
23
|
+
<% end %>
|
24
|
+
</code>
|
17
25
|
</div>
|
18
26
|
<% end %>
|
19
27
|
|
20
|
-
<script
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
traceFrames
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
currentSource
|
46
|
-
|
47
|
-
|
28
|
+
<script>
|
29
|
+
(function() {
|
30
|
+
var traceFrames = document.getElementsByClassName('trace-frames-<%= error_index %>');
|
31
|
+
var selectedFrame, currentSource = document.getElementById('frame-source-<%= error_index %>-0');
|
32
|
+
|
33
|
+
// Add click listeners for all stack frames
|
34
|
+
for (var i = 0; i < traceFrames.length; i++) {
|
35
|
+
traceFrames[i].addEventListener('click', function(e) {
|
36
|
+
e.preventDefault();
|
37
|
+
var target = e.target;
|
38
|
+
var frame_id = target.dataset.frameId;
|
39
|
+
|
40
|
+
if (selectedFrame) {
|
41
|
+
selectedFrame.className = selectedFrame.className.replace("selected", "");
|
42
|
+
}
|
43
|
+
|
44
|
+
target.className += " selected";
|
45
|
+
selectedFrame = target;
|
46
|
+
|
47
|
+
// Change the extracted source code
|
48
|
+
changeSourceExtract(frame_id);
|
49
|
+
});
|
50
|
+
|
51
|
+
function changeSourceExtract(frame_id) {
|
52
|
+
var el = document.getElementById('frame-source-<%= error_index %>-' + frame_id);
|
53
|
+
if (currentSource && el) {
|
54
|
+
currentSource.className += " hidden";
|
55
|
+
el.className = el.className.replace(" hidden", "");
|
56
|
+
currentSource = el;
|
57
|
+
}
|
48
58
|
}
|
49
59
|
}
|
50
|
-
}
|
60
|
+
})();
|
51
61
|
</script>
|
52
62
|
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<header>
|
2
|
+
<h1>Blocked hosts: <%= @hosts.join(", ") %></h1>
|
3
|
+
</header>
|
4
|
+
<main role="main" id="container">
|
5
|
+
<h2>To allow requests to these hosts, make sure they are valid hostnames (containing only numbers, letters, dashes and dots), then add the following to your environment configuration:</h2>
|
6
|
+
<pre>
|
7
|
+
<% @hosts.each do |host| %>
|
8
|
+
config.hosts << "<%= host %>"
|
9
|
+
<% end %>
|
10
|
+
</pre>
|
11
|
+
<p>For more details view: <a href="https://guides.rubyonrails.org/configuring.html#actiondispatch-hostauthorization">the Host Authorization guide</a></p>
|
12
|
+
</main>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Blocked hosts: <%= @hosts.join(", ") %>
|
2
|
+
|
3
|
+
To allow requests to these hosts, make sure they are valid hostnames (containing only numbers, letters, dashes and dots), then add the following to your environment configuration:
|
4
|
+
|
5
|
+
<% @hosts.each do |host| %>
|
6
|
+
config.hosts << "<%= host %>"
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
For more details on host authorization view: https://guides.rubyonrails.org/configuring.html#actiondispatch-hostauthorization
|
@@ -1,16 +1,35 @@
|
|
1
1
|
<header>
|
2
2
|
<h1>
|
3
|
-
<%= @
|
4
|
-
<% if @request.parameters['controller'] %>
|
3
|
+
<%= @exception_wrapper.exception_class_name %>
|
4
|
+
<% if params_valid? && @request.parameters['controller'] %>
|
5
5
|
in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
|
6
6
|
<% end %>
|
7
7
|
</h1>
|
8
8
|
</header>
|
9
9
|
|
10
|
-
<
|
11
|
-
|
10
|
+
<main role="main" id="container">
|
11
|
+
<%= render "rescues/message_and_suggestions", exception: @exception, exception_wrapper: @exception_wrapper %>
|
12
|
+
<%= render "rescues/actions", exception: @exception, request: @request, exception_wrapper: @exception_wrapper %>
|
13
|
+
|
14
|
+
<%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx, error_index: 0 %>
|
15
|
+
<%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show, error_index: 0 %>
|
16
|
+
|
17
|
+
<% if @exception_wrapper.has_cause? %>
|
18
|
+
<h2>Exception Causes</h2>
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
<% @exception_wrapper.wrapped_causes.each.with_index(1) do |wrapper, index| %>
|
22
|
+
<div class="details">
|
23
|
+
<a class="summary" href="#" onclick="return toggle(<%= wrapper.exception_id %>)">
|
24
|
+
<%= wrapper.exception_class_name %>: <%= h wrapper.message %>
|
25
|
+
</a>
|
26
|
+
</div>
|
27
|
+
|
28
|
+
<div id="<%= wrapper.exception_id %>" class="hidden">
|
29
|
+
<%= render "rescues/source", source_extracts: wrapper.source_extracts, show_source_idx: wrapper.source_to_show_id, error_index: index %>
|
30
|
+
<%= render "rescues/trace", traces: wrapper.traces, trace_to_show: wrapper.trace_to_show, error_index: index %>
|
31
|
+
</div>
|
32
|
+
<% end %>
|
12
33
|
|
13
|
-
<%= render template: "rescues/_source" %>
|
14
|
-
<%= render template: "rescues/_trace" %>
|
15
34
|
<%= render template: "rescues/_request_and_response" %>
|
16
|
-
</
|
35
|
+
</main>
|
@@ -1,9 +1,9 @@
|
|
1
|
-
<%= @
|
2
|
-
if @request.parameters['controller']
|
1
|
+
<%= @exception_wrapper.exception_class_name %><%
|
2
|
+
if params_valid? && @request.parameters['controller']
|
3
3
|
%> in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
|
4
4
|
<% end %>
|
5
5
|
|
6
|
-
<%= @
|
6
|
+
<%= @exception_wrapper.message %>
|
7
7
|
<%= render template: "rescues/_source" %>
|
8
8
|
<%= render template: "rescues/_trace" %>
|
9
9
|
<%= render template: "rescues/_request_and_response" %>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<header role="banner">
|
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>
|
9
|
+
|
10
|
+
<main role="main" id="container">
|
11
|
+
<h2>
|
12
|
+
<%= h @exception.message %>
|
13
|
+
<% if defined?(ActiveStorage) && @exception.message.match?(%r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}) %>
|
14
|
+
<br />To resolve this issue run: bin/rails active_storage:install
|
15
|
+
<% end %>
|
16
|
+
<% if defined?(ActionMailbox) && @exception.message.match?(%r{#{ActionMailbox::InboundEmail.table_name}}) %>
|
17
|
+
<br />To resolve this issue run: bin/rails action_mailbox:install
|
18
|
+
<% end %>
|
19
|
+
</h2>
|
20
|
+
|
21
|
+
<%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx %>
|
22
|
+
<%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show %>
|
23
|
+
<%= render template: "rescues/_request_and_response" %>
|
24
|
+
</main>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<%= @exception.class.to_s %><%
|
2
|
+
if @request.parameters['controller']
|
3
|
+
%> in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
|
4
|
+
<% end %>
|
5
|
+
|
6
|
+
<%= @exception.message %>
|
7
|
+
<% if defined?(ActiveStorage) && @exception.message.match?(%r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}) %>
|
8
|
+
To resolve this issue run: bin/rails active_storage:install
|
9
|
+
<% end %>
|
10
|
+
<% if defined?(ActionMailbox) && @exception.message.match?(%r{#{ActionMailbox::InboundEmail.table_name}}) %>
|
11
|
+
To resolve this issue run: bin/rails action_mailbox:install
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<%= render template: "rescues/_source" %>
|
15
|
+
<%= render template: "rescues/_trace" %>
|
16
|
+
<%= render template: "rescues/_request_and_response" %>
|