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.
Files changed (162) hide show
  1. checksums.yaml +7 -0
  2. data/roda-3.105.0/MIT-LICENSE +21 -0
  3. data/roda-3.105.0/lib/roda/cache.rb +42 -0
  4. data/roda-3.105.0/lib/roda/plugins/Integer_matcher_max.rb +55 -0
  5. data/roda-3.105.0/lib/roda/plugins/_after_hook.rb +11 -0
  6. data/roda-3.105.0/lib/roda/plugins/_base64.rb +34 -0
  7. data/roda-3.105.0/lib/roda/plugins/_before_hook.rb +41 -0
  8. data/roda-3.105.0/lib/roda/plugins/_optimized_matching.rb +227 -0
  9. data/roda-3.105.0/lib/roda/plugins/_symbol_class_matchers.rb +108 -0
  10. data/roda-3.105.0/lib/roda/plugins/_symbol_regexp_matchers.rb +24 -0
  11. data/roda-3.105.0/lib/roda/plugins/additional_render_engines.rb +61 -0
  12. data/roda-3.105.0/lib/roda/plugins/additional_view_directories.rb +66 -0
  13. data/roda-3.105.0/lib/roda/plugins/all_verbs.rb +50 -0
  14. data/roda-3.105.0/lib/roda/plugins/assets.rb +902 -0
  15. data/roda-3.105.0/lib/roda/plugins/assets_preloading.rb +89 -0
  16. data/roda-3.105.0/lib/roda/plugins/assume_ssl.rb +28 -0
  17. data/roda-3.105.0/lib/roda/plugins/autoload_hash_branches.rb +79 -0
  18. data/roda-3.105.0/lib/roda/plugins/autoload_named_routes.rb +65 -0
  19. data/roda-3.105.0/lib/roda/plugins/backtracking_array.rb +88 -0
  20. data/roda-3.105.0/lib/roda/plugins/bearer_token.rb +28 -0
  21. data/roda-3.105.0/lib/roda/plugins/branch_locals.rb +74 -0
  22. data/roda-3.105.0/lib/roda/plugins/break.rb +43 -0
  23. data/roda-3.105.0/lib/roda/plugins/caching.rb +206 -0
  24. data/roda-3.105.0/lib/roda/plugins/capture_erb.rb +94 -0
  25. data/roda-3.105.0/lib/roda/plugins/chunked.rb +331 -0
  26. data/roda-3.105.0/lib/roda/plugins/class_level_routing.rb +111 -0
  27. data/roda-3.105.0/lib/roda/plugins/class_matchers.rb +155 -0
  28. data/roda-3.105.0/lib/roda/plugins/common_logger.rb +80 -0
  29. data/roda-3.105.0/lib/roda/plugins/conditional_sessions.rb +67 -0
  30. data/roda-3.105.0/lib/roda/plugins/content_for.rb +103 -0
  31. data/roda-3.105.0/lib/roda/plugins/content_security_policy.rb +329 -0
  32. data/roda-3.105.0/lib/roda/plugins/cookie_flags.rb +157 -0
  33. data/roda-3.105.0/lib/roda/plugins/cookies.rb +51 -0
  34. data/roda-3.105.0/lib/roda/plugins/csrf.rb +81 -0
  35. data/roda-3.105.0/lib/roda/plugins/custom_block_results.rb +85 -0
  36. data/roda-3.105.0/lib/roda/plugins/custom_matchers.rb +89 -0
  37. data/roda-3.105.0/lib/roda/plugins/default_headers.rb +64 -0
  38. data/roda-3.105.0/lib/roda/plugins/default_status.rb +35 -0
  39. data/roda-3.105.0/lib/roda/plugins/delay_build.rb +18 -0
  40. data/roda-3.105.0/lib/roda/plugins/delegate.rb +77 -0
  41. data/roda-3.105.0/lib/roda/plugins/delete_empty_headers.rb +36 -0
  42. data/roda-3.105.0/lib/roda/plugins/direct_call.rb +38 -0
  43. data/roda-3.105.0/lib/roda/plugins/disallow_file_uploads.rb +38 -0
  44. data/roda-3.105.0/lib/roda/plugins/drop_body.rb +43 -0
  45. data/roda-3.105.0/lib/roda/plugins/each_part.rb +87 -0
  46. data/roda-3.105.0/lib/roda/plugins/early_hints.rb +25 -0
  47. data/roda-3.105.0/lib/roda/plugins/empty_root.rb +49 -0
  48. data/roda-3.105.0/lib/roda/plugins/environments.rb +79 -0
  49. data/roda-3.105.0/lib/roda/plugins/erb_h.rb +43 -0
  50. data/roda-3.105.0/lib/roda/plugins/error_email.rb +152 -0
  51. data/roda-3.105.0/lib/roda/plugins/error_handler.rb +133 -0
  52. data/roda-3.105.0/lib/roda/plugins/error_mail.rb +149 -0
  53. data/roda-3.105.0/lib/roda/plugins/exception_page.rb +445 -0
  54. data/roda-3.105.0/lib/roda/plugins/filter_common_logger.rb +46 -0
  55. data/roda-3.105.0/lib/roda/plugins/flash.rb +117 -0
  56. data/roda-3.105.0/lib/roda/plugins/h.rb +59 -0
  57. data/roda-3.105.0/lib/roda/plugins/halt.rb +108 -0
  58. data/roda-3.105.0/lib/roda/plugins/hash_branch_view_subdir.rb +76 -0
  59. data/roda-3.105.0/lib/roda/plugins/hash_branches.rb +145 -0
  60. data/roda-3.105.0/lib/roda/plugins/hash_matcher.rb +39 -0
  61. data/roda-3.105.0/lib/roda/plugins/hash_paths.rb +128 -0
  62. data/roda-3.105.0/lib/roda/plugins/hash_public.rb +125 -0
  63. data/roda-3.105.0/lib/roda/plugins/hash_public_cache.rb +91 -0
  64. data/roda-3.105.0/lib/roda/plugins/hash_routes.rb +304 -0
  65. data/roda-3.105.0/lib/roda/plugins/head.rb +99 -0
  66. data/roda-3.105.0/lib/roda/plugins/header_matchers.rb +88 -0
  67. data/roda-3.105.0/lib/roda/plugins/heartbeat.rb +41 -0
  68. data/roda-3.105.0/lib/roda/plugins/hmac_paths.rb +413 -0
  69. data/roda-3.105.0/lib/roda/plugins/hooks.rb +92 -0
  70. data/roda-3.105.0/lib/roda/plugins/host_authorization.rb +155 -0
  71. data/roda-3.105.0/lib/roda/plugins/host_routing.rb +190 -0
  72. data/roda-3.105.0/lib/roda/plugins/hsts.rb +35 -0
  73. data/roda-3.105.0/lib/roda/plugins/indifferent_params.rb +124 -0
  74. data/roda-3.105.0/lib/roda/plugins/inject_erb.rb +33 -0
  75. data/roda-3.105.0/lib/roda/plugins/invalid_request_body.rb +107 -0
  76. data/roda-3.105.0/lib/roda/plugins/ip_from_header.rb +34 -0
  77. data/roda-3.105.0/lib/roda/plugins/json.rb +119 -0
  78. data/roda-3.105.0/lib/roda/plugins/json_parser.rb +107 -0
  79. data/roda-3.105.0/lib/roda/plugins/link_to.rb +83 -0
  80. data/roda-3.105.0/lib/roda/plugins/mail_processor.rb +629 -0
  81. data/roda-3.105.0/lib/roda/plugins/mailer.rb +283 -0
  82. data/roda-3.105.0/lib/roda/plugins/map_matcher.rb +48 -0
  83. data/roda-3.105.0/lib/roda/plugins/match_affix.rb +64 -0
  84. data/roda-3.105.0/lib/roda/plugins/match_hook.rb +34 -0
  85. data/roda-3.105.0/lib/roda/plugins/match_hook_args.rb +93 -0
  86. data/roda-3.105.0/lib/roda/plugins/middleware.rb +225 -0
  87. data/roda-3.105.0/lib/roda/plugins/middleware_stack.rb +101 -0
  88. data/roda-3.105.0/lib/roda/plugins/module_include.rb +96 -0
  89. data/roda-3.105.0/lib/roda/plugins/multi_public.rb +95 -0
  90. data/roda-3.105.0/lib/roda/plugins/multi_route.rb +156 -0
  91. data/roda-3.105.0/lib/roda/plugins/multi_run.rb +144 -0
  92. data/roda-3.105.0/lib/roda/plugins/multi_view.rb +83 -0
  93. data/roda-3.105.0/lib/roda/plugins/multibyte_string_matcher.rb +57 -0
  94. data/roda-3.105.0/lib/roda/plugins/named_routes.rb +167 -0
  95. data/roda-3.105.0/lib/roda/plugins/named_templates.rb +102 -0
  96. data/roda-3.105.0/lib/roda/plugins/not_allowed.rb +149 -0
  97. data/roda-3.105.0/lib/roda/plugins/not_found.rb +55 -0
  98. data/roda-3.105.0/lib/roda/plugins/optimized_segment_matchers.rb +53 -0
  99. data/roda-3.105.0/lib/roda/plugins/optimized_string_matchers.rb +50 -0
  100. data/roda-3.105.0/lib/roda/plugins/padrino_render.rb +42 -0
  101. data/roda-3.105.0/lib/roda/plugins/param_matchers.rb +83 -0
  102. data/roda-3.105.0/lib/roda/plugins/params_capturing.rb +116 -0
  103. data/roda-3.105.0/lib/roda/plugins/part.rb +76 -0
  104. data/roda-3.105.0/lib/roda/plugins/partials.rb +74 -0
  105. data/roda-3.105.0/lib/roda/plugins/pass.rb +47 -0
  106. data/roda-3.105.0/lib/roda/plugins/path.rb +255 -0
  107. data/roda-3.105.0/lib/roda/plugins/path_matchers.rb +54 -0
  108. data/roda-3.105.0/lib/roda/plugins/path_rewriter.rb +111 -0
  109. data/roda-3.105.0/lib/roda/plugins/permissions_policy.rb +336 -0
  110. data/roda-3.105.0/lib/roda/plugins/placeholder_string_matchers.rb +48 -0
  111. data/roda-3.105.0/lib/roda/plugins/plain_hash_response_headers.rb +32 -0
  112. data/roda-3.105.0/lib/roda/plugins/precompile_templates.rb +156 -0
  113. data/roda-3.105.0/lib/roda/plugins/public.rb +182 -0
  114. data/roda-3.105.0/lib/roda/plugins/r.rb +35 -0
  115. data/roda-3.105.0/lib/roda/plugins/recheck_precompiled_assets.rb +107 -0
  116. data/roda-3.105.0/lib/roda/plugins/redirect_http_to_https.rb +99 -0
  117. data/roda-3.105.0/lib/roda/plugins/redirect_path.rb +59 -0
  118. data/roda-3.105.0/lib/roda/plugins/relative_path.rb +74 -0
  119. data/roda-3.105.0/lib/roda/plugins/render.rb +998 -0
  120. data/roda-3.105.0/lib/roda/plugins/render_coverage.rb +105 -0
  121. data/roda-3.105.0/lib/roda/plugins/render_each.rb +224 -0
  122. data/roda-3.105.0/lib/roda/plugins/render_locals.rb +102 -0
  123. data/roda-3.105.0/lib/roda/plugins/request_aref.rb +77 -0
  124. data/roda-3.105.0/lib/roda/plugins/request_headers.rb +81 -0
  125. data/roda-3.105.0/lib/roda/plugins/response_attachment.rb +94 -0
  126. data/roda-3.105.0/lib/roda/plugins/response_content_type.rb +79 -0
  127. data/roda-3.105.0/lib/roda/plugins/response_request.rb +29 -0
  128. data/roda-3.105.0/lib/roda/plugins/route_block_args.rb +50 -0
  129. data/roda-3.105.0/lib/roda/plugins/route_csrf.rb +388 -0
  130. data/roda-3.105.0/lib/roda/plugins/run_append_slash.rb +51 -0
  131. data/roda-3.105.0/lib/roda/plugins/run_handler.rb +51 -0
  132. data/roda-3.105.0/lib/roda/plugins/run_require_slash.rb +46 -0
  133. data/roda-3.105.0/lib/roda/plugins/sec_fetch_site_csrf.rb +131 -0
  134. data/roda-3.105.0/lib/roda/plugins/send_file.rb +127 -0
  135. data/roda-3.105.0/lib/roda/plugins/sessions.rb +537 -0
  136. data/roda-3.105.0/lib/roda/plugins/shared_vars.rb +86 -0
  137. data/roda-3.105.0/lib/roda/plugins/sinatra_helpers.rb +443 -0
  138. data/roda-3.105.0/lib/roda/plugins/slash_path_empty.rb +26 -0
  139. data/roda-3.105.0/lib/roda/plugins/static.rb +42 -0
  140. data/roda-3.105.0/lib/roda/plugins/static_routing.rb +89 -0
  141. data/roda-3.105.0/lib/roda/plugins/status_303.rb +34 -0
  142. data/roda-3.105.0/lib/roda/plugins/status_handler.rb +86 -0
  143. data/roda-3.105.0/lib/roda/plugins/streaming.rb +170 -0
  144. data/roda-3.105.0/lib/roda/plugins/strip_path_prefix.rb +33 -0
  145. data/roda-3.105.0/lib/roda/plugins/symbol_matchers.rb +188 -0
  146. data/roda-3.105.0/lib/roda/plugins/symbol_status.rb +32 -0
  147. data/roda-3.105.0/lib/roda/plugins/symbol_views.rb +37 -0
  148. data/roda-3.105.0/lib/roda/plugins/timestamp_public.rb +78 -0
  149. data/roda-3.105.0/lib/roda/plugins/type_routing.rb +215 -0
  150. data/roda-3.105.0/lib/roda/plugins/typecast_params.rb +1183 -0
  151. data/roda-3.105.0/lib/roda/plugins/typecast_params_sized_integers.rb +108 -0
  152. data/roda-3.105.0/lib/roda/plugins/unescape_path.rb +41 -0
  153. data/roda-3.105.0/lib/roda/plugins/view_options.rb +201 -0
  154. data/roda-3.105.0/lib/roda/plugins/view_subdir_leading_slash.rb +49 -0
  155. data/roda-3.105.0/lib/roda/plugins.rb +68 -0
  156. data/roda-3.105.0/lib/roda/request.rb +722 -0
  157. data/roda-3.105.0/lib/roda/response.rb +221 -0
  158. data/roda-3.105.0/lib/roda/session_middleware.rb +183 -0
  159. data/roda-3.105.0/lib/roda/version.rb +18 -0
  160. data/roda-3.105.0/lib/roda.rb +586 -0
  161. data/ultra-lite-hub.gemspec +12 -0
  162. 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