actionpack 4.2.10 → 6.1.3.2
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 +291 -479
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -9
- data/lib/abstract_controller/asset_paths.rb +2 -0
- data/lib/abstract_controller/base.rb +81 -51
- data/lib/{action_controller → abstract_controller}/caching/fragments.rb +64 -17
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/callbacks.rb +61 -33
- data/lib/abstract_controller/collector.rb +9 -13
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +115 -99
- data/lib/abstract_controller/logger.rb +2 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +21 -3
- data/lib/abstract_controller/rendering.rb +48 -47
- data/lib/abstract_controller/translation.rb +17 -8
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +13 -5
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/api.rb +150 -0
- data/lib/action_controller/base.rb +29 -24
- data/lib/action_controller/caching.rb +12 -57
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +17 -19
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +134 -46
- data/lib/action_controller/metal/content_security_policy.rb +51 -0
- data/lib/action_controller/metal/cookies.rb +6 -4
- data/lib/action_controller/metal/data_streaming.rb +30 -50
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +21 -16
- data/lib/action_controller/metal/exceptions.rb +63 -15
- data/lib/action_controller/metal/flash.rb +9 -8
- data/lib/action_controller/metal/head.rb +26 -21
- data/lib/action_controller/metal/helpers.rb +37 -18
- data/lib/action_controller/metal/http_authentication.rb +81 -73
- data/lib/action_controller/metal/implicit_render.rb +53 -9
- data/lib/action_controller/metal/instrumentation.rb +32 -35
- data/lib/action_controller/metal/live.rb +102 -120
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +49 -47
- data/lib/action_controller/metal/parameter_encoding.rb +82 -0
- data/lib/action_controller/metal/params_wrapper.rb +83 -66
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +53 -32
- data/lib/action_controller/metal/renderers.rb +87 -44
- data/lib/action_controller/metal/rendering.rb +77 -50
- data/lib/action_controller/metal/request_forgery_protection.rb +267 -103
- data/lib/action_controller/metal/rescue.rb +10 -17
- data/lib/action_controller/metal/streaming.rb +12 -11
- data/lib/action_controller/metal/strong_parameters.rb +714 -186
- data/lib/action_controller/metal/testing.rb +2 -17
- data/lib/action_controller/metal/url_for.rb +19 -10
- data/lib/action_controller/metal.rb +104 -87
- data/lib/action_controller/railtie.rb +28 -10
- data/lib/action_controller/railties/helpers.rb +3 -1
- data/lib/action_controller/renderer.rb +141 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +296 -422
- data/lib/action_controller.rb +34 -23
- data/lib/action_dispatch/http/cache.rb +107 -56
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +286 -0
- data/lib/action_dispatch/http/filter_parameters.rb +32 -25
- data/lib/action_dispatch/http/filter_redirect.rb +10 -12
- data/lib/action_dispatch/http/headers.rb +55 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +82 -50
- data/lib/action_dispatch/http/mime_type.rb +153 -121
- data/lib/action_dispatch/http/mime_types.rb +20 -6
- data/lib/action_dispatch/http/parameters.rb +90 -40
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +226 -121
- data/lib/action_dispatch/http/response.rb +248 -113
- data/lib/action_dispatch/http/upload.rb +21 -7
- data/lib/action_dispatch/http/url.rb +182 -100
- data/lib/action_dispatch/journey/formatter.rb +90 -43
- data/lib/action_dispatch/journey/gtg/builder.rb +28 -41
- data/lib/action_dispatch/journey/gtg/simulator.rb +11 -16
- data/lib/action_dispatch/journey/gtg/transition_table.rb +23 -21
- data/lib/action_dispatch/journey/nfa/dot.rb +3 -14
- data/lib/action_dispatch/journey/nodes/node.rb +29 -15
- data/lib/action_dispatch/journey/parser.rb +17 -16
- data/lib/action_dispatch/journey/parser.y +4 -3
- data/lib/action_dispatch/journey/parser_extras.rb +12 -4
- data/lib/action_dispatch/journey/path/pattern.rb +58 -54
- data/lib/action_dispatch/journey/route.rb +100 -32
- data/lib/action_dispatch/journey/router/utils.rb +29 -18
- data/lib/action_dispatch/journey/router.rb +55 -51
- data/lib/action_dispatch/journey/routes.rb +17 -17
- data/lib/action_dispatch/journey/scanner.rb +26 -17
- data/lib/action_dispatch/journey/visitors.rb +98 -54
- data/lib/action_dispatch/journey.rb +5 -5
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/callbacks.rb +3 -6
- data/lib/action_dispatch/middleware/cookies.rb +347 -217
- data/lib/action_dispatch/middleware/debug_exceptions.rb +135 -63
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/debug_view.rb +66 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +115 -71
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +78 -54
- data/lib/action_dispatch/middleware/host_authorization.rb +130 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +32 -27
- data/lib/action_dispatch/middleware/reloader.rb +5 -91
- data/lib/action_dispatch/middleware/remote_ip.rb +53 -45
- data/lib/action_dispatch/middleware/request_id.rb +17 -10
- data/lib/action_dispatch/middleware/session/abstract_store.rb +41 -26
- data/lib/action_dispatch/middleware/session/cache_store.rb +24 -14
- data/lib/action_dispatch/middleware/session/cookie_store.rb +74 -75
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +28 -23
- data/lib/action_dispatch/middleware/ssl.rb +118 -35
- data/lib/action_dispatch/middleware/stack.rb +82 -41
- data/lib/action_dispatch/middleware/static.rb +156 -89
- 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 +4 -14
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/{_source.erb → _source.html.erb} +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +15 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +105 -8
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -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 +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +87 -64
- data/lib/action_dispatch/railtie.rb +27 -13
- data/lib/action_dispatch/request/session.rb +109 -61
- data/lib/action_dispatch/request/utils.rb +90 -23
- data/lib/action_dispatch/routing/endpoint.rb +9 -2
- data/lib/action_dispatch/routing/inspector.rb +141 -102
- data/lib/action_dispatch/routing/mapper.rb +811 -473
- data/lib/action_dispatch/routing/polymorphic_routes.rb +167 -143
- data/lib/action_dispatch/routing/redirection.rb +37 -27
- data/lib/action_dispatch/routing/route_set.rb +363 -331
- data/lib/action_dispatch/routing/routes_proxy.rb +32 -5
- data/lib/action_dispatch/routing/url_for.rb +66 -26
- data/lib/action_dispatch/routing.rb +36 -36
- data/lib/action_dispatch/system_test_case.rb +190 -0
- data/lib/action_dispatch/system_testing/browser.rb +86 -0
- data/lib/action_dispatch/system_testing/driver.rb +67 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +138 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +29 -0
- data/lib/action_dispatch/testing/assertion_response.rb +46 -0
- data/lib/action_dispatch/testing/assertions/response.rb +44 -22
- data/lib/action_dispatch/testing/assertions/routing.rb +47 -31
- data/lib/action_dispatch/testing/assertions.rb +6 -4
- data/lib/action_dispatch/testing/integration.rb +391 -220
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +53 -22
- data/lib/action_dispatch/testing/test_request.rb +27 -34
- data/lib/action_dispatch/testing/test_response.rb +11 -11
- data/lib/action_dispatch.rb +35 -21
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +4 -2
- metadata +78 -49
- 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/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,28 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/inflector/methods"
|
2
4
|
require "active_support/dependencies"
|
3
5
|
|
4
6
|
module ActionDispatch
|
5
7
|
class MiddlewareStack
|
6
8
|
class Middleware
|
7
|
-
attr_reader :args, :block, :
|
8
|
-
|
9
|
-
def initialize(klass_or_name, *args, &block)
|
10
|
-
@klass = nil
|
11
|
-
|
12
|
-
if klass_or_name.respond_to?(:name)
|
13
|
-
@klass = klass_or_name
|
14
|
-
@name = @klass.name
|
15
|
-
else
|
16
|
-
@name = klass_or_name.to_s
|
17
|
-
end
|
9
|
+
attr_reader :args, :block, :klass
|
18
10
|
|
19
|
-
|
20
|
-
@
|
11
|
+
def initialize(klass, args, block)
|
12
|
+
@klass = klass
|
13
|
+
@args = args
|
14
|
+
@block = block
|
21
15
|
end
|
22
16
|
|
23
|
-
def klass
|
24
|
-
@klass || classcache[@name]
|
25
|
-
end
|
17
|
+
def name; klass.name; end
|
26
18
|
|
27
19
|
def ==(middleware)
|
28
20
|
case middleware
|
@@ -30,23 +22,44 @@ module ActionDispatch
|
|
30
22
|
klass == middleware.klass
|
31
23
|
when Class
|
32
24
|
klass == middleware
|
33
|
-
else
|
34
|
-
normalize(@name) == normalize(middleware)
|
35
25
|
end
|
36
26
|
end
|
37
27
|
|
38
28
|
def inspect
|
39
|
-
klass.
|
29
|
+
if klass.is_a?(Class)
|
30
|
+
klass.to_s
|
31
|
+
else
|
32
|
+
klass.class.to_s
|
33
|
+
end
|
40
34
|
end
|
41
35
|
|
42
36
|
def build(app)
|
43
37
|
klass.new(app, *args, &block)
|
44
38
|
end
|
45
39
|
|
46
|
-
|
40
|
+
def build_instrumented(app)
|
41
|
+
InstrumentationProxy.new(build(app), inspect)
|
42
|
+
end
|
43
|
+
end
|
47
44
|
|
48
|
-
|
49
|
-
|
45
|
+
# This class is used to instrument the execution of a single middleware.
|
46
|
+
# It proxies the +call+ method transparently and instruments the method
|
47
|
+
# call.
|
48
|
+
class InstrumentationProxy
|
49
|
+
EVENT_NAME = "process_middleware.action_dispatch"
|
50
|
+
|
51
|
+
def initialize(middleware, class_name)
|
52
|
+
@middleware = middleware
|
53
|
+
|
54
|
+
@payload = {
|
55
|
+
middleware: class_name,
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def call(env)
|
60
|
+
ActiveSupport::Notifications.instrument(EVENT_NAME, @payload) do
|
61
|
+
@middleware.call(env)
|
62
|
+
end
|
50
63
|
end
|
51
64
|
end
|
52
65
|
|
@@ -75,20 +88,20 @@ module ActionDispatch
|
|
75
88
|
middlewares[i]
|
76
89
|
end
|
77
90
|
|
78
|
-
def unshift(*args, &block)
|
79
|
-
|
80
|
-
middlewares.unshift(middleware)
|
91
|
+
def unshift(klass, *args, &block)
|
92
|
+
middlewares.unshift(build_middleware(klass, args, block))
|
81
93
|
end
|
94
|
+
ruby2_keywords(:unshift) if respond_to?(:ruby2_keywords, true)
|
82
95
|
|
83
96
|
def initialize_copy(other)
|
84
97
|
self.middlewares = other.middlewares.dup
|
85
98
|
end
|
86
99
|
|
87
|
-
def insert(index, *args, &block)
|
100
|
+
def insert(index, klass, *args, &block)
|
88
101
|
index = assert_index(index, :before)
|
89
|
-
|
90
|
-
middlewares.insert(index, middleware)
|
102
|
+
middlewares.insert(index, build_middleware(klass, args, block))
|
91
103
|
end
|
104
|
+
ruby2_keywords(:insert) if respond_to?(:ruby2_keywords, true)
|
92
105
|
|
93
106
|
alias_method :insert_before, :insert
|
94
107
|
|
@@ -96,34 +109,62 @@ module ActionDispatch
|
|
96
109
|
index = assert_index(index, :after)
|
97
110
|
insert(index + 1, *args, &block)
|
98
111
|
end
|
112
|
+
ruby2_keywords(:insert_after) if respond_to?(:ruby2_keywords, true)
|
99
113
|
|
100
114
|
def swap(target, *args, &block)
|
101
115
|
index = assert_index(target, :before)
|
102
116
|
insert(index, *args, &block)
|
103
117
|
middlewares.delete_at(index + 1)
|
104
118
|
end
|
119
|
+
ruby2_keywords(:swap) if respond_to?(:ruby2_keywords, true)
|
105
120
|
|
106
121
|
def delete(target)
|
107
|
-
middlewares.
|
122
|
+
middlewares.delete_if { |m| m.klass == target }
|
108
123
|
end
|
109
124
|
|
110
|
-
def
|
111
|
-
|
112
|
-
middlewares.
|
125
|
+
def move(target, source)
|
126
|
+
source_index = assert_index(source, :before)
|
127
|
+
source_middleware = middlewares.delete_at(source_index)
|
128
|
+
|
129
|
+
target_index = assert_index(target, :before)
|
130
|
+
middlewares.insert(target_index, source_middleware)
|
113
131
|
end
|
114
132
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
133
|
+
alias_method :move_before, :move
|
134
|
+
|
135
|
+
def move_after(target, source)
|
136
|
+
source_index = assert_index(source, :after)
|
137
|
+
source_middleware = middlewares.delete_at(source_index)
|
138
|
+
|
139
|
+
target_index = assert_index(target, :after)
|
140
|
+
middlewares.insert(target_index + 1, source_middleware)
|
119
141
|
end
|
120
142
|
|
121
|
-
|
143
|
+
def use(klass, *args, &block)
|
144
|
+
middlewares.push(build_middleware(klass, args, block))
|
145
|
+
end
|
146
|
+
ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
|
122
147
|
|
123
|
-
def
|
124
|
-
|
125
|
-
|
126
|
-
|
148
|
+
def build(app = nil, &block)
|
149
|
+
instrumenting = ActiveSupport::Notifications.notifier.listening?(InstrumentationProxy::EVENT_NAME)
|
150
|
+
middlewares.freeze.reverse.inject(app || block) do |a, e|
|
151
|
+
if instrumenting
|
152
|
+
e.build_instrumented(a)
|
153
|
+
else
|
154
|
+
e.build(a)
|
155
|
+
end
|
156
|
+
end
|
127
157
|
end
|
158
|
+
|
159
|
+
private
|
160
|
+
def assert_index(index, where)
|
161
|
+
i = index.is_a?(Integer) ? index : middlewares.index { |m| m.klass == index }
|
162
|
+
raise "No such middleware to insert #{where}: #{index.inspect}" unless i
|
163
|
+
i
|
164
|
+
end
|
165
|
+
|
166
|
+
def build_middleware(klass, args, block)
|
167
|
+
Middleware.new(klass, args, block)
|
168
|
+
end
|
128
169
|
end
|
129
170
|
end
|
@@ -1,123 +1,190 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack/utils"
|
4
|
+
require "active_support/core_ext/uri"
|
3
5
|
|
4
6
|
module ActionDispatch
|
5
|
-
# This middleware
|
6
|
-
#
|
7
|
-
#
|
7
|
+
# This middleware serves static files from disk, if available.
|
8
|
+
# If no file is found, it hands off to the main app.
|
9
|
+
#
|
10
|
+
# In Rails apps, this middleware is configured to serve assets from
|
11
|
+
# the +public/+ directory.
|
12
|
+
#
|
13
|
+
# Only GET and HEAD requests are served. POST and other HTTP methods
|
14
|
+
# are handed off to the main app.
|
15
|
+
#
|
16
|
+
# Only files in the root directory are served; path traversal is denied.
|
17
|
+
class Static
|
18
|
+
def initialize(app, path, index: "index", headers: {})
|
19
|
+
@app = app
|
20
|
+
@file_handler = FileHandler.new(path, index: index, headers: headers)
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(env)
|
24
|
+
@file_handler.attempt(env) || @app.call(env)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# This endpoint serves static files from disk using Rack::File.
|
8
29
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
30
|
+
# URL paths are matched with static files according to expected
|
31
|
+
# conventions: +path+, +path+.html, +path+/index.html.
|
32
|
+
#
|
33
|
+
# Precompressed versions of these files are checked first. Brotli (.br)
|
34
|
+
# and gzip (.gz) files are supported. If +path+.br exists, this
|
35
|
+
# endpoint returns that file with a <tt>Content-Encoding: br</tt> header.
|
36
|
+
#
|
37
|
+
# If no matching file is found, this endpoint responds 404 Not Found.
|
38
|
+
#
|
39
|
+
# Pass the +root+ directory to search for matching files, an optional
|
40
|
+
# <tt>index: "index"</tt> to change the default +path+/index.html, and optional
|
41
|
+
# additional response headers.
|
15
42
|
class FileHandler
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
43
|
+
# Accept-Encoding value -> file extension
|
44
|
+
PRECOMPRESSED = {
|
45
|
+
"br" => ".br",
|
46
|
+
"gzip" => ".gz",
|
47
|
+
"identity" => nil
|
48
|
+
}
|
49
|
+
|
50
|
+
def initialize(root, index: "index", headers: {}, precompressed: %i[ br gzip ], compressible_content_types: /\A(?:text\/|application\/javascript)/)
|
51
|
+
@root = root.chomp("/").b
|
52
|
+
@index = index
|
53
|
+
|
54
|
+
@precompressed = Array(precompressed).map(&:to_s) | %w[ identity ]
|
55
|
+
@compressible_content_types = compressible_content_types
|
56
|
+
|
20
57
|
@file_server = ::Rack::File.new(@root, headers)
|
21
58
|
end
|
22
59
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
60
|
+
def call(env)
|
61
|
+
attempt(env) || @file_server.call(env)
|
62
|
+
end
|
26
63
|
|
27
|
-
|
28
|
-
|
29
|
-
}
|
64
|
+
def attempt(env)
|
65
|
+
request = Rack::Request.new env
|
30
66
|
|
31
|
-
if
|
32
|
-
|
33
|
-
|
34
|
-
File.file?(path) && File.readable?(path)
|
35
|
-
rescue SystemCallError
|
36
|
-
false
|
67
|
+
if request.get? || request.head?
|
68
|
+
if found = find_file(request.path_info, accept_encoding: request.accept_encoding)
|
69
|
+
serve request, *found
|
37
70
|
end
|
38
|
-
|
39
|
-
}
|
40
|
-
return ::Rack::Utils.escape(match)
|
41
71
|
end
|
42
72
|
end
|
43
73
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
env
|
50
|
-
|
51
|
-
|
52
|
-
|
74
|
+
private
|
75
|
+
def serve(request, filepath, content_headers)
|
76
|
+
original, request.path_info =
|
77
|
+
request.path_info, ::Rack::Utils.escape_path(filepath).b
|
78
|
+
|
79
|
+
@file_server.call(request.env).tap do |status, headers, body|
|
80
|
+
# Omit Content-Encoding/Type/etc headers for 304 Not Modified
|
81
|
+
if status != 304
|
82
|
+
headers.update(content_headers)
|
83
|
+
end
|
53
84
|
end
|
54
|
-
|
55
|
-
|
56
|
-
else
|
57
|
-
status, headers, body = @file_server.call(env)
|
85
|
+
ensure
|
86
|
+
request.path_info = original
|
58
87
|
end
|
59
88
|
|
60
|
-
|
89
|
+
# Match a URI path to a static file to be served.
|
90
|
+
#
|
91
|
+
# Used by the +Static+ class to negotiate a servable file in the
|
92
|
+
# +public/+ directory (see Static#call).
|
93
|
+
#
|
94
|
+
# Checks for +path+, +path+.html, and +path+/index.html files,
|
95
|
+
# in that order, including .br and .gzip compressed extensions.
|
96
|
+
#
|
97
|
+
# If a matching file is found, the path and necessary response headers
|
98
|
+
# (Content-Type, Content-Encoding) are returned.
|
99
|
+
def find_file(path_info, accept_encoding:)
|
100
|
+
each_candidate_filepath(path_info) do |filepath, content_type|
|
101
|
+
if response = try_files(filepath, content_type, accept_encoding: accept_encoding)
|
102
|
+
return response
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
61
106
|
|
62
|
-
|
63
|
-
|
64
|
-
env['PATH_INFO'] = path
|
65
|
-
end
|
107
|
+
def try_files(filepath, content_type, accept_encoding:)
|
108
|
+
headers = { "Content-Type" => content_type }
|
66
109
|
|
67
|
-
|
68
|
-
|
69
|
-
|
110
|
+
if compressible? content_type
|
111
|
+
try_precompressed_files filepath, headers, accept_encoding: accept_encoding
|
112
|
+
elsif file_readable? filepath
|
113
|
+
[ filepath, headers ]
|
114
|
+
end
|
70
115
|
end
|
71
116
|
|
72
|
-
def
|
73
|
-
|
117
|
+
def try_precompressed_files(filepath, headers, accept_encoding:)
|
118
|
+
each_precompressed_filepath(filepath) do |content_encoding, precompressed_filepath|
|
119
|
+
if file_readable? precompressed_filepath
|
120
|
+
# Identity encoding is default, so we skip Accept-Encoding
|
121
|
+
# negotiation and needn't set Content-Encoding.
|
122
|
+
#
|
123
|
+
# Vary header is expected when we've found other available
|
124
|
+
# encodings that Accept-Encoding ruled out.
|
125
|
+
if content_encoding == "identity"
|
126
|
+
return precompressed_filepath, headers
|
127
|
+
else
|
128
|
+
headers["Vary"] = "Accept-Encoding"
|
129
|
+
|
130
|
+
if accept_encoding.any? { |enc, _| /\b#{content_encoding}\b/i.match?(enc) }
|
131
|
+
headers["Content-Encoding"] = content_encoding
|
132
|
+
return precompressed_filepath, headers
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
74
137
|
end
|
75
138
|
|
76
|
-
def
|
77
|
-
|
139
|
+
def file_readable?(path)
|
140
|
+
file_stat = File.stat(File.join(@root, path.b))
|
141
|
+
rescue SystemCallError
|
142
|
+
false
|
143
|
+
else
|
144
|
+
file_stat.file? && file_stat.readable?
|
78
145
|
end
|
79
146
|
|
80
|
-
def
|
81
|
-
|
82
|
-
gzip_path = "#{path}.gz"
|
83
|
-
if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape(gzip_path)))
|
84
|
-
gzip_path
|
85
|
-
else
|
86
|
-
false
|
87
|
-
end
|
147
|
+
def compressible?(content_type)
|
148
|
+
@compressible_content_types.match?(content_type)
|
88
149
|
end
|
89
150
|
|
90
|
-
def
|
91
|
-
|
151
|
+
def each_precompressed_filepath(filepath)
|
152
|
+
@precompressed.each do |content_encoding|
|
153
|
+
precompressed_ext = PRECOMPRESSED.fetch(content_encoding)
|
154
|
+
yield content_encoding, "#{filepath}#{precompressed_ext}"
|
155
|
+
end
|
156
|
+
|
157
|
+
nil
|
92
158
|
end
|
93
|
-
end
|
94
159
|
|
95
|
-
|
96
|
-
|
97
|
-
# delegated to the application stack. This middleware is commonly initialized
|
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
|
160
|
+
def each_candidate_filepath(path_info)
|
161
|
+
return unless path = clean_path(path_info)
|
109
162
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
163
|
+
ext = ::File.extname(path)
|
164
|
+
content_type = ::Rack::Mime.mime_type(ext, nil)
|
165
|
+
yield path, content_type || "text/plain"
|
166
|
+
|
167
|
+
# Tack on .html and /index.html only for paths that don't have
|
168
|
+
# an explicit, resolvable file extension. No need to check
|
169
|
+
# for foo.js.html and foo.js/index.html.
|
170
|
+
unless content_type
|
171
|
+
default_ext = ::ActionController::Base.default_static_extension
|
172
|
+
if ext != default_ext
|
173
|
+
default_content_type = ::Rack::Mime.mime_type(default_ext, "text/plain")
|
174
|
+
|
175
|
+
yield "#{path}#{default_ext}", default_content_type
|
176
|
+
yield "#{path}/#{@index}#{default_ext}", default_content_type
|
177
|
+
end
|
117
178
|
end
|
179
|
+
|
180
|
+
nil
|
118
181
|
end
|
119
182
|
|
120
|
-
|
121
|
-
|
183
|
+
def clean_path(path_info)
|
184
|
+
path = ::Rack::Utils.unescape_path path_info.chomp("/")
|
185
|
+
if ::Rack::Utils.valid_path? path
|
186
|
+
::Rack::Utils.clean_path_info path
|
187
|
+
end
|
188
|
+
end
|
122
189
|
end
|
123
190
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<% actions = ActiveSupport::ActionableError.actions(exception) %>
|
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.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.respond_to?(:original_message) && exception.respond_to?(:corrections) %>
|
2
|
+
<div class="exception-message">
|
3
|
+
<%= simple_format h(exception.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.corrections rescue []
|
9
|
+
%>
|
10
|
+
<% if corrections.any? %>
|
11
|
+
<b>Did you mean?</b>
|
12
|
+
<ul>
|
13
|
+
<% corrections.each do |correction| %>
|
14
|
+
<li style="list-style-type: none"><%= h correction %></li>
|
15
|
+
<% end %>
|
16
|
+
</ul>
|
17
|
+
<% end %>
|
18
|
+
<% else %>
|
19
|
+
<div class="exception-message">
|
20
|
+
<%= simple_format h(exception.message), { class: "message" }, wrapper_tag: "div" %>
|
21
|
+
</div>
|
22
|
+
<% end %>
|
@@ -5,20 +5,10 @@
|
|
5
5
|
<pre id="blame_trace" <%='style="display:none"' if hide %>><code><%= @exception.describe_blame %></code></pre>
|
6
6
|
<% end %>
|
7
7
|
|
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
8
|
<h2 style="margin-top: 30px">Request</h2>
|
21
|
-
|
9
|
+
<% if params_valid? %>
|
10
|
+
<p><b>Parameters</b>:</p> <pre><%= debug_params(@request.filtered_parameters) %></pre>
|
11
|
+
<% end %>
|
22
12
|
|
23
13
|
<div class="details">
|
24
14
|
<div class="summary"><a href="#" onclick="return toggleSessionDump()">Toggle session dump</a></div>
|
@@ -31,4 +21,4 @@
|
|
31
21
|
</div>
|
32
22
|
|
33
23
|
<h2 style="margin-top: 30px">Response</h2>
|
34
|
-
<p><b>Headers</b>:</p> <pre><%= defined?(@response) ? @response.headers
|
24
|
+
<p><b>Headers</b>:</p> <pre><%= debug_headers(defined?(@response) ? @response.headers : {}) %></pre>
|
@@ -1,6 +1,8 @@
|
|
1
|
-
<%
|
1
|
+
<% error_index = local_assigns[:error_index] || 0 %>
|
2
|
+
|
3
|
+
<% source_extracts.each_with_index do |source_extract, index| %>
|
2
4
|
<% if source_extract[:code] %>
|
3
|
-
<div class="source <%="hidden" if
|
5
|
+
<div class="source <%= "hidden" if show_source_idx != index %>" id="frame-source-<%= error_index %>-<%= index %>">
|
4
6
|
<div class="info">
|
5
7
|
Extracted source (around line <strong>#<%= source_extract[:line_number] %></strong>):
|
6
8
|
</div>
|
@@ -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 %>
|