actionpack 5.0.7.2 → 5.1.0.beta1
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 +189 -1002
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/abstract_controller.rb +3 -3
- data/lib/abstract_controller/base.rb +10 -12
- data/lib/abstract_controller/caching.rb +6 -3
- data/lib/abstract_controller/caching/fragments.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +2 -43
- data/lib/abstract_controller/collector.rb +2 -2
- data/lib/abstract_controller/helpers.rb +19 -19
- data/lib/abstract_controller/rendering.rb +9 -11
- data/lib/abstract_controller/translation.rb +3 -3
- data/lib/action_controller.rb +15 -13
- data/lib/action_controller/api.rb +3 -3
- data/lib/action_controller/base.rb +7 -12
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +2 -2
- data/lib/action_controller/metal.rb +34 -43
- data/lib/action_controller/metal/conditional_get.rb +10 -9
- data/lib/action_controller/metal/data_streaming.rb +8 -9
- data/lib/action_controller/metal/etag_with_flash.rb +16 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +15 -15
- data/lib/action_controller/metal/exceptions.rb +4 -14
- data/lib/action_controller/metal/flash.rb +1 -1
- data/lib/action_controller/metal/force_ssl.rb +6 -6
- data/lib/action_controller/metal/head.rb +13 -19
- data/lib/action_controller/metal/helpers.rb +6 -6
- data/lib/action_controller/metal/http_authentication.rb +22 -23
- data/lib/action_controller/metal/implicit_render.rb +2 -5
- data/lib/action_controller/metal/instrumentation.rb +14 -14
- data/lib/action_controller/metal/live.rb +15 -16
- data/lib/action_controller/metal/mime_responds.rb +3 -3
- data/lib/action_controller/metal/parameter_encoding.rb +49 -0
- data/lib/action_controller/metal/params_wrapper.rb +32 -32
- data/lib/action_controller/metal/redirecting.rb +8 -24
- data/lib/action_controller/metal/renderers.rb +2 -3
- data/lib/action_controller/metal/rendering.rb +50 -60
- data/lib/action_controller/metal/request_forgery_protection.rb +51 -49
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +4 -4
- data/lib/action_controller/metal/strong_parameters.rb +117 -250
- data/lib/action_controller/metal/testing.rb +1 -1
- data/lib/action_controller/metal/url_for.rb +4 -4
- data/lib/action_controller/railtie.rb +9 -13
- data/lib/action_controller/renderer.rb +17 -16
- data/lib/action_controller/test_case.rb +75 -148
- data/lib/action_dispatch.rb +20 -19
- data/lib/action_dispatch/http/cache.rb +9 -10
- data/lib/action_dispatch/http/filter_parameters.rb +8 -8
- data/lib/action_dispatch/http/filter_redirect.rb +2 -4
- data/lib/action_dispatch/http/headers.rb +10 -10
- data/lib/action_dispatch/http/mime_negotiation.rb +17 -22
- data/lib/action_dispatch/http/mime_type.rb +27 -52
- data/lib/action_dispatch/http/parameter_filter.rb +8 -6
- data/lib/action_dispatch/http/parameters.rb +40 -17
- data/lib/action_dispatch/http/request.rb +38 -34
- data/lib/action_dispatch/http/response.rb +16 -16
- data/lib/action_dispatch/http/upload.rb +6 -10
- data/lib/action_dispatch/http/url.rb +48 -74
- data/lib/action_dispatch/journey.rb +5 -5
- data/lib/action_dispatch/journey/formatter.rb +8 -4
- data/lib/action_dispatch/journey/gtg/builder.rb +5 -5
- data/lib/action_dispatch/journey/gtg/simulator.rb +1 -1
- data/lib/action_dispatch/journey/gtg/transition_table.rb +15 -15
- data/lib/action_dispatch/journey/nfa/builder.rb +3 -3
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +2 -2
- data/lib/action_dispatch/journey/nodes/node.rb +5 -5
- data/lib/action_dispatch/journey/parser.rb +23 -24
- data/lib/action_dispatch/journey/parser.y +3 -2
- data/lib/action_dispatch/journey/parser_extras.rb +2 -2
- data/lib/action_dispatch/journey/path/pattern.rb +10 -3
- data/lib/action_dispatch/journey/route.rb +19 -12
- data/lib/action_dispatch/journey/router.rb +19 -12
- data/lib/action_dispatch/journey/router/utils.rb +9 -9
- data/lib/action_dispatch/journey/scanner.rb +17 -15
- data/lib/action_dispatch/journey/visitors.rb +23 -23
- data/lib/action_dispatch/middleware/callbacks.rb +0 -12
- data/lib/action_dispatch/middleware/cookies.rb +39 -39
- data/lib/action_dispatch/middleware/debug_exceptions.rb +126 -112
- data/lib/action_dispatch/middleware/debug_locks.rb +8 -8
- data/lib/action_dispatch/middleware/exception_wrapper.rb +55 -55
- data/lib/action_dispatch/middleware/executor.rb +1 -1
- data/lib/action_dispatch/middleware/flash.rb +17 -16
- data/lib/action_dispatch/middleware/public_exceptions.rb +20 -20
- data/lib/action_dispatch/middleware/reloader.rb +3 -47
- data/lib/action_dispatch/middleware/remote_ip.rb +6 -8
- data/lib/action_dispatch/middleware/request_id.rb +6 -5
- data/lib/action_dispatch/middleware/session/abstract_store.rb +14 -26
- data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
- data/lib/action_dispatch/middleware/session/cookie_store.rb +35 -35
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +2 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +19 -19
- data/lib/action_dispatch/middleware/ssl.rb +9 -27
- data/lib/action_dispatch/middleware/stack.rb +7 -26
- data/lib/action_dispatch/middleware/static.rb +13 -24
- data/lib/action_dispatch/railtie.rb +9 -11
- data/lib/action_dispatch/request/session.rb +22 -22
- data/lib/action_dispatch/request/utils.rb +11 -2
- data/lib/action_dispatch/routing.rb +8 -6
- data/lib/action_dispatch/routing/inspector.rb +37 -37
- data/lib/action_dispatch/routing/mapper.rb +296 -203
- data/lib/action_dispatch/routing/polymorphic_routes.rb +160 -134
- data/lib/action_dispatch/routing/redirection.rb +27 -22
- data/lib/action_dispatch/routing/route_set.rb +206 -92
- data/lib/action_dispatch/routing/routes_proxy.rb +2 -2
- data/lib/action_dispatch/routing/url_for.rb +14 -12
- data/lib/action_dispatch/system_test_case.rb +119 -0
- data/lib/action_dispatch/system_testing/browser.rb +28 -0
- data/lib/action_dispatch/system_testing/driver.rb +18 -0
- data/lib/action_dispatch/system_testing/server.rb +32 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +61 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +20 -0
- data/lib/action_dispatch/testing/assertion_response.rb +6 -6
- data/lib/action_dispatch/testing/assertions.rb +4 -4
- data/lib/action_dispatch/testing/assertions/response.rb +8 -3
- data/lib/action_dispatch/testing/assertions/routing.rb +11 -11
- data/lib/action_dispatch/testing/integration.rb +47 -138
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- data/lib/action_dispatch/testing/test_request.rb +16 -16
- data/lib/action_dispatch/testing/test_response.rb +1 -1
- data/lib/action_pack.rb +2 -2
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack/version.rb +1 -1
- metadata +20 -12
- data/lib/action_dispatch/middleware/params_parser.rb +0 -46
@@ -5,7 +5,7 @@ module ActionDispatch
|
|
5
5
|
ESCAPE_PATH = ->(value) { Router::Utils.escape_path(value) }
|
6
6
|
ESCAPE_SEGMENT = ->(value) { Router::Utils.escape_segment(value) }
|
7
7
|
|
8
|
-
|
8
|
+
Parameter = Struct.new(:name, :escaper) do
|
9
9
|
def escape(value); escaper.call value; end
|
10
10
|
end
|
11
11
|
|
@@ -22,7 +22,7 @@ module ActionDispatch
|
|
22
22
|
@children = []
|
23
23
|
@parameters = []
|
24
24
|
|
25
|
-
parts.each_with_index do |object,i|
|
25
|
+
parts.each_with_index do |object, i|
|
26
26
|
case object
|
27
27
|
when Journey::Format
|
28
28
|
@children << i
|
@@ -38,7 +38,7 @@ module ActionDispatch
|
|
38
38
|
@parameters.each do |index|
|
39
39
|
param = parts[index]
|
40
40
|
value = hash[param.name]
|
41
|
-
return
|
41
|
+
return "".freeze unless value
|
42
42
|
parts[index] = param.escape value
|
43
43
|
end
|
44
44
|
|
@@ -58,7 +58,7 @@ module ActionDispatch
|
|
58
58
|
|
59
59
|
private
|
60
60
|
|
61
|
-
def visit
|
61
|
+
def visit(node)
|
62
62
|
send(DISPATCH_CACHE[node.type], node)
|
63
63
|
end
|
64
64
|
|
@@ -98,7 +98,7 @@ module ActionDispatch
|
|
98
98
|
visit(node, seed)
|
99
99
|
end
|
100
100
|
|
101
|
-
def visit
|
101
|
+
def visit(node, seed)
|
102
102
|
send(DISPATCH_CACHE[node.type], node, seed)
|
103
103
|
end
|
104
104
|
|
@@ -167,28 +167,28 @@ module ActionDispatch
|
|
167
167
|
class String < FunctionalVisitor # :nodoc:
|
168
168
|
private
|
169
169
|
|
170
|
-
|
171
|
-
|
172
|
-
|
170
|
+
def binary(node, seed)
|
171
|
+
visit(node.right, visit(node.left, seed))
|
172
|
+
end
|
173
173
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
174
|
+
def nary(node, seed)
|
175
|
+
last_child = node.children.last
|
176
|
+
node.children.inject(seed) { |s, c|
|
177
|
+
string = visit(c, s)
|
178
|
+
string << "|".freeze unless last_child == c
|
179
|
+
string
|
180
|
+
}
|
181
|
+
end
|
182
182
|
|
183
|
-
|
184
|
-
|
185
|
-
|
183
|
+
def terminal(node, seed)
|
184
|
+
seed + node.left
|
185
|
+
end
|
186
186
|
|
187
|
-
|
188
|
-
|
189
|
-
|
187
|
+
def visit_GROUP(node, seed)
|
188
|
+
visit(node.left, seed << "(".freeze) << ")".freeze
|
189
|
+
end
|
190
190
|
|
191
|
-
|
191
|
+
INSTANCE = new
|
192
192
|
end
|
193
193
|
|
194
194
|
class Dot < FunctionalVisitor # :nodoc:
|
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
module ActionDispatch
|
3
2
|
# Provides callbacks to be executed before and after dispatching the request.
|
4
3
|
class Callbacks
|
@@ -7,17 +6,6 @@ module ActionDispatch
|
|
7
6
|
define_callbacks :call
|
8
7
|
|
9
8
|
class << self
|
10
|
-
def to_prepare(*args, &block)
|
11
|
-
ActiveSupport::Reloader.to_prepare(*args, &block)
|
12
|
-
end
|
13
|
-
|
14
|
-
def to_cleanup(*args, &block)
|
15
|
-
ActiveSupport::Reloader.to_complete(*args, &block)
|
16
|
-
end
|
17
|
-
|
18
|
-
deprecate to_prepare: 'use ActiveSupport::Reloader.to_prepare instead',
|
19
|
-
to_cleanup: 'use ActiveSupport::Reloader.to_complete instead'
|
20
|
-
|
21
9
|
def before(*args, &block)
|
22
10
|
set_callback(:call, :before, *args, &block)
|
23
11
|
end
|
@@ -1,13 +1,13 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
require "active_support/core_ext/hash/keys"
|
2
|
+
require "active_support/key_generator"
|
3
|
+
require "active_support/message_verifier"
|
4
|
+
require "active_support/json"
|
5
|
+
require "rack/utils"
|
6
6
|
|
7
7
|
module ActionDispatch
|
8
8
|
class Request
|
9
9
|
def cookie_jar
|
10
|
-
fetch_header(
|
10
|
+
fetch_header("action_dispatch.cookies".freeze) do
|
11
11
|
self.cookie_jar = Cookies::CookieJar.build(self, cookies)
|
12
12
|
end
|
13
13
|
end
|
@@ -20,11 +20,11 @@ module ActionDispatch
|
|
20
20
|
}
|
21
21
|
|
22
22
|
def have_cookie_jar?
|
23
|
-
has_header?
|
23
|
+
has_header? "action_dispatch.cookies".freeze
|
24
24
|
end
|
25
25
|
|
26
26
|
def cookie_jar=(jar)
|
27
|
-
set_header
|
27
|
+
set_header "action_dispatch.cookies".freeze, jar
|
28
28
|
end
|
29
29
|
|
30
30
|
def key_generator
|
@@ -179,7 +179,7 @@ module ActionDispatch
|
|
179
179
|
|
180
180
|
# Returns a jar that'll automatically generate a signed representation of cookie value and verify it when reading from
|
181
181
|
# the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed
|
182
|
-
# cookie was tampered with by the user (or a 3rd party), nil will be returned.
|
182
|
+
# cookie was tampered with by the user (or a 3rd party), +nil+ will be returned.
|
183
183
|
#
|
184
184
|
# If +secrets.secret_key_base+ and +secrets.secret_token+ (deprecated) are both set,
|
185
185
|
# legacy cookies signed with the old key generator will be transparently upgraded.
|
@@ -202,7 +202,7 @@ module ActionDispatch
|
|
202
202
|
end
|
203
203
|
|
204
204
|
# Returns a jar that'll automatically encrypt cookie values before sending them to the client and will decrypt them for read.
|
205
|
-
# If the cookie was tampered with by the user (or a 3rd party), nil will be returned.
|
205
|
+
# If the cookie was tampered with by the user (or a 3rd party), +nil+ will be returned.
|
206
206
|
#
|
207
207
|
# If +secrets.secret_key_base+ and +secrets.secret_token+ (deprecated) are both set,
|
208
208
|
# legacy cookies signed with the old key generator will be transparently upgraded.
|
@@ -237,9 +237,9 @@ module ActionDispatch
|
|
237
237
|
|
238
238
|
private
|
239
239
|
|
240
|
-
|
241
|
-
|
242
|
-
|
240
|
+
def upgrade_legacy_signed_cookies?
|
241
|
+
request.secret_token.present? && request.secret_key_base.present?
|
242
|
+
end
|
243
243
|
end
|
244
244
|
|
245
245
|
# Passing the ActiveSupport::MessageEncryptor::NullSerializer downstream
|
@@ -332,19 +332,19 @@ module ActionDispatch
|
|
332
332
|
|
333
333
|
def update_cookies_from_jar
|
334
334
|
request_jar = @request.cookie_jar.instance_variable_get(:@cookies)
|
335
|
-
set_cookies = request_jar.reject { |k,_| @delete_cookies.key?(k) }
|
335
|
+
set_cookies = request_jar.reject { |k, _| @delete_cookies.key?(k) }
|
336
336
|
|
337
337
|
@cookies.update set_cookies if set_cookies
|
338
338
|
end
|
339
339
|
|
340
340
|
def to_header
|
341
|
-
@cookies.map { |k,v| "#{escape(k)}=#{escape(v)}" }.join
|
341
|
+
@cookies.map { |k, v| "#{escape(k)}=#{escape(v)}" }.join "; "
|
342
342
|
end
|
343
343
|
|
344
344
|
def handle_options(options) #:nodoc:
|
345
345
|
options[:path] ||= "/"
|
346
346
|
|
347
|
-
if options[:domain] == :all || options[:domain] ==
|
347
|
+
if options[:domain] == :all || options[:domain] == "all"
|
348
348
|
# if there is a provided tld length then we use it otherwise default domain regexp
|
349
349
|
domain_regexp = options[:tld_length] ? /([^.]+\.?){#{options[:tld_length]}}$/ : DOMAIN_REGEXP
|
350
350
|
|
@@ -355,7 +355,7 @@ module ActionDispatch
|
|
355
355
|
end
|
356
356
|
elsif options[:domain].is_a? Array
|
357
357
|
# if host matches one of the supplied domains without a dot in front of it
|
358
|
-
options[:domain] = options[:domain].find {|domain| request.host.include? domain.sub(/^\./,
|
358
|
+
options[:domain] = options[:domain].find { |domain| request.host.include? domain.sub(/^\./, "") }
|
359
359
|
end
|
360
360
|
end
|
361
361
|
|
@@ -367,7 +367,7 @@ module ActionDispatch
|
|
367
367
|
value = options[:value]
|
368
368
|
else
|
369
369
|
value = options
|
370
|
-
options = { :
|
370
|
+
options = { value: value }
|
371
371
|
end
|
372
372
|
|
373
373
|
handle_options(options)
|
@@ -406,7 +406,7 @@ module ActionDispatch
|
|
406
406
|
|
407
407
|
# Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie
|
408
408
|
def clear(options = {})
|
409
|
-
@cookies.each_key{ |k| delete(k, options) }
|
409
|
+
@cookies.each_key { |k| delete(k, options) }
|
410
410
|
end
|
411
411
|
|
412
412
|
def write(headers)
|
@@ -420,26 +420,26 @@ module ActionDispatch
|
|
420
420
|
|
421
421
|
private
|
422
422
|
|
423
|
-
|
424
|
-
|
425
|
-
|
423
|
+
def escape(string)
|
424
|
+
::Rack::Utils.escape(string)
|
425
|
+
end
|
426
426
|
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
427
|
+
def make_set_cookie_header(header)
|
428
|
+
header = @set_cookies.inject(header) { |m, (k, v)|
|
429
|
+
if write_cookie?(v)
|
430
|
+
::Rack::Utils.add_cookie_to_header(m, k, v)
|
431
|
+
else
|
432
|
+
m
|
433
|
+
end
|
434
|
+
}
|
435
|
+
@delete_cookies.inject(header) { |m, (k, v)|
|
436
|
+
::Rack::Utils.add_remove_cookie_to_header(m, k, v)
|
437
|
+
}
|
438
|
+
end
|
439
439
|
|
440
|
-
|
441
|
-
|
442
|
-
|
440
|
+
def write_cookie?(cookie)
|
441
|
+
request.ssl? || !cookie[:secure] || always_write_cookie
|
442
|
+
end
|
443
443
|
end
|
444
444
|
|
445
445
|
class AbstractCookieJar # :nodoc:
|
@@ -528,7 +528,7 @@ module ActionDispatch
|
|
528
528
|
end
|
529
529
|
|
530
530
|
def digest
|
531
|
-
request.cookies_digest ||
|
531
|
+
request.cookies_digest || "SHA1"
|
532
532
|
end
|
533
533
|
|
534
534
|
def key_generator
|
@@ -572,7 +572,7 @@ module ActionDispatch
|
|
572
572
|
super
|
573
573
|
|
574
574
|
if ActiveSupport::LegacyKeyGenerator === key_generator
|
575
|
-
raise "You didn't set secrets.secret_key_base, which is required for this cookie jar. "
|
575
|
+
raise "You didn't set secrets.secret_key_base, which is required for this cookie jar. " \
|
576
576
|
"Read the upgrade documentation to learn more about this new config option."
|
577
577
|
end
|
578
578
|
|
@@ -1,16 +1,16 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
require "action_dispatch/http/request"
|
2
|
+
require "action_dispatch/middleware/exception_wrapper"
|
3
|
+
require "action_dispatch/routing/inspector"
|
4
|
+
require "action_view"
|
5
|
+
require "action_view/base"
|
6
6
|
|
7
|
-
require
|
7
|
+
require "pp"
|
8
8
|
|
9
9
|
module ActionDispatch
|
10
10
|
# This middleware is responsible for logging exceptions and
|
11
11
|
# showing a debugging page in case the request is local.
|
12
12
|
class DebugExceptions
|
13
|
-
RESCUES_TEMPLATE_PATH = File.expand_path(
|
13
|
+
RESCUES_TEMPLATE_PATH = File.expand_path("../templates", __FILE__)
|
14
14
|
|
15
15
|
class DebugView < ActionView::Base
|
16
16
|
def debug_params(params)
|
@@ -19,7 +19,7 @@ module ActionDispatch
|
|
19
19
|
clean_params.delete("controller")
|
20
20
|
|
21
21
|
if clean_params.empty?
|
22
|
-
|
22
|
+
"None"
|
23
23
|
else
|
24
24
|
PP.pp(clean_params, "", 200)
|
25
25
|
end
|
@@ -27,15 +27,25 @@ module ActionDispatch
|
|
27
27
|
|
28
28
|
def debug_headers(headers)
|
29
29
|
if headers.present?
|
30
|
-
headers.inspect.gsub(
|
30
|
+
headers.inspect.gsub(",", ",\n")
|
31
31
|
else
|
32
|
-
|
32
|
+
"None"
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
def debug_hash(object)
|
37
37
|
object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
|
38
38
|
end
|
39
|
+
|
40
|
+
def render(*)
|
41
|
+
logger = ActionView::Base.logger
|
42
|
+
|
43
|
+
if logger && logger.respond_to?(:silence)
|
44
|
+
logger.silence { super }
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
39
49
|
end
|
40
50
|
|
41
51
|
def initialize(app, routes_app = nil, response_format = :default)
|
@@ -48,7 +58,7 @@ module ActionDispatch
|
|
48
58
|
request = ActionDispatch::Request.new env
|
49
59
|
_, headers, body = response = @app.call(env)
|
50
60
|
|
51
|
-
if headers[
|
61
|
+
if headers["X-Cascade"] == "pass"
|
52
62
|
body.close if body.respond_to?(:close)
|
53
63
|
raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}"
|
54
64
|
end
|
@@ -61,129 +71,133 @@ module ActionDispatch
|
|
61
71
|
|
62
72
|
private
|
63
73
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
74
|
+
def render_exception(request, exception)
|
75
|
+
backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
|
76
|
+
wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
|
77
|
+
log_error(request, wrapper)
|
78
|
+
|
79
|
+
if request.get_header("action_dispatch.show_detailed_exceptions")
|
80
|
+
content_type = request.formats.first
|
81
|
+
|
82
|
+
if api_request?(content_type)
|
83
|
+
render_for_api_request(content_type, wrapper)
|
84
|
+
else
|
85
|
+
render_for_browser_request(request, wrapper)
|
86
|
+
end
|
87
|
+
else
|
88
|
+
raise exception
|
75
89
|
end
|
76
|
-
else
|
77
|
-
raise exception
|
78
90
|
end
|
79
|
-
end
|
80
91
|
|
81
|
-
|
82
|
-
|
83
|
-
|
92
|
+
def render_for_browser_request(request, wrapper)
|
93
|
+
template = create_template(request, wrapper)
|
94
|
+
file = "rescues/#{wrapper.rescue_template}"
|
84
95
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
96
|
+
if request.xhr?
|
97
|
+
body = template.render(template: file, layout: false, formats: [:text])
|
98
|
+
format = "text/plain"
|
99
|
+
else
|
100
|
+
body = template.render(template: file, layout: "rescues/layout")
|
101
|
+
format = "text/html"
|
102
|
+
end
|
103
|
+
render(wrapper.status_code, body, format)
|
91
104
|
end
|
92
|
-
render(wrapper.status_code, body, format)
|
93
|
-
end
|
94
|
-
|
95
|
-
def render_for_api_application(request, wrapper)
|
96
|
-
body = {
|
97
|
-
status: wrapper.status_code,
|
98
|
-
error: Rack::Utils::HTTP_STATUS_CODES.fetch(
|
99
|
-
wrapper.status_code,
|
100
|
-
Rack::Utils::HTTP_STATUS_CODES[500]
|
101
|
-
),
|
102
|
-
exception: wrapper.exception.inspect,
|
103
|
-
traces: wrapper.traces
|
104
|
-
}
|
105
|
-
|
106
|
-
content_type = request.formats.first
|
107
|
-
to_format = "to_#{content_type.to_sym}"
|
108
|
-
|
109
|
-
if content_type && body.respond_to?(to_format)
|
110
|
-
formatted_body = body.public_send(to_format)
|
111
|
-
format = content_type
|
112
|
-
else
|
113
|
-
formatted_body = body.to_json
|
114
|
-
format = Mime[:json]
|
115
|
-
end
|
116
|
-
|
117
|
-
render(wrapper.status_code, formatted_body, format)
|
118
|
-
end
|
119
105
|
|
120
|
-
|
121
|
-
|
106
|
+
def render_for_api_request(content_type, wrapper)
|
107
|
+
body = {
|
108
|
+
status: wrapper.status_code,
|
109
|
+
error: Rack::Utils::HTTP_STATUS_CODES.fetch(
|
110
|
+
wrapper.status_code,
|
111
|
+
Rack::Utils::HTTP_STATUS_CODES[500]
|
112
|
+
),
|
113
|
+
exception: wrapper.exception.inspect,
|
114
|
+
traces: wrapper.traces
|
115
|
+
}
|
116
|
+
|
117
|
+
to_format = "to_#{content_type.to_sym}"
|
118
|
+
|
119
|
+
if content_type && body.respond_to?(to_format)
|
120
|
+
formatted_body = body.public_send(to_format)
|
121
|
+
format = content_type
|
122
|
+
else
|
123
|
+
formatted_body = body.to_json
|
124
|
+
format = Mime[:json]
|
125
|
+
end
|
122
126
|
|
123
|
-
|
124
|
-
if traces[trace_to_show].empty? && wrapper.rescue_template != 'routing_error'
|
125
|
-
trace_to_show = 'Full Trace'
|
127
|
+
render(wrapper.status_code, formatted_body, format)
|
126
128
|
end
|
127
129
|
|
128
|
-
|
129
|
-
|
130
|
+
def create_template(request, wrapper)
|
131
|
+
traces = wrapper.traces
|
132
|
+
|
133
|
+
trace_to_show = "Application Trace"
|
134
|
+
if traces[trace_to_show].empty? && wrapper.rescue_template != "routing_error"
|
135
|
+
trace_to_show = "Full Trace"
|
136
|
+
end
|
137
|
+
|
138
|
+
if source_to_show = traces[trace_to_show].first
|
139
|
+
source_to_show_id = source_to_show[:id]
|
140
|
+
end
|
141
|
+
|
142
|
+
DebugView.new([RESCUES_TEMPLATE_PATH],
|
143
|
+
request: request,
|
144
|
+
exception: wrapper.exception,
|
145
|
+
traces: traces,
|
146
|
+
show_source_idx: source_to_show_id,
|
147
|
+
trace_to_show: trace_to_show,
|
148
|
+
routes_inspector: routes_inspector(wrapper.exception),
|
149
|
+
source_extracts: wrapper.source_extracts,
|
150
|
+
line_number: wrapper.line_number,
|
151
|
+
file: wrapper.file
|
152
|
+
)
|
130
153
|
end
|
131
154
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
traces: traces,
|
136
|
-
show_source_idx: source_to_show_id,
|
137
|
-
trace_to_show: trace_to_show,
|
138
|
-
routes_inspector: routes_inspector(wrapper.exception),
|
139
|
-
source_extracts: wrapper.source_extracts,
|
140
|
-
line_number: wrapper.line_number,
|
141
|
-
file: wrapper.file
|
142
|
-
)
|
143
|
-
end
|
155
|
+
def render(status, body, format)
|
156
|
+
[status, { "Content-Type" => "#{format}; charset=#{Response.default_charset}", "Content-Length" => body.bytesize.to_s }, [body]]
|
157
|
+
end
|
144
158
|
|
145
|
-
|
146
|
-
|
147
|
-
|
159
|
+
def log_error(request, wrapper)
|
160
|
+
logger = logger(request)
|
161
|
+
return unless logger
|
148
162
|
|
149
|
-
|
150
|
-
logger = logger(request)
|
151
|
-
return unless logger
|
163
|
+
exception = wrapper.exception
|
152
164
|
|
153
|
-
|
165
|
+
trace = wrapper.application_trace
|
166
|
+
trace = wrapper.framework_trace if trace.empty?
|
154
167
|
|
155
|
-
|
156
|
-
|
168
|
+
ActiveSupport::Deprecation.silence do
|
169
|
+
logger.fatal " "
|
170
|
+
logger.fatal "#{exception.class} (#{exception.message}):"
|
171
|
+
log_array logger, exception.annoted_source_code if exception.respond_to?(:annoted_source_code)
|
172
|
+
logger.fatal " "
|
173
|
+
log_array logger, trace
|
174
|
+
end
|
175
|
+
end
|
157
176
|
|
158
|
-
|
159
|
-
logger.
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
177
|
+
def log_array(logger, array)
|
178
|
+
if logger.formatter && logger.formatter.respond_to?(:tags_text)
|
179
|
+
logger.fatal array.join("\n#{logger.formatter.tags_text}")
|
180
|
+
else
|
181
|
+
logger.fatal array.join("\n")
|
182
|
+
end
|
164
183
|
end
|
165
|
-
end
|
166
184
|
|
167
|
-
|
168
|
-
|
169
|
-
logger.fatal array.join("\n#{logger.formatter.tags_text}")
|
170
|
-
else
|
171
|
-
logger.fatal array.join("\n")
|
185
|
+
def logger(request)
|
186
|
+
request.logger || ActionView::Base.logger || stderr_logger
|
172
187
|
end
|
173
|
-
end
|
174
188
|
|
175
|
-
|
176
|
-
|
177
|
-
|
189
|
+
def stderr_logger
|
190
|
+
@stderr_logger ||= ActiveSupport::Logger.new($stderr)
|
191
|
+
end
|
178
192
|
|
179
|
-
|
180
|
-
|
181
|
-
|
193
|
+
def routes_inspector(exception)
|
194
|
+
if @routes_app.respond_to?(:routes) && (exception.is_a?(ActionController::RoutingError) || exception.is_a?(ActionView::Template::Error))
|
195
|
+
ActionDispatch::Routing::RoutesInspector.new(@routes_app.routes.routes)
|
196
|
+
end
|
197
|
+
end
|
182
198
|
|
183
|
-
|
184
|
-
|
185
|
-
ActionDispatch::Routing::RoutesInspector.new(@routes_app.routes.routes)
|
199
|
+
def api_request?(content_type)
|
200
|
+
@response_format == :api && !content_type.html?
|
186
201
|
end
|
187
|
-
end
|
188
202
|
end
|
189
203
|
end
|