ultra-max-sys 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.
Potentially problematic release.
This version of ultra-max-sys might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/roda-3.106.0/MIT-LICENSE +21 -0
- data/roda-3.106.0/lib/roda/cache.rb +42 -0
- data/roda-3.106.0/lib/roda/plugins/Integer_matcher_max.rb +55 -0
- data/roda-3.106.0/lib/roda/plugins/_after_hook.rb +11 -0
- data/roda-3.106.0/lib/roda/plugins/_base64.rb +34 -0
- data/roda-3.106.0/lib/roda/plugins/_before_hook.rb +41 -0
- data/roda-3.106.0/lib/roda/plugins/_optimized_matching.rb +227 -0
- data/roda-3.106.0/lib/roda/plugins/_symbol_class_matchers.rb +108 -0
- data/roda-3.106.0/lib/roda/plugins/_symbol_regexp_matchers.rb +24 -0
- data/roda-3.106.0/lib/roda/plugins/additional_render_engines.rb +61 -0
- data/roda-3.106.0/lib/roda/plugins/additional_view_directories.rb +66 -0
- data/roda-3.106.0/lib/roda/plugins/all_verbs.rb +50 -0
- data/roda-3.106.0/lib/roda/plugins/assets.rb +902 -0
- data/roda-3.106.0/lib/roda/plugins/assets_preloading.rb +89 -0
- data/roda-3.106.0/lib/roda/plugins/assume_ssl.rb +28 -0
- data/roda-3.106.0/lib/roda/plugins/autoload_hash_branches.rb +79 -0
- data/roda-3.106.0/lib/roda/plugins/autoload_named_routes.rb +65 -0
- data/roda-3.106.0/lib/roda/plugins/backtracking_array.rb +88 -0
- data/roda-3.106.0/lib/roda/plugins/bearer_token.rb +28 -0
- data/roda-3.106.0/lib/roda/plugins/branch_locals.rb +76 -0
- data/roda-3.106.0/lib/roda/plugins/break.rb +43 -0
- data/roda-3.106.0/lib/roda/plugins/caching.rb +206 -0
- data/roda-3.106.0/lib/roda/plugins/capture_erb.rb +94 -0
- data/roda-3.106.0/lib/roda/plugins/chunked.rb +333 -0
- data/roda-3.106.0/lib/roda/plugins/class_level_routing.rb +111 -0
- data/roda-3.106.0/lib/roda/plugins/class_matchers.rb +155 -0
- data/roda-3.106.0/lib/roda/plugins/common_logger.rb +82 -0
- data/roda-3.106.0/lib/roda/plugins/conditional_sessions.rb +67 -0
- data/roda-3.106.0/lib/roda/plugins/content_for.rb +105 -0
- data/roda-3.106.0/lib/roda/plugins/content_security_policy.rb +333 -0
- data/roda-3.106.0/lib/roda/plugins/cookie_flags.rb +157 -0
- data/roda-3.106.0/lib/roda/plugins/cookies.rb +51 -0
- data/roda-3.106.0/lib/roda/plugins/csrf.rb +81 -0
- data/roda-3.106.0/lib/roda/plugins/custom_block_results.rb +85 -0
- data/roda-3.106.0/lib/roda/plugins/custom_matchers.rb +89 -0
- data/roda-3.106.0/lib/roda/plugins/default_headers.rb +64 -0
- data/roda-3.106.0/lib/roda/plugins/default_status.rb +35 -0
- data/roda-3.106.0/lib/roda/plugins/delay_build.rb +18 -0
- data/roda-3.106.0/lib/roda/plugins/delegate.rb +77 -0
- data/roda-3.106.0/lib/roda/plugins/delete_empty_headers.rb +36 -0
- data/roda-3.106.0/lib/roda/plugins/direct_call.rb +38 -0
- data/roda-3.106.0/lib/roda/plugins/disallow_file_uploads.rb +38 -0
- data/roda-3.106.0/lib/roda/plugins/drop_body.rb +43 -0
- data/roda-3.106.0/lib/roda/plugins/each_part.rb +87 -0
- data/roda-3.106.0/lib/roda/plugins/early_hints.rb +25 -0
- data/roda-3.106.0/lib/roda/plugins/empty_root.rb +49 -0
- data/roda-3.106.0/lib/roda/plugins/environments.rb +79 -0
- data/roda-3.106.0/lib/roda/plugins/erb_h.rb +43 -0
- data/roda-3.106.0/lib/roda/plugins/error_email.rb +152 -0
- data/roda-3.106.0/lib/roda/plugins/error_handler.rb +133 -0
- data/roda-3.106.0/lib/roda/plugins/error_mail.rb +149 -0
- data/roda-3.106.0/lib/roda/plugins/exception_page.rb +445 -0
- data/roda-3.106.0/lib/roda/plugins/filter_common_logger.rb +46 -0
- data/roda-3.106.0/lib/roda/plugins/flash.rb +119 -0
- data/roda-3.106.0/lib/roda/plugins/h.rb +59 -0
- data/roda-3.106.0/lib/roda/plugins/halt.rb +108 -0
- data/roda-3.106.0/lib/roda/plugins/hash_branch_view_subdir.rb +76 -0
- data/roda-3.106.0/lib/roda/plugins/hash_branches.rb +145 -0
- data/roda-3.106.0/lib/roda/plugins/hash_matcher.rb +39 -0
- data/roda-3.106.0/lib/roda/plugins/hash_paths.rb +128 -0
- data/roda-3.106.0/lib/roda/plugins/hash_public.rb +125 -0
- data/roda-3.106.0/lib/roda/plugins/hash_public_cache.rb +91 -0
- data/roda-3.106.0/lib/roda/plugins/hash_routes.rb +304 -0
- data/roda-3.106.0/lib/roda/plugins/head.rb +99 -0
- data/roda-3.106.0/lib/roda/plugins/header_matchers.rb +88 -0
- data/roda-3.106.0/lib/roda/plugins/heartbeat.rb +41 -0
- data/roda-3.106.0/lib/roda/plugins/hmac_paths.rb +413 -0
- data/roda-3.106.0/lib/roda/plugins/hooks.rb +92 -0
- data/roda-3.106.0/lib/roda/plugins/host_authorization.rb +155 -0
- data/roda-3.106.0/lib/roda/plugins/host_routing.rb +194 -0
- data/roda-3.106.0/lib/roda/plugins/hsts.rb +35 -0
- data/roda-3.106.0/lib/roda/plugins/indifferent_params.rb +126 -0
- data/roda-3.106.0/lib/roda/plugins/inject_erb.rb +33 -0
- data/roda-3.106.0/lib/roda/plugins/invalid_request_body.rb +107 -0
- data/roda-3.106.0/lib/roda/plugins/ip_from_header.rb +34 -0
- data/roda-3.106.0/lib/roda/plugins/json.rb +119 -0
- data/roda-3.106.0/lib/roda/plugins/json_parser.rb +107 -0
- data/roda-3.106.0/lib/roda/plugins/link_to.rb +83 -0
- data/roda-3.106.0/lib/roda/plugins/mail_processor.rb +629 -0
- data/roda-3.106.0/lib/roda/plugins/mailer.rb +285 -0
- data/roda-3.106.0/lib/roda/plugins/map_matcher.rb +48 -0
- data/roda-3.106.0/lib/roda/plugins/match_affix.rb +64 -0
- data/roda-3.106.0/lib/roda/plugins/match_hook.rb +34 -0
- data/roda-3.106.0/lib/roda/plugins/match_hook_args.rb +93 -0
- data/roda-3.106.0/lib/roda/plugins/middleware.rb +225 -0
- data/roda-3.106.0/lib/roda/plugins/middleware_stack.rb +101 -0
- data/roda-3.106.0/lib/roda/plugins/module_include.rb +96 -0
- data/roda-3.106.0/lib/roda/plugins/multi_public.rb +95 -0
- data/roda-3.106.0/lib/roda/plugins/multi_route.rb +156 -0
- data/roda-3.106.0/lib/roda/plugins/multi_run.rb +144 -0
- data/roda-3.106.0/lib/roda/plugins/multi_view.rb +83 -0
- data/roda-3.106.0/lib/roda/plugins/multibyte_string_matcher.rb +57 -0
- data/roda-3.106.0/lib/roda/plugins/named_routes.rb +167 -0
- data/roda-3.106.0/lib/roda/plugins/named_templates.rb +102 -0
- data/roda-3.106.0/lib/roda/plugins/not_allowed.rb +151 -0
- data/roda-3.106.0/lib/roda/plugins/not_found.rb +55 -0
- data/roda-3.106.0/lib/roda/plugins/optimized_segment_matchers.rb +53 -0
- data/roda-3.106.0/lib/roda/plugins/optimized_string_matchers.rb +50 -0
- data/roda-3.106.0/lib/roda/plugins/padrino_render.rb +42 -0
- data/roda-3.106.0/lib/roda/plugins/param_matchers.rb +83 -0
- data/roda-3.106.0/lib/roda/plugins/params_capturing.rb +118 -0
- data/roda-3.106.0/lib/roda/plugins/part.rb +76 -0
- data/roda-3.106.0/lib/roda/plugins/partials.rb +74 -0
- data/roda-3.106.0/lib/roda/plugins/pass.rb +47 -0
- data/roda-3.106.0/lib/roda/plugins/path.rb +255 -0
- data/roda-3.106.0/lib/roda/plugins/path_matchers.rb +54 -0
- data/roda-3.106.0/lib/roda/plugins/path_rewriter.rb +111 -0
- data/roda-3.106.0/lib/roda/plugins/permissions_policy.rb +340 -0
- data/roda-3.106.0/lib/roda/plugins/placeholder_string_matchers.rb +48 -0
- data/roda-3.106.0/lib/roda/plugins/plain_hash_response_headers.rb +32 -0
- data/roda-3.106.0/lib/roda/plugins/precompile_templates.rb +156 -0
- data/roda-3.106.0/lib/roda/plugins/public.rb +182 -0
- data/roda-3.106.0/lib/roda/plugins/r.rb +35 -0
- data/roda-3.106.0/lib/roda/plugins/recheck_precompiled_assets.rb +107 -0
- data/roda-3.106.0/lib/roda/plugins/redirect_http_to_https.rb +99 -0
- data/roda-3.106.0/lib/roda/plugins/redirect_path.rb +59 -0
- data/roda-3.106.0/lib/roda/plugins/relative_path.rb +76 -0
- data/roda-3.106.0/lib/roda/plugins/render.rb +998 -0
- data/roda-3.106.0/lib/roda/plugins/render_coverage.rb +105 -0
- data/roda-3.106.0/lib/roda/plugins/render_each.rb +224 -0
- data/roda-3.106.0/lib/roda/plugins/render_locals.rb +102 -0
- data/roda-3.106.0/lib/roda/plugins/request_aref.rb +77 -0
- data/roda-3.106.0/lib/roda/plugins/request_headers.rb +83 -0
- data/roda-3.106.0/lib/roda/plugins/response_attachment.rb +94 -0
- data/roda-3.106.0/lib/roda/plugins/response_content_type.rb +79 -0
- data/roda-3.106.0/lib/roda/plugins/response_request.rb +36 -0
- data/roda-3.106.0/lib/roda/plugins/route_block_args.rb +50 -0
- data/roda-3.106.0/lib/roda/plugins/route_csrf.rb +388 -0
- data/roda-3.106.0/lib/roda/plugins/run_append_slash.rb +51 -0
- data/roda-3.106.0/lib/roda/plugins/run_handler.rb +51 -0
- data/roda-3.106.0/lib/roda/plugins/run_require_slash.rb +46 -0
- data/roda-3.106.0/lib/roda/plugins/sec_fetch_site_csrf.rb +131 -0
- data/roda-3.106.0/lib/roda/plugins/send_file.rb +127 -0
- data/roda-3.106.0/lib/roda/plugins/sessions.rb +537 -0
- data/roda-3.106.0/lib/roda/plugins/shape_friendly.rb +232 -0
- data/roda-3.106.0/lib/roda/plugins/shared_vars.rb +86 -0
- data/roda-3.106.0/lib/roda/plugins/sinatra_helpers.rb +444 -0
- data/roda-3.106.0/lib/roda/plugins/slash_path_empty.rb +26 -0
- data/roda-3.106.0/lib/roda/plugins/static.rb +42 -0
- data/roda-3.106.0/lib/roda/plugins/static_routing.rb +89 -0
- data/roda-3.106.0/lib/roda/plugins/status_303.rb +34 -0
- data/roda-3.106.0/lib/roda/plugins/status_handler.rb +86 -0
- data/roda-3.106.0/lib/roda/plugins/streaming.rb +170 -0
- data/roda-3.106.0/lib/roda/plugins/strip_path_prefix.rb +33 -0
- data/roda-3.106.0/lib/roda/plugins/symbol_matchers.rb +188 -0
- data/roda-3.106.0/lib/roda/plugins/symbol_status.rb +32 -0
- data/roda-3.106.0/lib/roda/plugins/symbol_views.rb +37 -0
- data/roda-3.106.0/lib/roda/plugins/timestamp_public.rb +78 -0
- data/roda-3.106.0/lib/roda/plugins/type_routing.rb +217 -0
- data/roda-3.106.0/lib/roda/plugins/typecast_params.rb +1185 -0
- data/roda-3.106.0/lib/roda/plugins/typecast_params_sized_integers.rb +108 -0
- data/roda-3.106.0/lib/roda/plugins/unescape_path.rb +41 -0
- data/roda-3.106.0/lib/roda/plugins/view_options.rb +203 -0
- data/roda-3.106.0/lib/roda/plugins/view_subdir_leading_slash.rb +49 -0
- data/roda-3.106.0/lib/roda/plugins.rb +68 -0
- data/roda-3.106.0/lib/roda/request.rb +722 -0
- data/roda-3.106.0/lib/roda/response.rb +221 -0
- data/roda-3.106.0/lib/roda/session_middleware.rb +184 -0
- data/roda-3.106.0/lib/roda/version.rb +18 -0
- data/roda-3.106.0/lib/roda.rb +741 -0
- data/ultra-max-sys.gemspec +12 -0
- metadata +202 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The host_routing plugin adds support for more routing requests based on
|
|
7
|
+
# the requested host. It also adds predicate methods for checking
|
|
8
|
+
# whether a request was requested with the given host.
|
|
9
|
+
#
|
|
10
|
+
# When loading the plugin, you pass a block, which is used for configuring
|
|
11
|
+
# the plugin. For example, if you want to treat requests to api.example.com
|
|
12
|
+
# or api2.example.com as api requests, and treat other requests as www
|
|
13
|
+
# requests, you could use:
|
|
14
|
+
#
|
|
15
|
+
# plugin :host_routing do |hosts|
|
|
16
|
+
# hosts.to :api, "api.example.com", "api2.example.com"
|
|
17
|
+
# hosts.default :www
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# With this configuration, in your routing tree, you can call the +r.api+ and
|
|
21
|
+
# +r.www+ methods for dispatching to routing blocks only for those types of
|
|
22
|
+
# requests:
|
|
23
|
+
#
|
|
24
|
+
# route do |r|
|
|
25
|
+
# r.api do
|
|
26
|
+
# # requests to api.example.com or api2.example.com
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# r.www do
|
|
30
|
+
# # requests to other domains
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# In addition to the routing methods, predicate methods are also added to the
|
|
35
|
+
# request object:
|
|
36
|
+
#
|
|
37
|
+
# route do |r|
|
|
38
|
+
# "#{r.api?}-#{r.www?}"
|
|
39
|
+
# end
|
|
40
|
+
# # Requests to api.example.com or api2.example.com return "true-false"
|
|
41
|
+
# # Other requests return "false-true"
|
|
42
|
+
#
|
|
43
|
+
# If the +:scope_predicates+ plugin option is given, predicate methods are also
|
|
44
|
+
# created in route block scope:
|
|
45
|
+
#
|
|
46
|
+
# plugin :host_routing, scope_predicates: true do |hosts|
|
|
47
|
+
# hosts.to :api, "api.example.com"
|
|
48
|
+
# hosts.default :www
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# route do |r|
|
|
52
|
+
# "#{api?}-#{www?}"
|
|
53
|
+
# end
|
|
54
|
+
#
|
|
55
|
+
# To handle hosts that match a certain format (such as all subdomains),
|
|
56
|
+
# where the specific host names are not known up front, you can provide a block
|
|
57
|
+
# when calling +hosts.default+. This block is passed the host name, or an empty
|
|
58
|
+
# string if no host name is provided, and is evaluated in route block scope.
|
|
59
|
+
# When using this support, you should also call +hosts.register+
|
|
60
|
+
# to register host types that could be returned by the block. For example, to
|
|
61
|
+
# handle api subdomains differently:
|
|
62
|
+
#
|
|
63
|
+
# plugin :host_routing do |hosts|
|
|
64
|
+
# hosts.to :api, "api.example.com"
|
|
65
|
+
# hosts.register :api_sub
|
|
66
|
+
# hosts.default :www do |host|
|
|
67
|
+
# :api_sub if host.end_with?(".api.example.com")
|
|
68
|
+
# end
|
|
69
|
+
# end
|
|
70
|
+
#
|
|
71
|
+
# This plugin uses the host method on the request to get the hostname (this method
|
|
72
|
+
# is defined by Rack).
|
|
73
|
+
module HostRouting
|
|
74
|
+
REQUEST_INSTANCE_VARIABLES = [:@_host_routing_host].freeze
|
|
75
|
+
|
|
76
|
+
# Setup the host routing support. The block yields an object used to
|
|
77
|
+
# configure the plugin. Options:
|
|
78
|
+
#
|
|
79
|
+
# :scope_predicates :: Setup predicate methods in route block scope
|
|
80
|
+
# in addition to request scope.
|
|
81
|
+
def self.configure(app, opts=OPTS, &block)
|
|
82
|
+
hosts, host_hash, default_block, default_host = DSL.new.process(&block)
|
|
83
|
+
app.opts[:host_routing_hash] = host_hash
|
|
84
|
+
app.opts[:host_routing_default_host] = default_host
|
|
85
|
+
|
|
86
|
+
app.send(:define_method, :_host_routing_default, &default_block) if default_block
|
|
87
|
+
|
|
88
|
+
app::RodaRequest.class_exec do
|
|
89
|
+
hosts.each do |host|
|
|
90
|
+
host_sym = host.to_sym
|
|
91
|
+
define_method(host_sym){|&blk| always(&blk) if _host_routing_host == host}
|
|
92
|
+
alias_method host_sym, host_sym
|
|
93
|
+
|
|
94
|
+
meth = :"#{host}?"
|
|
95
|
+
define_method(meth){_host_routing_host == host}
|
|
96
|
+
alias_method meth, meth
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
if opts[:scope_predicates]
|
|
101
|
+
app.class_exec do
|
|
102
|
+
hosts.each do |host|
|
|
103
|
+
meth = :"#{host}?"
|
|
104
|
+
define_method(meth){@_request.send(meth)}
|
|
105
|
+
alias_method meth, meth
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
class DSL
|
|
112
|
+
def initialize
|
|
113
|
+
@hosts = []
|
|
114
|
+
@host_hash = {}
|
|
115
|
+
@default_host = nil
|
|
116
|
+
@default_block = nil
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Run the DSL for the given block.
|
|
120
|
+
def process(&block)
|
|
121
|
+
instance_exec(self, &block)
|
|
122
|
+
|
|
123
|
+
if !@default_host
|
|
124
|
+
raise RodaError, "must call default method inside host_routing plugin block to set default host"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
@hosts.concat(@host_hash.values)
|
|
128
|
+
@hosts << @default_host
|
|
129
|
+
@hosts.uniq!
|
|
130
|
+
[@hosts.freeze, @host_hash.freeze, @default_block, @default_host].freeze
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Register hosts that can be returned. This is only needed if
|
|
134
|
+
# calling register with a block, where the block can return
|
|
135
|
+
# a value that doesn't match a host given to +to+ or +default+.
|
|
136
|
+
def register(*hosts)
|
|
137
|
+
@hosts = hosts
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Treat all given hostnames as routing to the give host.
|
|
141
|
+
def to(host, *hostnames)
|
|
142
|
+
hostnames.each do |hostname|
|
|
143
|
+
@host_hash[hostname] = host
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Register the default hostname. If a block is provided, it is
|
|
148
|
+
# called with the host if there is no match for one of the hostnames
|
|
149
|
+
# provided to +to+. If the block returns nil/false, the hostname
|
|
150
|
+
# given to this method is used.
|
|
151
|
+
def default(hostname, &block)
|
|
152
|
+
@default_host = hostname
|
|
153
|
+
@default_block = block
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
private_constant :DSL
|
|
157
|
+
|
|
158
|
+
module InstanceMethods
|
|
159
|
+
# Handle case where plugin is used without providing a block to
|
|
160
|
+
# +hosts.default+. This returns nil, ensuring that the hostname
|
|
161
|
+
# provided to +hosts.default+ will be used.
|
|
162
|
+
def _host_routing_default(_)
|
|
163
|
+
nil
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
module RequestMethods
|
|
168
|
+
private
|
|
169
|
+
|
|
170
|
+
# Cache the host to use in the host routing support, so the processing
|
|
171
|
+
# is only done once per request.
|
|
172
|
+
def _host_routing_host
|
|
173
|
+
@_host_routing_host ||= _get_host_routing_host
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Determine the host to use for the host routing support. Tries the
|
|
177
|
+
# following, in order:
|
|
178
|
+
#
|
|
179
|
+
# * An exact match for a hostname given in +hosts.to+
|
|
180
|
+
# * The return value of the +hosts.default+ block, if given
|
|
181
|
+
# * The default value provided in the +hosts.default+ call
|
|
182
|
+
def _get_host_routing_host
|
|
183
|
+
host = self.host || ""
|
|
184
|
+
|
|
185
|
+
roda_class.opts[:host_routing_hash][host] ||
|
|
186
|
+
scope._host_routing_default(host) ||
|
|
187
|
+
roda_class.opts[:host_routing_default_host]
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
register_plugin(:host_routing, HostRouting)
|
|
193
|
+
end
|
|
194
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The hsts plugin allows for easily configuring an appropriate
|
|
7
|
+
# Strict-Transport-Security response header for the application:
|
|
8
|
+
#
|
|
9
|
+
# plugin :hsts
|
|
10
|
+
# # Strict-Transport-Security: max-age=63072000; includeSubDomains
|
|
11
|
+
#
|
|
12
|
+
# plugin :hsts, preload: true
|
|
13
|
+
# # Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
|
|
14
|
+
#
|
|
15
|
+
# plugin :hsts, max_age: 31536000, subdomains: false
|
|
16
|
+
# # Strict-Transport-Security: max-age=31536000
|
|
17
|
+
module Hsts
|
|
18
|
+
# Ensure default_headers plugin is loaded first
|
|
19
|
+
def self.load_dependencies(app, opts=OPTS)
|
|
20
|
+
app.plugin :default_headers
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Configure the Strict-Transport-Security header. Options:
|
|
24
|
+
# :max_age :: Set max-age in seconds (default is 63072000, two years)
|
|
25
|
+
# :preload :: Set preload, so the domain can be included in HSTS preload lists
|
|
26
|
+
# :subdomains :: Set to false to not set includeSubDomains. By default,
|
|
27
|
+
# includeSubDomains is set to enforce HTTPS for subdomains.
|
|
28
|
+
def self.configure(app, opts=OPTS)
|
|
29
|
+
app.plugin :default_headers, RodaResponseHeaders::STRICT_TRANSPORT_SECURITY => "max-age=#{opts[:max_age]||63072000}#{'; includeSubDomains' unless opts[:subdomains] == false}#{'; preload' if opts[:preload]}".freeze
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
register_plugin(:hsts, Hsts)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The indifferent_params plugin adds a +params+ instance
|
|
7
|
+
# method which offers indifferent access to the request
|
|
8
|
+
# params, allowing you to use symbols to lookup values in
|
|
9
|
+
# a hash where the keys are strings. Note that while this
|
|
10
|
+
# allows for an easier transition from some other ruby frameworks,
|
|
11
|
+
# it is a bad idea in general as it makes it more difficult to
|
|
12
|
+
# separate external data from internal data, and doesn't handle
|
|
13
|
+
# any typecasting of the data. Consider using the typecast_params
|
|
14
|
+
# plugin instead of this plugin for accessing parameters.
|
|
15
|
+
#
|
|
16
|
+
# Example:
|
|
17
|
+
#
|
|
18
|
+
# plugin :indifferent_params
|
|
19
|
+
#
|
|
20
|
+
# route do |r|
|
|
21
|
+
# params[:foo]
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# The exact behavior depends on the version of Rack in use.
|
|
25
|
+
# If you are using Rack 2, this plugin uses rack's API
|
|
26
|
+
# to set the query parser for the request to use indifferent
|
|
27
|
+
# access. Rack 1 doesn't support indifferent access to
|
|
28
|
+
# params, so if you are using Rack 1, this plugin will make
|
|
29
|
+
# a deep copy of the request params hash, where each level
|
|
30
|
+
# uses indifferent access. On Rack 1, The params hash is
|
|
31
|
+
# initialized lazily, so you only pay the penalty of
|
|
32
|
+
# copying the request params if you call the +params+ method.
|
|
33
|
+
#
|
|
34
|
+
# Note that there is a rack-indifferent gem that
|
|
35
|
+
# monkey patches rack to always use indifferent params. If
|
|
36
|
+
# you are using Rack 1, it is recommended to use
|
|
37
|
+
# rack-indifferent instead of this plugin, as it is faster
|
|
38
|
+
# and has some other minor advantages, though
|
|
39
|
+
# it affects all rack applications instead of just the Roda app that
|
|
40
|
+
# you load the plugin into.
|
|
41
|
+
module IndifferentParams
|
|
42
|
+
SCOPE_INSTANCE_VARIABLES = [:@_params].freeze
|
|
43
|
+
|
|
44
|
+
INDIFFERENT_PROC = lambda{|h,k| h[k.to_s] if k.is_a?(Symbol)}
|
|
45
|
+
|
|
46
|
+
if Rack.release > '2'
|
|
47
|
+
require 'rack/query_parser'
|
|
48
|
+
|
|
49
|
+
class QueryParser < Rack::QueryParser
|
|
50
|
+
# Work around for invalid optimization in rack
|
|
51
|
+
def parse_nested_query(qs, d=nil)
|
|
52
|
+
return make_params.to_params_hash if qs.nil? || qs.empty?
|
|
53
|
+
super
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class Params < Rack::QueryParser::Params
|
|
57
|
+
if Rack.release >= '3'
|
|
58
|
+
if Params < Hash
|
|
59
|
+
def initialize
|
|
60
|
+
super(&INDIFFERENT_PROC)
|
|
61
|
+
end
|
|
62
|
+
else
|
|
63
|
+
def initialize
|
|
64
|
+
@size = 0
|
|
65
|
+
@params = Hash.new(&INDIFFERENT_PROC)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
else
|
|
69
|
+
def initialize(limit = Rack::Utils.key_space_limit)
|
|
70
|
+
@limit = limit
|
|
71
|
+
@size = 0
|
|
72
|
+
@params = Hash.new(&INDIFFERENT_PROC)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
module RequestMethods
|
|
80
|
+
query_parser = Rack.release >= '3' ? QueryParser.new(QueryParser::Params, 32) : QueryParser.new(QueryParser::Params, 65536, 32)
|
|
81
|
+
QUERY_PARSER = Rack::Utils.default_query_parser = query_parser
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def query_parser
|
|
86
|
+
QUERY_PARSER
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
module InstanceMethods
|
|
91
|
+
def params
|
|
92
|
+
@_request.params
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
module InstanceMethods
|
|
97
|
+
# A copy of the request params that will automatically
|
|
98
|
+
# convert symbols to strings.
|
|
99
|
+
def params
|
|
100
|
+
@_params ||= indifferent_params(@_request.params)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
private
|
|
104
|
+
|
|
105
|
+
# Recursively process the request params and convert
|
|
106
|
+
# hashes to support indifferent access, leaving
|
|
107
|
+
# other values alone.
|
|
108
|
+
def indifferent_params(params)
|
|
109
|
+
case params
|
|
110
|
+
when Hash
|
|
111
|
+
hash = Hash.new(&INDIFFERENT_PROC)
|
|
112
|
+
params.each{|k, v| hash[k] = indifferent_params(v)}
|
|
113
|
+
hash
|
|
114
|
+
when Array
|
|
115
|
+
params.map{|x| indifferent_params(x)}
|
|
116
|
+
else
|
|
117
|
+
params
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
register_plugin(:indifferent_params, IndifferentParams)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The inject_erb plugin allows you to inject content directly
|
|
7
|
+
# into the template output:
|
|
8
|
+
#
|
|
9
|
+
# <% inject_erb("Some HTML Here") %>
|
|
10
|
+
#
|
|
11
|
+
# This will inject <tt>Some HTML Here</tt> into the template output,
|
|
12
|
+
# even though the tag being used is <tt><%</tt> and not <tt><%=</tt>.
|
|
13
|
+
#
|
|
14
|
+
# This method can be used inside methods, such as to wrap calls to
|
|
15
|
+
# methods that accept template blocks, to inject code before and after
|
|
16
|
+
# the template blocks.
|
|
17
|
+
module InjectERB
|
|
18
|
+
def self.load_dependencies(app)
|
|
19
|
+
app.plugin :render
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module InstanceMethods
|
|
23
|
+
# Inject into the template output for the template currently being
|
|
24
|
+
# rendered.
|
|
25
|
+
def inject_erb(value)
|
|
26
|
+
instance_variable_get(render_opts[:template_opts][:outvar]) << value.to_s
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
register_plugin(:inject_erb, InjectERB)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The invalid_request_body plugin allows for custom handling of invalid request
|
|
7
|
+
# bodies. Roda uses Rack for parsing request bodies, so by default, any
|
|
8
|
+
# invalid request bodies would result in Rack raising an exception, and the
|
|
9
|
+
# exception could change for different reasons the request body is invalid.
|
|
10
|
+
# This plugin overrides RodaRequest#POST (which parses parameters from request
|
|
11
|
+
# bodies), and if parsing raises an exception, it allows for custom behavior.
|
|
12
|
+
#
|
|
13
|
+
# If you want to treat an invalid request body as the submission of no parameters,
|
|
14
|
+
# you can use the :empty_hash argument when loading the plugin:
|
|
15
|
+
#
|
|
16
|
+
# plugin :invalid_request_body, :empty_hash
|
|
17
|
+
#
|
|
18
|
+
# If you want to return a empty 400 (Bad Request) response if an invalid request
|
|
19
|
+
# body is submitted, you can use the :empty_400 argument when loading the plugin:
|
|
20
|
+
#
|
|
21
|
+
# plugin :invalid_request_body, :empty_400
|
|
22
|
+
#
|
|
23
|
+
# If you want to raise a Roda::RodaPlugins::InvalidRequestBody::Error exception
|
|
24
|
+
# if an invalid request body is submitted (which makes it easier to handle these
|
|
25
|
+
# exceptions when using the error_handler plugin), you can use the :raise argument
|
|
26
|
+
# when loading the plugin:
|
|
27
|
+
#
|
|
28
|
+
# plugin :invalid_request_body, :raise
|
|
29
|
+
#
|
|
30
|
+
# For custom behavior, you can pass a block when loading the plugin. The block
|
|
31
|
+
# is called with the exception Rack raised when parsing the body. The block will
|
|
32
|
+
# be used to define a method in the application's RodaRequest class. It can either
|
|
33
|
+
# return a hash of parameters, or you can raise a different exception, or you
|
|
34
|
+
# can halt processing and return a response:
|
|
35
|
+
#
|
|
36
|
+
# plugin :invalid_request_body do |exception|
|
|
37
|
+
# # To treat the exception raised as a submitted parameter
|
|
38
|
+
# {body_error: exception}
|
|
39
|
+
# end
|
|
40
|
+
module InvalidRequestBody
|
|
41
|
+
# Exception class raised for invalid request bodies.
|
|
42
|
+
Error = Class.new(RodaError)
|
|
43
|
+
|
|
44
|
+
# Set the action to use (:empty_400, :empty_hash, :raise) for invalid request bodies,
|
|
45
|
+
# or use a block for custom behavior.
|
|
46
|
+
def self.configure(app, action=nil, &block)
|
|
47
|
+
if action
|
|
48
|
+
if block
|
|
49
|
+
raise RodaError, "cannot provide both block and action when loading invalid_request_body plugin"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
method = :"handle_invalid_request_body_#{action}"
|
|
53
|
+
unless RequestMethods.private_method_defined?(method)
|
|
54
|
+
raise RodaError, "invalid invalid_request_body action provided: #{action}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
app::RodaRequest.send(:alias_method, :handle_invalid_request_body, method)
|
|
58
|
+
elsif block
|
|
59
|
+
app::RodaRequest.class_eval do
|
|
60
|
+
define_method(:handle_invalid_request_body, &block)
|
|
61
|
+
alias handle_invalid_request_body handle_invalid_request_body
|
|
62
|
+
end
|
|
63
|
+
else
|
|
64
|
+
raise RodaError, "must provide block or action when loading invalid_request_body plugin"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
app::RodaRequest.send(:private, :handle_invalid_request_body)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
module RequestMethods
|
|
71
|
+
# Handle invalid request bodies as configured if the default behavior
|
|
72
|
+
# raises an exception.
|
|
73
|
+
def POST
|
|
74
|
+
super
|
|
75
|
+
rescue => e
|
|
76
|
+
handle_invalid_request_body(e)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
# Return an empty 400 HTTP response for invalid request bodies.
|
|
82
|
+
def handle_invalid_request_body_empty_400(e)
|
|
83
|
+
response.status = 400
|
|
84
|
+
headers = response.headers
|
|
85
|
+
headers.clear
|
|
86
|
+
headers[RodaResponseHeaders::CONTENT_TYPE] = 'text/html'
|
|
87
|
+
headers[RodaResponseHeaders::CONTENT_LENGTH] ='0'
|
|
88
|
+
throw :halt, response.finish_with_body([])
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Treat invalid request bodies by using an empty hash as the
|
|
92
|
+
# POST params.
|
|
93
|
+
def handle_invalid_request_body_empty_hash(e)
|
|
94
|
+
{}
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Raise a specific error for all invalid request bodies,
|
|
98
|
+
# to allow for easy rescuing using the error_handler plugin.
|
|
99
|
+
def handle_invalid_request_body_raise(e)
|
|
100
|
+
raise Error, e.message
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
register_plugin(:invalid_request_body, InvalidRequestBody)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The ip_from_header plugin allows for overriding +request.ip+ to return
|
|
7
|
+
# the value contained in a specific header. This is useful when the
|
|
8
|
+
# application is behind a proxy that sets a specific header, especially
|
|
9
|
+
# when the proxy does not use a fixed IP address range. Example showing
|
|
10
|
+
# usage with Cloudflare:
|
|
11
|
+
#
|
|
12
|
+
# plugin :ip_from_header, "CF-Connecting-IP"
|
|
13
|
+
#
|
|
14
|
+
# This plugin assumes that if the header is set, it contains a valid IP
|
|
15
|
+
# address, it does not check the format of the header value, just as
|
|
16
|
+
# <tt>Rack::Request#ip</tt> does not check the IP address it returns is
|
|
17
|
+
# actually valid.
|
|
18
|
+
module IPFromHeader
|
|
19
|
+
def self.configure(app, header)
|
|
20
|
+
app.opts[:ip_from_header_env_key] = "HTTP_#{header.upcase.tr('-', '_')}".freeze
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module RequestMethods
|
|
24
|
+
# Return the IP address continained in the configured header, if present.
|
|
25
|
+
# Fallback to the default behavior if not present.
|
|
26
|
+
def ip
|
|
27
|
+
@env[roda_class.opts[:ip_from_header_env_key]] || super
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
register_plugin(:ip_from_header, IPFromHeader)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
class Roda
|
|
6
|
+
module RodaPlugins
|
|
7
|
+
# The json plugin allows match blocks to return
|
|
8
|
+
# arrays or hashes, and have those arrays or hashes be
|
|
9
|
+
# converted to json which is used as the response body.
|
|
10
|
+
# It also sets the response content type to application/json.
|
|
11
|
+
# So you can take code like:
|
|
12
|
+
#
|
|
13
|
+
# r.root do
|
|
14
|
+
# response['Content-Type'] = 'application/json'
|
|
15
|
+
# [1, 2, 3].to_json
|
|
16
|
+
# end
|
|
17
|
+
# r.is "foo" do
|
|
18
|
+
# response['Content-Type'] = 'application/json'
|
|
19
|
+
# {'a'=>'b'}.to_json
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# and DRY it up:
|
|
23
|
+
#
|
|
24
|
+
# plugin :json
|
|
25
|
+
# r.root do
|
|
26
|
+
# [1, 2, 3]
|
|
27
|
+
# end
|
|
28
|
+
# r.is "foo" do
|
|
29
|
+
# {'a'=>'b'}
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# By default, only arrays and hashes are handled, but you
|
|
33
|
+
# can specifically set the allowed classes to json by adding
|
|
34
|
+
# using the :classes option when loading the plugin:
|
|
35
|
+
#
|
|
36
|
+
# plugin :json, classes: [Array, Hash, Sequel::Model]
|
|
37
|
+
#
|
|
38
|
+
# By default objects are serialized with +to_json+, but you
|
|
39
|
+
# can pass in a custom serializer, which can be any object
|
|
40
|
+
# that responds to +call(object)+.
|
|
41
|
+
#
|
|
42
|
+
# plugin :json, serializer: proc{|o| o.to_json(root: true)}
|
|
43
|
+
#
|
|
44
|
+
# If you need the request information during serialization, such
|
|
45
|
+
# as HTTP headers or query parameters, you can pass in the
|
|
46
|
+
# +:include_request+ option, which will pass in the request
|
|
47
|
+
# object as the second argument when calling the serializer.
|
|
48
|
+
#
|
|
49
|
+
# plugin :json, include_request: true, serializer: proc{|o, request| ...}
|
|
50
|
+
#
|
|
51
|
+
# The default content-type is 'application/json', but you can change that
|
|
52
|
+
# using the +:content_type+ option:
|
|
53
|
+
#
|
|
54
|
+
# plugin :json, content_type: 'application/xml'
|
|
55
|
+
#
|
|
56
|
+
# This plugin depends on the custom_block_results plugin, and therefore does
|
|
57
|
+
# not support treating String, FalseClass, or NilClass values as JSON.
|
|
58
|
+
module Json
|
|
59
|
+
def self.load_dependencies(app, opts=OPTS)
|
|
60
|
+
app.plugin :custom_block_results
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Set the classes to automatically convert to JSON, and the serializer to use.
|
|
64
|
+
def self.configure(app, opts=OPTS)
|
|
65
|
+
classes = opts[:classes] || [Array, Hash]
|
|
66
|
+
app.opts[:json_result_classes] ||= []
|
|
67
|
+
app.opts[:json_result_classes] += classes
|
|
68
|
+
classes = app.opts[:json_result_classes]
|
|
69
|
+
classes.uniq!
|
|
70
|
+
classes.freeze
|
|
71
|
+
classes.each do |klass|
|
|
72
|
+
app.opts[:custom_block_results][klass] = :handle_json_block_result
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
app.opts[:json_result_serializer] = opts[:serializer] || app.opts[:json_result_serializer] || app.opts[:json_serializer] || :to_json.to_proc
|
|
76
|
+
|
|
77
|
+
app.opts[:json_result_include_request] = opts[:include_request] if opts.has_key?(:include_request)
|
|
78
|
+
|
|
79
|
+
app.opts[:json_result_content_type] = opts[:content_type] || 'application/json'.freeze
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
module ClassMethods
|
|
83
|
+
# The classes that should be automatically converted to json
|
|
84
|
+
def json_result_classes
|
|
85
|
+
# RODA4: remove, only used by previous implementation.
|
|
86
|
+
opts[:json_result_classes]
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
module InstanceMethods
|
|
91
|
+
# Handle a result for one of the registered JSON result classes
|
|
92
|
+
# by converting the result to JSON.
|
|
93
|
+
def handle_json_block_result(result)
|
|
94
|
+
@_response[RodaResponseHeaders::CONTENT_TYPE] ||= opts[:json_result_content_type]
|
|
95
|
+
@_request.send(:convert_to_json, result)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
module RequestMethods
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
# Convert the given object to JSON. Uses to_json by default,
|
|
103
|
+
# but can use a custom serializer passed to the plugin.
|
|
104
|
+
def convert_to_json(result)
|
|
105
|
+
opts = roda_class.opts
|
|
106
|
+
serializer = opts[:json_result_serializer]
|
|
107
|
+
|
|
108
|
+
if opts[:json_result_include_request]
|
|
109
|
+
serializer.call(result, self)
|
|
110
|
+
else
|
|
111
|
+
serializer.call(result)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
register_plugin(:json, Json)
|
|
118
|
+
end
|
|
119
|
+
end
|