ultra-lite-hub 0.0.1
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/roda-3.105.0/MIT-LICENSE +21 -0
- data/roda-3.105.0/lib/roda/cache.rb +42 -0
- data/roda-3.105.0/lib/roda/plugins/Integer_matcher_max.rb +55 -0
- data/roda-3.105.0/lib/roda/plugins/_after_hook.rb +11 -0
- data/roda-3.105.0/lib/roda/plugins/_base64.rb +34 -0
- data/roda-3.105.0/lib/roda/plugins/_before_hook.rb +41 -0
- data/roda-3.105.0/lib/roda/plugins/_optimized_matching.rb +227 -0
- data/roda-3.105.0/lib/roda/plugins/_symbol_class_matchers.rb +108 -0
- data/roda-3.105.0/lib/roda/plugins/_symbol_regexp_matchers.rb +24 -0
- data/roda-3.105.0/lib/roda/plugins/additional_render_engines.rb +61 -0
- data/roda-3.105.0/lib/roda/plugins/additional_view_directories.rb +66 -0
- data/roda-3.105.0/lib/roda/plugins/all_verbs.rb +50 -0
- data/roda-3.105.0/lib/roda/plugins/assets.rb +902 -0
- data/roda-3.105.0/lib/roda/plugins/assets_preloading.rb +89 -0
- data/roda-3.105.0/lib/roda/plugins/assume_ssl.rb +28 -0
- data/roda-3.105.0/lib/roda/plugins/autoload_hash_branches.rb +79 -0
- data/roda-3.105.0/lib/roda/plugins/autoload_named_routes.rb +65 -0
- data/roda-3.105.0/lib/roda/plugins/backtracking_array.rb +88 -0
- data/roda-3.105.0/lib/roda/plugins/bearer_token.rb +28 -0
- data/roda-3.105.0/lib/roda/plugins/branch_locals.rb +74 -0
- data/roda-3.105.0/lib/roda/plugins/break.rb +43 -0
- data/roda-3.105.0/lib/roda/plugins/caching.rb +206 -0
- data/roda-3.105.0/lib/roda/plugins/capture_erb.rb +94 -0
- data/roda-3.105.0/lib/roda/plugins/chunked.rb +331 -0
- data/roda-3.105.0/lib/roda/plugins/class_level_routing.rb +111 -0
- data/roda-3.105.0/lib/roda/plugins/class_matchers.rb +155 -0
- data/roda-3.105.0/lib/roda/plugins/common_logger.rb +80 -0
- data/roda-3.105.0/lib/roda/plugins/conditional_sessions.rb +67 -0
- data/roda-3.105.0/lib/roda/plugins/content_for.rb +103 -0
- data/roda-3.105.0/lib/roda/plugins/content_security_policy.rb +329 -0
- data/roda-3.105.0/lib/roda/plugins/cookie_flags.rb +157 -0
- data/roda-3.105.0/lib/roda/plugins/cookies.rb +51 -0
- data/roda-3.105.0/lib/roda/plugins/csrf.rb +81 -0
- data/roda-3.105.0/lib/roda/plugins/custom_block_results.rb +85 -0
- data/roda-3.105.0/lib/roda/plugins/custom_matchers.rb +89 -0
- data/roda-3.105.0/lib/roda/plugins/default_headers.rb +64 -0
- data/roda-3.105.0/lib/roda/plugins/default_status.rb +35 -0
- data/roda-3.105.0/lib/roda/plugins/delay_build.rb +18 -0
- data/roda-3.105.0/lib/roda/plugins/delegate.rb +77 -0
- data/roda-3.105.0/lib/roda/plugins/delete_empty_headers.rb +36 -0
- data/roda-3.105.0/lib/roda/plugins/direct_call.rb +38 -0
- data/roda-3.105.0/lib/roda/plugins/disallow_file_uploads.rb +38 -0
- data/roda-3.105.0/lib/roda/plugins/drop_body.rb +43 -0
- data/roda-3.105.0/lib/roda/plugins/each_part.rb +87 -0
- data/roda-3.105.0/lib/roda/plugins/early_hints.rb +25 -0
- data/roda-3.105.0/lib/roda/plugins/empty_root.rb +49 -0
- data/roda-3.105.0/lib/roda/plugins/environments.rb +79 -0
- data/roda-3.105.0/lib/roda/plugins/erb_h.rb +43 -0
- data/roda-3.105.0/lib/roda/plugins/error_email.rb +152 -0
- data/roda-3.105.0/lib/roda/plugins/error_handler.rb +133 -0
- data/roda-3.105.0/lib/roda/plugins/error_mail.rb +149 -0
- data/roda-3.105.0/lib/roda/plugins/exception_page.rb +445 -0
- data/roda-3.105.0/lib/roda/plugins/filter_common_logger.rb +46 -0
- data/roda-3.105.0/lib/roda/plugins/flash.rb +117 -0
- data/roda-3.105.0/lib/roda/plugins/h.rb +59 -0
- data/roda-3.105.0/lib/roda/plugins/halt.rb +108 -0
- data/roda-3.105.0/lib/roda/plugins/hash_branch_view_subdir.rb +76 -0
- data/roda-3.105.0/lib/roda/plugins/hash_branches.rb +145 -0
- data/roda-3.105.0/lib/roda/plugins/hash_matcher.rb +39 -0
- data/roda-3.105.0/lib/roda/plugins/hash_paths.rb +128 -0
- data/roda-3.105.0/lib/roda/plugins/hash_public.rb +125 -0
- data/roda-3.105.0/lib/roda/plugins/hash_public_cache.rb +91 -0
- data/roda-3.105.0/lib/roda/plugins/hash_routes.rb +304 -0
- data/roda-3.105.0/lib/roda/plugins/head.rb +99 -0
- data/roda-3.105.0/lib/roda/plugins/header_matchers.rb +88 -0
- data/roda-3.105.0/lib/roda/plugins/heartbeat.rb +41 -0
- data/roda-3.105.0/lib/roda/plugins/hmac_paths.rb +413 -0
- data/roda-3.105.0/lib/roda/plugins/hooks.rb +92 -0
- data/roda-3.105.0/lib/roda/plugins/host_authorization.rb +155 -0
- data/roda-3.105.0/lib/roda/plugins/host_routing.rb +190 -0
- data/roda-3.105.0/lib/roda/plugins/hsts.rb +35 -0
- data/roda-3.105.0/lib/roda/plugins/indifferent_params.rb +124 -0
- data/roda-3.105.0/lib/roda/plugins/inject_erb.rb +33 -0
- data/roda-3.105.0/lib/roda/plugins/invalid_request_body.rb +107 -0
- data/roda-3.105.0/lib/roda/plugins/ip_from_header.rb +34 -0
- data/roda-3.105.0/lib/roda/plugins/json.rb +119 -0
- data/roda-3.105.0/lib/roda/plugins/json_parser.rb +107 -0
- data/roda-3.105.0/lib/roda/plugins/link_to.rb +83 -0
- data/roda-3.105.0/lib/roda/plugins/mail_processor.rb +629 -0
- data/roda-3.105.0/lib/roda/plugins/mailer.rb +283 -0
- data/roda-3.105.0/lib/roda/plugins/map_matcher.rb +48 -0
- data/roda-3.105.0/lib/roda/plugins/match_affix.rb +64 -0
- data/roda-3.105.0/lib/roda/plugins/match_hook.rb +34 -0
- data/roda-3.105.0/lib/roda/plugins/match_hook_args.rb +93 -0
- data/roda-3.105.0/lib/roda/plugins/middleware.rb +225 -0
- data/roda-3.105.0/lib/roda/plugins/middleware_stack.rb +101 -0
- data/roda-3.105.0/lib/roda/plugins/module_include.rb +96 -0
- data/roda-3.105.0/lib/roda/plugins/multi_public.rb +95 -0
- data/roda-3.105.0/lib/roda/plugins/multi_route.rb +156 -0
- data/roda-3.105.0/lib/roda/plugins/multi_run.rb +144 -0
- data/roda-3.105.0/lib/roda/plugins/multi_view.rb +83 -0
- data/roda-3.105.0/lib/roda/plugins/multibyte_string_matcher.rb +57 -0
- data/roda-3.105.0/lib/roda/plugins/named_routes.rb +167 -0
- data/roda-3.105.0/lib/roda/plugins/named_templates.rb +102 -0
- data/roda-3.105.0/lib/roda/plugins/not_allowed.rb +149 -0
- data/roda-3.105.0/lib/roda/plugins/not_found.rb +55 -0
- data/roda-3.105.0/lib/roda/plugins/optimized_segment_matchers.rb +53 -0
- data/roda-3.105.0/lib/roda/plugins/optimized_string_matchers.rb +50 -0
- data/roda-3.105.0/lib/roda/plugins/padrino_render.rb +42 -0
- data/roda-3.105.0/lib/roda/plugins/param_matchers.rb +83 -0
- data/roda-3.105.0/lib/roda/plugins/params_capturing.rb +116 -0
- data/roda-3.105.0/lib/roda/plugins/part.rb +76 -0
- data/roda-3.105.0/lib/roda/plugins/partials.rb +74 -0
- data/roda-3.105.0/lib/roda/plugins/pass.rb +47 -0
- data/roda-3.105.0/lib/roda/plugins/path.rb +255 -0
- data/roda-3.105.0/lib/roda/plugins/path_matchers.rb +54 -0
- data/roda-3.105.0/lib/roda/plugins/path_rewriter.rb +111 -0
- data/roda-3.105.0/lib/roda/plugins/permissions_policy.rb +336 -0
- data/roda-3.105.0/lib/roda/plugins/placeholder_string_matchers.rb +48 -0
- data/roda-3.105.0/lib/roda/plugins/plain_hash_response_headers.rb +32 -0
- data/roda-3.105.0/lib/roda/plugins/precompile_templates.rb +156 -0
- data/roda-3.105.0/lib/roda/plugins/public.rb +182 -0
- data/roda-3.105.0/lib/roda/plugins/r.rb +35 -0
- data/roda-3.105.0/lib/roda/plugins/recheck_precompiled_assets.rb +107 -0
- data/roda-3.105.0/lib/roda/plugins/redirect_http_to_https.rb +99 -0
- data/roda-3.105.0/lib/roda/plugins/redirect_path.rb +59 -0
- data/roda-3.105.0/lib/roda/plugins/relative_path.rb +74 -0
- data/roda-3.105.0/lib/roda/plugins/render.rb +998 -0
- data/roda-3.105.0/lib/roda/plugins/render_coverage.rb +105 -0
- data/roda-3.105.0/lib/roda/plugins/render_each.rb +224 -0
- data/roda-3.105.0/lib/roda/plugins/render_locals.rb +102 -0
- data/roda-3.105.0/lib/roda/plugins/request_aref.rb +77 -0
- data/roda-3.105.0/lib/roda/plugins/request_headers.rb +81 -0
- data/roda-3.105.0/lib/roda/plugins/response_attachment.rb +94 -0
- data/roda-3.105.0/lib/roda/plugins/response_content_type.rb +79 -0
- data/roda-3.105.0/lib/roda/plugins/response_request.rb +29 -0
- data/roda-3.105.0/lib/roda/plugins/route_block_args.rb +50 -0
- data/roda-3.105.0/lib/roda/plugins/route_csrf.rb +388 -0
- data/roda-3.105.0/lib/roda/plugins/run_append_slash.rb +51 -0
- data/roda-3.105.0/lib/roda/plugins/run_handler.rb +51 -0
- data/roda-3.105.0/lib/roda/plugins/run_require_slash.rb +46 -0
- data/roda-3.105.0/lib/roda/plugins/sec_fetch_site_csrf.rb +131 -0
- data/roda-3.105.0/lib/roda/plugins/send_file.rb +127 -0
- data/roda-3.105.0/lib/roda/plugins/sessions.rb +537 -0
- data/roda-3.105.0/lib/roda/plugins/shared_vars.rb +86 -0
- data/roda-3.105.0/lib/roda/plugins/sinatra_helpers.rb +443 -0
- data/roda-3.105.0/lib/roda/plugins/slash_path_empty.rb +26 -0
- data/roda-3.105.0/lib/roda/plugins/static.rb +42 -0
- data/roda-3.105.0/lib/roda/plugins/static_routing.rb +89 -0
- data/roda-3.105.0/lib/roda/plugins/status_303.rb +34 -0
- data/roda-3.105.0/lib/roda/plugins/status_handler.rb +86 -0
- data/roda-3.105.0/lib/roda/plugins/streaming.rb +170 -0
- data/roda-3.105.0/lib/roda/plugins/strip_path_prefix.rb +33 -0
- data/roda-3.105.0/lib/roda/plugins/symbol_matchers.rb +188 -0
- data/roda-3.105.0/lib/roda/plugins/symbol_status.rb +32 -0
- data/roda-3.105.0/lib/roda/plugins/symbol_views.rb +37 -0
- data/roda-3.105.0/lib/roda/plugins/timestamp_public.rb +78 -0
- data/roda-3.105.0/lib/roda/plugins/type_routing.rb +215 -0
- data/roda-3.105.0/lib/roda/plugins/typecast_params.rb +1183 -0
- data/roda-3.105.0/lib/roda/plugins/typecast_params_sized_integers.rb +108 -0
- data/roda-3.105.0/lib/roda/plugins/unescape_path.rb +41 -0
- data/roda-3.105.0/lib/roda/plugins/view_options.rb +201 -0
- data/roda-3.105.0/lib/roda/plugins/view_subdir_leading_slash.rb +49 -0
- data/roda-3.105.0/lib/roda/plugins.rb +68 -0
- data/roda-3.105.0/lib/roda/request.rb +722 -0
- data/roda-3.105.0/lib/roda/response.rb +221 -0
- data/roda-3.105.0/lib/roda/session_middleware.rb +183 -0
- data/roda-3.105.0/lib/roda/version.rb +18 -0
- data/roda-3.105.0/lib/roda.rb +586 -0
- data/ultra-lite-hub.gemspec +12 -0
- metadata +201 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
require 'erb/escape'
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
class Roda
|
|
7
|
+
module RodaPlugins
|
|
8
|
+
# The erb_h plugin adds an +h+ instance method that will HTML
|
|
9
|
+
# escape the input and return it. This is similar to the h
|
|
10
|
+
# plugin, but it uses erb/escape to implement the HTML escaping,
|
|
11
|
+
# which offers faster performance.
|
|
12
|
+
#
|
|
13
|
+
# To make sure that this speeds up applications using the h
|
|
14
|
+
# plugin, this depends on the h plugin, and overrides the
|
|
15
|
+
# h method.
|
|
16
|
+
#
|
|
17
|
+
# The following example will return "<foo>" as the body.
|
|
18
|
+
#
|
|
19
|
+
# plugin :erb_h
|
|
20
|
+
#
|
|
21
|
+
# route do |r|
|
|
22
|
+
# h('<foo>')
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# The faster performance offered by the erb_h plugin is due
|
|
26
|
+
# to erb/escape avoiding allocations if not needed (returning the
|
|
27
|
+
# input object if no escaping is needed). That behavior change
|
|
28
|
+
# can cause problems if you mutate the result of the h method
|
|
29
|
+
# (which can mutate the input), or mutate the input of the h
|
|
30
|
+
# method after calling it (which can mutate the result).
|
|
31
|
+
module ErbH
|
|
32
|
+
def self.load_dependencies(app)
|
|
33
|
+
app.plugin :h
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
module InstanceMethods
|
|
37
|
+
define_method(:h, ERB::Escape.instance_method(:html_escape))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
register_plugin(:erb_h, ErbH)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
require 'net/smtp'
|
|
4
|
+
|
|
5
|
+
class Roda
|
|
6
|
+
module RodaPlugins
|
|
7
|
+
# The error_email plugin adds an +error_email+ instance method that
|
|
8
|
+
# send an email related to the exception. This is most useful if you are
|
|
9
|
+
# also using the error_handler plugin:
|
|
10
|
+
#
|
|
11
|
+
# plugin :error_email, to: 'to@example.com', from: 'from@example.com'
|
|
12
|
+
# plugin :error_handler do |e|
|
|
13
|
+
# error_email(e)
|
|
14
|
+
# 'Internal Server Error'
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# It is similar to the error_mail plugin, except that it uses net/smtp
|
|
18
|
+
# directly instead of using the mail library. If you are not already using the
|
|
19
|
+
# mail library in your application, it makes sense to use error_email
|
|
20
|
+
# instead of error_mail.
|
|
21
|
+
#
|
|
22
|
+
# Options:
|
|
23
|
+
#
|
|
24
|
+
# :filter :: Callable called with the key and value for each parameter, environment
|
|
25
|
+
# variable, and session value. If it returns true, the value of the
|
|
26
|
+
# parameter is filtered in the email.
|
|
27
|
+
# :from :: The From address to use in the email (required)
|
|
28
|
+
# :headers :: A hash of additional headers to use in the email (default: empty hash)
|
|
29
|
+
# :host :: The SMTP server to use to send the email (default: localhost)
|
|
30
|
+
# :prefix :: A prefix to use in the email's subject line (default: no prefix)
|
|
31
|
+
# :to :: The To address to use in the email (required)
|
|
32
|
+
#
|
|
33
|
+
# The subject of the error email shows the exception class and message.
|
|
34
|
+
# The body of the error email shows the backtrace of the error and the
|
|
35
|
+
# request environment, as well the request params and session variables (if any).
|
|
36
|
+
# You can also call error_email with a plain string instead of an exception,
|
|
37
|
+
# in which case the string is used as the subject, and no backtrace is included.
|
|
38
|
+
#
|
|
39
|
+
# Note that emailing on every error as shown above is only appropriate
|
|
40
|
+
# for low traffic web applications. For high traffic web applications,
|
|
41
|
+
# use an error reporting service instead of this plugin.
|
|
42
|
+
module ErrorEmail
|
|
43
|
+
DEFAULTS = {
|
|
44
|
+
:filter=>lambda{|k,v| false},
|
|
45
|
+
:headers=>OPTS,
|
|
46
|
+
:host=>'localhost',
|
|
47
|
+
# :nocov:
|
|
48
|
+
:emailer=>lambda{|h| Net::SMTP.start(h[:host]){|s| s.send_message(h[:message], h[:from], h[:to])}},
|
|
49
|
+
# :nocov:
|
|
50
|
+
:default_headers=>lambda do |h, e|
|
|
51
|
+
subject = if e.respond_to?(:message)
|
|
52
|
+
"#{e.class}: #{e.message}"
|
|
53
|
+
else
|
|
54
|
+
e.to_s
|
|
55
|
+
end
|
|
56
|
+
{'From'=>h[:from], 'To'=>h[:to], 'Subject'=>"#{h[:prefix]}#{subject}"}
|
|
57
|
+
end,
|
|
58
|
+
:body=>lambda do |s, e|
|
|
59
|
+
filter = s.opts[:error_email][:filter]
|
|
60
|
+
format = lambda do |h|
|
|
61
|
+
h = h.map{|k, v| "#{k.inspect} => #{filter.call(k, v) ? 'FILTERED' : v.inspect}"}
|
|
62
|
+
h.sort!
|
|
63
|
+
h.join("\n")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
begin
|
|
67
|
+
params = s.request.params
|
|
68
|
+
params = (format[params] unless params.empty?)
|
|
69
|
+
rescue
|
|
70
|
+
params = 'Invalid Parameters!'
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
message = String.new
|
|
74
|
+
message << <<END
|
|
75
|
+
Path: #{s.request.path}
|
|
76
|
+
|
|
77
|
+
END
|
|
78
|
+
if e.respond_to?(:backtrace)
|
|
79
|
+
message << <<END
|
|
80
|
+
Backtrace:
|
|
81
|
+
|
|
82
|
+
#{e.backtrace.join("\n")}
|
|
83
|
+
END
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
message << <<END
|
|
87
|
+
ENV:
|
|
88
|
+
|
|
89
|
+
#{format[s.env]}
|
|
90
|
+
END
|
|
91
|
+
|
|
92
|
+
if params
|
|
93
|
+
message << <<END
|
|
94
|
+
|
|
95
|
+
Params:
|
|
96
|
+
|
|
97
|
+
#{params}
|
|
98
|
+
END
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
if s.env['rack.session']
|
|
102
|
+
message << <<END
|
|
103
|
+
|
|
104
|
+
Session:
|
|
105
|
+
|
|
106
|
+
#{format[s.session]}
|
|
107
|
+
END
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
message
|
|
111
|
+
end
|
|
112
|
+
}.freeze
|
|
113
|
+
|
|
114
|
+
# Set default opts for plugin. See ErrorEmail module RDoc for options.
|
|
115
|
+
def self.configure(app, opts=OPTS)
|
|
116
|
+
email_opts = app.opts[:error_email] ||= DEFAULTS
|
|
117
|
+
email_opts = email_opts.merge(opts)
|
|
118
|
+
email_opts[:headers] = email_opts[:headers].dup
|
|
119
|
+
unless email_opts[:to] && email_opts[:from]
|
|
120
|
+
raise RodaError, "must provide :to and :from options to error_email plugin"
|
|
121
|
+
end
|
|
122
|
+
app.opts[:error_email] = email_opts
|
|
123
|
+
app.opts[:error_email][:headers].freeze
|
|
124
|
+
app.opts[:error_email].freeze
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
module InstanceMethods
|
|
128
|
+
# Send an email for the given error. +exception+ is usually an exception
|
|
129
|
+
# instance, but it can be a plain string which is used as the subject for
|
|
130
|
+
# the email.
|
|
131
|
+
def error_email(exception)
|
|
132
|
+
email_opts = self.class.opts[:error_email].dup
|
|
133
|
+
email_opts[:message] = error_email_content(exception)
|
|
134
|
+
email_opts[:emailer].call(email_opts)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# The content of the email to send, include the headers and the body.
|
|
138
|
+
# Takes the same argument as #error_email.
|
|
139
|
+
def error_email_content(exception)
|
|
140
|
+
email_opts = self.class.opts[:error_email]
|
|
141
|
+
headers = email_opts[:default_headers].call(email_opts, exception)
|
|
142
|
+
headers = headers.merge(email_opts[:headers])
|
|
143
|
+
headers = headers.map{|k,v| "#{k}: #{v.gsub(/\r?\n/m, "\r\n ")}"}.sort.join("\r\n")
|
|
144
|
+
body = email_opts[:body].call(self, exception)
|
|
145
|
+
"#{headers}\r\n\r\n#{body}"
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
register_plugin(:error_email, ErrorEmail)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The error_handler plugin adds an error handler to the routing,
|
|
7
|
+
# so that if routing the request raises an error, a nice error
|
|
8
|
+
# message page can be returned to the user.
|
|
9
|
+
#
|
|
10
|
+
# You can provide the error handler as a block to the plugin:
|
|
11
|
+
#
|
|
12
|
+
# plugin :error_handler do |e|
|
|
13
|
+
# "Oh No!"
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# Or later via the +error+ class method:
|
|
17
|
+
#
|
|
18
|
+
# plugin :error_handler
|
|
19
|
+
#
|
|
20
|
+
# error do |e|
|
|
21
|
+
# "Oh No!"
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# In both cases, the exception instance is passed into the block,
|
|
25
|
+
# and the block can return the request body via a string.
|
|
26
|
+
#
|
|
27
|
+
# If an exception is raised, a new response will be used, with the
|
|
28
|
+
# default status set to 500, before executing the error handler.
|
|
29
|
+
# The error handler can change the response status if necessary,
|
|
30
|
+
# as well set headers and/or write to the body, just like a regular
|
|
31
|
+
# request. After the error handler returns a response, normal after
|
|
32
|
+
# processing of that response occurs, except that an exception during
|
|
33
|
+
# after processing is logged to <tt>env['rack.errors']</tt> but
|
|
34
|
+
# otherwise ignored. This avoids recursive calls into the
|
|
35
|
+
# error_handler. Note that if the error_handler itself raises
|
|
36
|
+
# an exception, the exception will be raised without normal after
|
|
37
|
+
# processing. This can cause some after processing to run twice
|
|
38
|
+
# (once before the error_handler is called and once after) if
|
|
39
|
+
# later after processing raises an exception.
|
|
40
|
+
#
|
|
41
|
+
# By default, this plugin handles StandardError and ScriptError.
|
|
42
|
+
# To override the exception classes it will handle, pass a :classes
|
|
43
|
+
# option to the plugin:
|
|
44
|
+
#
|
|
45
|
+
# plugin :error_handler, classes: [StandardError, ScriptError, NoMemoryError]
|
|
46
|
+
module ErrorHandler
|
|
47
|
+
DEFAULT_ERROR_HANDLER_CLASSES = [StandardError, ScriptError].freeze
|
|
48
|
+
|
|
49
|
+
# If a block is given, automatically call the +error+ method on
|
|
50
|
+
# the Roda class with it.
|
|
51
|
+
def self.configure(app, opts={}, &block)
|
|
52
|
+
app.opts[:error_handler_classes] = (opts[:classes] || app.opts[:error_handler_classes] || DEFAULT_ERROR_HANDLER_CLASSES).dup.freeze
|
|
53
|
+
|
|
54
|
+
if block
|
|
55
|
+
app.error(&block)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
module ClassMethods
|
|
60
|
+
# Install the given block as the error handler, so that if routing
|
|
61
|
+
# the request raises an exception, the block will be called with
|
|
62
|
+
# the exception in the scope of the Roda instance.
|
|
63
|
+
def error(&block)
|
|
64
|
+
define_method(:handle_error, &block)
|
|
65
|
+
alias_method(:handle_error, :handle_error)
|
|
66
|
+
private :handle_error
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
module InstanceMethods
|
|
71
|
+
# If an error occurs, set the response status to 500 and call
|
|
72
|
+
# the error handler. Old Dispatch API.
|
|
73
|
+
def call
|
|
74
|
+
# RODA4: Remove
|
|
75
|
+
begin
|
|
76
|
+
res = super
|
|
77
|
+
ensure
|
|
78
|
+
_roda_after(res)
|
|
79
|
+
end
|
|
80
|
+
rescue *opts[:error_handler_classes] => e
|
|
81
|
+
_handle_error(e)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# If an error occurs, set the response status to 500 and call
|
|
85
|
+
# the error handler.
|
|
86
|
+
def _roda_handle_main_route
|
|
87
|
+
begin
|
|
88
|
+
res = super
|
|
89
|
+
ensure
|
|
90
|
+
_roda_after(res)
|
|
91
|
+
end
|
|
92
|
+
rescue *opts[:error_handler_classes] => e
|
|
93
|
+
_handle_error(e)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
# Default empty implementation of _roda_after, usually
|
|
99
|
+
# overridden by Roda.def_roda_before.
|
|
100
|
+
def _roda_after(res)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Handle the given exception using handle_error, using a default status
|
|
104
|
+
# of 500. Run after hooks on the rack response, but if any error occurs
|
|
105
|
+
# when doing so, log the error using rack.errors and return the response.
|
|
106
|
+
def _handle_error(e)
|
|
107
|
+
res = @_response
|
|
108
|
+
res.send(:initialize)
|
|
109
|
+
res.status = 500
|
|
110
|
+
res = _roda_handle_route{handle_error(e)}
|
|
111
|
+
begin
|
|
112
|
+
_roda_after(res)
|
|
113
|
+
rescue => e2
|
|
114
|
+
if errors = env['rack.errors']
|
|
115
|
+
errors.puts "Error in after hook processing of error handler: #{e2.class}: #{e2.message}"
|
|
116
|
+
e2.backtrace.each{|line| errors.puts(line)}
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
res
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# By default, have the error handler reraise the error, so using
|
|
123
|
+
# the plugin without installing an error handler doesn't change
|
|
124
|
+
# behavior.
|
|
125
|
+
def handle_error(e)
|
|
126
|
+
raise e
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
register_plugin(:error_handler, ErrorHandler)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
require 'mail'
|
|
4
|
+
|
|
5
|
+
class Roda
|
|
6
|
+
module RodaPlugins
|
|
7
|
+
# The error_mail plugin adds an +error_mail+ instance method that
|
|
8
|
+
# send an email related to the exception. This is most useful if you are
|
|
9
|
+
# also using the error_handler plugin:
|
|
10
|
+
#
|
|
11
|
+
# plugin :error_mail, to: 'to@example.com', from: 'from@example.com'
|
|
12
|
+
# plugin :error_handler do |e|
|
|
13
|
+
# error_mail(e)
|
|
14
|
+
# 'Internal Server Error'
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# It is similar to the error_email plugin, except that it uses the mail
|
|
18
|
+
# library instead of net/smtp directly. If you are already using the
|
|
19
|
+
# mail library in your application, it makes sense to use error_mail
|
|
20
|
+
# instead of error_email.
|
|
21
|
+
#
|
|
22
|
+
# Options:
|
|
23
|
+
#
|
|
24
|
+
# :filter :: Callable called with the key and value for each parameter, environment
|
|
25
|
+
# variable, and session value. If it returns true, the value of the
|
|
26
|
+
# parameter is filtered in the email.
|
|
27
|
+
# :from :: The From address to use in the email (required)
|
|
28
|
+
# :headers :: A hash of additional headers to use in the email (default: empty hash)
|
|
29
|
+
# :prefix :: A prefix to use in the email's subject line (default: no prefix)
|
|
30
|
+
# :to :: The To address to use in the email (required)
|
|
31
|
+
#
|
|
32
|
+
# The subject of the error email shows the exception class and message.
|
|
33
|
+
# The body of the error email shows the backtrace of the error and the
|
|
34
|
+
# request environment, as well the request params and session variables (if any).
|
|
35
|
+
# You can also call error_mail with a plain string instead of an exception,
|
|
36
|
+
# in which case the string is used as the subject, and no backtrace is included.
|
|
37
|
+
#
|
|
38
|
+
# Note that emailing on every error as shown above is only appropriate
|
|
39
|
+
# for low traffic web applications. For high traffic web applications,
|
|
40
|
+
# use an error reporting service instead of this plugin.
|
|
41
|
+
module ErrorMail
|
|
42
|
+
DEFAULT_FILTER = lambda{|k,v| false}
|
|
43
|
+
private_constant :DEFAULT_FILTER
|
|
44
|
+
|
|
45
|
+
# Set default opts for plugin. See ErrorEmail module RDoc for options.
|
|
46
|
+
def self.configure(app, opts=OPTS)
|
|
47
|
+
app.opts[:error_mail] = email_opts = (app.opts[:error_mail] || {:filter=>DEFAULT_FILTER}).merge(opts).freeze
|
|
48
|
+
unless email_opts[:to] && email_opts[:from]
|
|
49
|
+
raise RodaError, "must provide :to and :from options to error_mail plugin"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
module InstanceMethods
|
|
54
|
+
# Send an email for the given error. +exception+ is usually an exception
|
|
55
|
+
# instance, but it can be a plain string which is used as the subject for
|
|
56
|
+
# the email.
|
|
57
|
+
def error_mail(exception)
|
|
58
|
+
_error_mail(exception).deliver!
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# The content of the email to send, include the headers and the body.
|
|
62
|
+
# Takes the same argument as #error_mail.
|
|
63
|
+
def error_mail_content(exception)
|
|
64
|
+
_error_mail(exception).to_s
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def _error_mail(e)
|
|
70
|
+
email_opts = self.class.opts[:error_mail]
|
|
71
|
+
subject = if e.respond_to?(:message)
|
|
72
|
+
"#{e.class}: #{e.message}"
|
|
73
|
+
else
|
|
74
|
+
e.to_s
|
|
75
|
+
end
|
|
76
|
+
subject = "#{email_opts[:prefix]}#{subject}"
|
|
77
|
+
filter = email_opts[:filter]
|
|
78
|
+
|
|
79
|
+
format = lambda do |h|
|
|
80
|
+
h = h.map{|k, v| "#{k.inspect} => #{filter.call(k, v) ? 'FILTERED' : v.inspect}"}
|
|
81
|
+
h.sort!
|
|
82
|
+
h.join("\n")
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
begin
|
|
86
|
+
params = request.params
|
|
87
|
+
params = (format[params] unless params.empty?)
|
|
88
|
+
rescue
|
|
89
|
+
params = 'Invalid Parameters!'
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
message = String.new
|
|
93
|
+
message << <<END
|
|
94
|
+
Path: #{request.path}
|
|
95
|
+
|
|
96
|
+
END
|
|
97
|
+
if e.respond_to?(:backtrace)
|
|
98
|
+
message << <<END
|
|
99
|
+
Backtrace:
|
|
100
|
+
|
|
101
|
+
#{e.backtrace.join("\n")}
|
|
102
|
+
END
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
message << <<END
|
|
106
|
+
|
|
107
|
+
ENV:
|
|
108
|
+
|
|
109
|
+
#{format[env]}
|
|
110
|
+
END
|
|
111
|
+
|
|
112
|
+
if params
|
|
113
|
+
message << <<END
|
|
114
|
+
|
|
115
|
+
Params:
|
|
116
|
+
|
|
117
|
+
#{params}
|
|
118
|
+
END
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
if env['rack.session']
|
|
122
|
+
message << <<END
|
|
123
|
+
|
|
124
|
+
Session:
|
|
125
|
+
|
|
126
|
+
#{format[session]}
|
|
127
|
+
END
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
Mail.new do
|
|
132
|
+
from email_opts[:from]
|
|
133
|
+
to email_opts[:to]
|
|
134
|
+
subject subject
|
|
135
|
+
body message
|
|
136
|
+
|
|
137
|
+
if headers = email_opts[:headers]
|
|
138
|
+
headers.each do |k,v|
|
|
139
|
+
header[k] = v
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
register_plugin(:error_mail, ErrorMail)
|
|
148
|
+
end
|
|
149
|
+
end
|