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,225 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The middleware plugin allows the Roda app to be used as
|
|
7
|
+
# rack middleware.
|
|
8
|
+
#
|
|
9
|
+
# In the example below, requests to /mid will return Mid
|
|
10
|
+
# by the Mid middleware, and requests to /app will not be
|
|
11
|
+
# matched by the Mid middleware, so they will be forwarded
|
|
12
|
+
# to App.
|
|
13
|
+
#
|
|
14
|
+
# class Mid < Roda
|
|
15
|
+
# plugin :middleware
|
|
16
|
+
#
|
|
17
|
+
# route do |r|
|
|
18
|
+
# r.is "mid" do
|
|
19
|
+
# "Mid"
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# class App < Roda
|
|
25
|
+
# use Mid
|
|
26
|
+
#
|
|
27
|
+
# route do |r|
|
|
28
|
+
# r.is "app" do
|
|
29
|
+
# "App"
|
|
30
|
+
# end
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# run App
|
|
35
|
+
#
|
|
36
|
+
# By default, when the app is used as middleware and handles the request at
|
|
37
|
+
# all, it does not forward the request to the next middleware. For the
|
|
38
|
+
# following setup:
|
|
39
|
+
#
|
|
40
|
+
# class Mid < Roda
|
|
41
|
+
# plugin :middleware
|
|
42
|
+
#
|
|
43
|
+
# route do |r|
|
|
44
|
+
# r.on "foo" do
|
|
45
|
+
# r.is "mid" do
|
|
46
|
+
# "Mid"
|
|
47
|
+
# end
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
# end
|
|
51
|
+
#
|
|
52
|
+
# class App < Roda
|
|
53
|
+
# use Mid
|
|
54
|
+
#
|
|
55
|
+
# route do |r|
|
|
56
|
+
# r.on "foo" do
|
|
57
|
+
# r.is "app" do
|
|
58
|
+
# "App"
|
|
59
|
+
# end
|
|
60
|
+
# end
|
|
61
|
+
# end
|
|
62
|
+
# end
|
|
63
|
+
#
|
|
64
|
+
# run App
|
|
65
|
+
#
|
|
66
|
+
# Requests for +/foo/mid will+ return +Mid+, but requests for +/foo/app+
|
|
67
|
+
# will return an empty 404 response, because the middleware handles the
|
|
68
|
+
# +/foo/app+ request in the <tt>r.on "foo" do</tt> block, but does not
|
|
69
|
+
# have the block return a result, which Roda treats as an empty 404 response.
|
|
70
|
+
# If you would like the middleware to forward +/foo/app+ request to the
|
|
71
|
+
# application, you should use the +:next_if_not_found+ plugin option.
|
|
72
|
+
#
|
|
73
|
+
# It is possible to use the Roda app as a regular app even when using
|
|
74
|
+
# the middleware plugin. Using an app as middleware automatically creates
|
|
75
|
+
# a subclass of the app for the middleware. Because a subclass is automatically
|
|
76
|
+
# created when the app is used as middleware, any configuration of the app
|
|
77
|
+
# should be done before using it as middleware instead of after.
|
|
78
|
+
#
|
|
79
|
+
# You can support configurable middleware by passing a block when loading
|
|
80
|
+
# the plugin:
|
|
81
|
+
#
|
|
82
|
+
# class Mid < Roda
|
|
83
|
+
# plugin :middleware do |middleware, *args, &block|
|
|
84
|
+
# middleware.opts[:middleware_args] = args
|
|
85
|
+
# block.call(middleware)
|
|
86
|
+
# end
|
|
87
|
+
#
|
|
88
|
+
# route do |r|
|
|
89
|
+
# r.is "mid" do
|
|
90
|
+
# opts[:middleware_args].join(' ')
|
|
91
|
+
# end
|
|
92
|
+
# end
|
|
93
|
+
# end
|
|
94
|
+
#
|
|
95
|
+
# class App < Roda
|
|
96
|
+
# use Mid, :foo, :bar do |middleware|
|
|
97
|
+
# middleware.opts[:middleware_args] << :baz
|
|
98
|
+
# end
|
|
99
|
+
# end
|
|
100
|
+
#
|
|
101
|
+
# # Request to App for /mid returns
|
|
102
|
+
# # "foo bar baz"
|
|
103
|
+
module Middleware
|
|
104
|
+
NEXT_PROC = lambda{throw :next, true}
|
|
105
|
+
private_constant :NEXT_PROC
|
|
106
|
+
|
|
107
|
+
# Configure the middleware plugin. Options:
|
|
108
|
+
# :env_var :: Set the environment variable to use to indicate to the roda
|
|
109
|
+
# application that the current request is a middleware request.
|
|
110
|
+
# You should only need to override this if you are using multiple
|
|
111
|
+
# roda middleware in the same application.
|
|
112
|
+
# :handle_result :: Callable object that will be called with request environment
|
|
113
|
+
# and rack response for all requests passing through the middleware,
|
|
114
|
+
# after either the middleware or next app handles the request
|
|
115
|
+
# and returns a response.
|
|
116
|
+
# :forward_response_headers :: Whether changes to the response headers made inside
|
|
117
|
+
# the middleware's route block should be applied to the
|
|
118
|
+
# final response when the request is forwarded to the app.
|
|
119
|
+
# Defaults to false.
|
|
120
|
+
# :next_if_not_found :: If the middleware handles the request but returns a not found
|
|
121
|
+
# result (404 with no body), forward the result to the next middleware.
|
|
122
|
+
def self.configure(app, opts={}, &block)
|
|
123
|
+
app.opts[:middleware_env_var] = opts[:env_var] if opts.has_key?(:env_var)
|
|
124
|
+
app.opts[:middleware_env_var] ||= 'roda.forward_next'
|
|
125
|
+
app.opts[:middleware_configure] = block if block
|
|
126
|
+
app.opts[:middleware_handle_result] = opts[:handle_result]
|
|
127
|
+
app.opts[:middleware_forward_response_headers] = opts[:forward_response_headers]
|
|
128
|
+
app.opts[:middleware_next_if_not_found] = opts[:next_if_not_found]
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Forwarder instances are what is actually used as middleware.
|
|
132
|
+
class Forwarder
|
|
133
|
+
# Make a subclass of +mid+ to use as the current middleware,
|
|
134
|
+
# and store +app+ as the next middleware to call.
|
|
135
|
+
def initialize(mid, app, *args, &block)
|
|
136
|
+
@mid = Class.new(mid)
|
|
137
|
+
RodaPlugins.set_temp_name(@mid){"#{mid}::middleware_subclass"}
|
|
138
|
+
if @mid.opts[:middleware_next_if_not_found]
|
|
139
|
+
@mid.plugin(:not_found, &NEXT_PROC)
|
|
140
|
+
end
|
|
141
|
+
if configure = @mid.opts[:middleware_configure]
|
|
142
|
+
configure.call(@mid, *args, &block)
|
|
143
|
+
elsif block || !args.empty?
|
|
144
|
+
raise RodaError, "cannot provide middleware args or block unless loading middleware plugin with a block"
|
|
145
|
+
end
|
|
146
|
+
@app = app
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# When calling the middleware, first call the current middleware.
|
|
150
|
+
# If this returns a result, return that result directly. Otherwise,
|
|
151
|
+
# pass handling of the request to the next middleware.
|
|
152
|
+
def call(env)
|
|
153
|
+
res = nil
|
|
154
|
+
|
|
155
|
+
call_next = catch(:next) do
|
|
156
|
+
env[@mid.opts[:middleware_env_var]] = true
|
|
157
|
+
res = @mid.call(env)
|
|
158
|
+
false
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
if call_next
|
|
162
|
+
res = @app.call(env)
|
|
163
|
+
|
|
164
|
+
if modified_headers = env.delete('roda.response_headers')
|
|
165
|
+
res[1] = modified_headers.merge(res[1])
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
if handle_result = @mid.opts[:middleware_handle_result]
|
|
170
|
+
handle_result.call(env, res)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
res
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
module ClassMethods
|
|
178
|
+
# Create a Forwarder instead of a new instance if a non-Hash is given.
|
|
179
|
+
def new(app, *args, &block)
|
|
180
|
+
if app.is_a?(Hash)
|
|
181
|
+
super
|
|
182
|
+
else
|
|
183
|
+
Forwarder.new(self, app, *args, &block)
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
module InstanceMethods
|
|
189
|
+
# Override the route block so that if no route matches, we throw so
|
|
190
|
+
# that the next middleware is called. Old Dispatch API.
|
|
191
|
+
def call(&block)
|
|
192
|
+
super do |r|
|
|
193
|
+
res = instance_exec(r, &block) # call Fallback
|
|
194
|
+
if r.forward_next
|
|
195
|
+
r.env['roda.response_headers'] = response.headers if opts[:middleware_forward_response_headers]
|
|
196
|
+
throw :next, true
|
|
197
|
+
end
|
|
198
|
+
res
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Override the route block so that if no route matches, we throw so
|
|
203
|
+
# that the next middleware is called.
|
|
204
|
+
def _roda_run_main_route(r)
|
|
205
|
+
res = super
|
|
206
|
+
if r.forward_next
|
|
207
|
+
r.env['roda.response_headers'] = response.headers if opts[:middleware_forward_response_headers]
|
|
208
|
+
throw :next, true
|
|
209
|
+
end
|
|
210
|
+
res
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
module RequestMethods
|
|
215
|
+
# Whether to forward the request to the next application. Set only if
|
|
216
|
+
# this request is being performed for middleware.
|
|
217
|
+
def forward_next
|
|
218
|
+
env[roda_class.opts[:middleware_env_var]]
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
register_plugin(:middleware, Middleware)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The middleware_stack plugin adds methods to remove middleware
|
|
7
|
+
# from the middleware stack, and insert new middleware at specific
|
|
8
|
+
# positions in the middleware stack.
|
|
9
|
+
#
|
|
10
|
+
# plugin :middleware_stack
|
|
11
|
+
#
|
|
12
|
+
# # Remove csrf middleware
|
|
13
|
+
# middleware_stack.remove{|m, *args| m == Rack::Csrf}
|
|
14
|
+
#
|
|
15
|
+
# # Insert csrf middleware
|
|
16
|
+
# middleware_stack.before{|m, *args| m == Rack::CommonLogger}.use(Rack::Csrf, raise: true)
|
|
17
|
+
# middleware_stack.after{|m, *args| m == Rack::CommonLogger}.use(Rack::Csrf, raise: true)
|
|
18
|
+
module MiddlewareStack
|
|
19
|
+
# Represents a specific position in the application's middleware stack where new
|
|
20
|
+
# middleware can be inserted.
|
|
21
|
+
class StackPosition
|
|
22
|
+
def initialize(app, middleware, position)
|
|
23
|
+
@app = app
|
|
24
|
+
@middleware = middleware
|
|
25
|
+
@position = position
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Insert a new middleware into the current position in the middleware stack.
|
|
29
|
+
# Increments the position so that calling this multiple times adds later
|
|
30
|
+
# middleware after earlier middleware, similar to how +Roda.use+ works.
|
|
31
|
+
def use(*args, &block)
|
|
32
|
+
@middleware.insert(@position, [args, block])
|
|
33
|
+
@app.send(:build_rack_app)
|
|
34
|
+
@position += 1
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Represents the applications middleware as a stack, allowing for easily
|
|
40
|
+
# removing middleware or finding places to insert new middleware.
|
|
41
|
+
class Stack
|
|
42
|
+
def initialize(app, middleware)
|
|
43
|
+
@app = app
|
|
44
|
+
@middleware = middleware
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Return a StackPosition representing the position after the middleware where
|
|
48
|
+
# the block returns true. Yields the middleware and any middleware arguments
|
|
49
|
+
# given, but not the middleware block.
|
|
50
|
+
# It the block never returns true, returns a StackPosition that will insert
|
|
51
|
+
# new middleware at the end of the stack.
|
|
52
|
+
def after(&block)
|
|
53
|
+
handle(1, &block)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Return a StackPosition representing the position before the middleware where
|
|
57
|
+
# the block returns true. Yields the middleware and any middleware arguments
|
|
58
|
+
# given, but not the middleware block.
|
|
59
|
+
# It the block never returns true, returns a StackPosition that will insert
|
|
60
|
+
# new middleware at the end of the stack.
|
|
61
|
+
def before(&block)
|
|
62
|
+
handle(0, &block)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Removes any middleware where the block returns true. Yields the middleware
|
|
66
|
+
# and any middleware arguments given, but not the middleware block
|
|
67
|
+
def remove
|
|
68
|
+
@middleware.delete_if do |m, _|
|
|
69
|
+
yield(*m)
|
|
70
|
+
end
|
|
71
|
+
@app.send(:build_rack_app)
|
|
72
|
+
nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
# Internals of before and after.
|
|
78
|
+
def handle(offset)
|
|
79
|
+
@middleware.each_with_index do |(m, _), i|
|
|
80
|
+
if yield(*m)
|
|
81
|
+
return StackPosition.new(@app, @middleware, i+offset)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
StackPosition.new(@app, @middleware, @middleware.length)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
module ClassMethods
|
|
90
|
+
# Return a new Stack that allows removing middleware and inserting
|
|
91
|
+
# middleware at specific places in the stack.
|
|
92
|
+
def middleware_stack
|
|
93
|
+
Stack.new(self, @middleware)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
register_plugin(:middleware_stack, MiddlewareStack)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The module_include plugin adds request_module and response_module class methods
|
|
7
|
+
# for adding modules/methods to request/response classes. It's designed to make
|
|
8
|
+
# it easier to add request/response methods for a given roda class. To add a module
|
|
9
|
+
# to the request or response class:
|
|
10
|
+
#
|
|
11
|
+
# Roda.request_module SomeRequestModule
|
|
12
|
+
# Roda.response_module SomeResponseModule
|
|
13
|
+
#
|
|
14
|
+
# Alternatively, you can pass a block to the methods and it will create a module
|
|
15
|
+
# automatically:
|
|
16
|
+
#
|
|
17
|
+
# Roda.request_module do
|
|
18
|
+
# def description
|
|
19
|
+
# "#{request_method} #{path_info}"
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
module ModuleInclude
|
|
23
|
+
module ClassMethods
|
|
24
|
+
# Include the given module in the request class. If a block
|
|
25
|
+
# is provided instead of a module, create a module using the
|
|
26
|
+
# the block. Example:
|
|
27
|
+
#
|
|
28
|
+
# Roda.request_module SomeModule
|
|
29
|
+
#
|
|
30
|
+
# Roda.request_module do
|
|
31
|
+
# def description
|
|
32
|
+
# "#{request_method} #{path_info}"
|
|
33
|
+
# end
|
|
34
|
+
# end
|
|
35
|
+
#
|
|
36
|
+
# Roda.route do |r|
|
|
37
|
+
# r.description
|
|
38
|
+
# end
|
|
39
|
+
def request_module(mod = nil, &block)
|
|
40
|
+
module_include(:request, mod, &block)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Include the given module in the response class. If a block
|
|
44
|
+
# is provided instead of a module, create a module using the
|
|
45
|
+
# the block. Example:
|
|
46
|
+
#
|
|
47
|
+
# Roda.response_module SomeModule
|
|
48
|
+
#
|
|
49
|
+
# Roda.response_module do
|
|
50
|
+
# def error!
|
|
51
|
+
# self.status = 500
|
|
52
|
+
# end
|
|
53
|
+
# end
|
|
54
|
+
#
|
|
55
|
+
# Roda.route do |r|
|
|
56
|
+
# response.error!
|
|
57
|
+
# end
|
|
58
|
+
def response_module(mod = nil, &block)
|
|
59
|
+
module_include(:response, mod, &block)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
# Backbone of the request_module and response_module methods.
|
|
65
|
+
def module_include(type, mod, &block)
|
|
66
|
+
if type == :response
|
|
67
|
+
klass = self::RodaResponse
|
|
68
|
+
iv = :@response_module
|
|
69
|
+
else
|
|
70
|
+
klass = self::RodaRequest
|
|
71
|
+
iv = :@request_module
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
if mod
|
|
75
|
+
raise RodaError, "can't provide both argument and block to response_module" if defined?(yield)
|
|
76
|
+
klass.send(:include, mod)
|
|
77
|
+
else
|
|
78
|
+
if instance_variable_defined?(iv)
|
|
79
|
+
mod = instance_variable_get(iv)
|
|
80
|
+
else
|
|
81
|
+
mod = instance_variable_set(iv, Module.new)
|
|
82
|
+
RodaPlugins.set_temp_name(mod){"#{klass}::module_include"}
|
|
83
|
+
klass.send(:include, mod)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
mod.module_eval(&block) if block
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
mod
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
register_plugin(:module_include, ModuleInclude)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'rack/files'
|
|
5
|
+
rescue LoadError
|
|
6
|
+
require 'rack/file'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
class Roda
|
|
11
|
+
module RodaPlugins
|
|
12
|
+
# The multi_public plugin adds an +r.multi_public+ method that accepts an argument specifying
|
|
13
|
+
# a directory from which to serve static files. It is similar to the public plugin, but
|
|
14
|
+
# allows for multiple separate directories.
|
|
15
|
+
#
|
|
16
|
+
# Here's an example of using the multi_public plugin to serve 3 different types of files
|
|
17
|
+
# from 3 different directories:
|
|
18
|
+
#
|
|
19
|
+
# plugin :multi_public,
|
|
20
|
+
# img: 'static/images',
|
|
21
|
+
# font: 'assets/fonts',
|
|
22
|
+
# form: 'static/forms/pdfs'
|
|
23
|
+
#
|
|
24
|
+
# route do
|
|
25
|
+
# r.on "images" do
|
|
26
|
+
# r.multi_public(:img)
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# r.on "fonts" do
|
|
30
|
+
# r.multi_public(:font)
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# r.on "forms" do
|
|
34
|
+
# r.multi_public(:form)
|
|
35
|
+
# end
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# It is possible to simplify the routing tree for this using string keys and an array
|
|
39
|
+
# matcher:
|
|
40
|
+
#
|
|
41
|
+
# plugin :multi_public,
|
|
42
|
+
# 'images' => 'static/images',
|
|
43
|
+
# 'fonts' => 'assets/fonts',
|
|
44
|
+
# 'forms' => 'static/forms/pdfs'
|
|
45
|
+
#
|
|
46
|
+
# route do
|
|
47
|
+
# r.on %w"images fonts forms" do |dir|
|
|
48
|
+
# r.multi_public(dir)
|
|
49
|
+
# end
|
|
50
|
+
# end
|
|
51
|
+
#
|
|
52
|
+
# You can provide custom headers and default mime type for each directory using an array
|
|
53
|
+
# of three elements as the value, with the first element being the path, the second
|
|
54
|
+
# being the custom headers, and the third being the default mime type:
|
|
55
|
+
#
|
|
56
|
+
# plugin :multi_public,
|
|
57
|
+
# 'images' => ['static/images', {'Cache-Control'=>'max-age=86400'}, nil],
|
|
58
|
+
# 'fonts' => ['assets/fonts', {'Cache-Control'=>'max-age=31536000'}, 'font/ttf'],
|
|
59
|
+
# 'forms' => ['static/forms/pdfs', nil, 'application/pdf']
|
|
60
|
+
#
|
|
61
|
+
# route do
|
|
62
|
+
# r.on %w"images fonts forms" do |dir|
|
|
63
|
+
# r.multi_public(dir)
|
|
64
|
+
# end
|
|
65
|
+
# end
|
|
66
|
+
module MultiPublic
|
|
67
|
+
RACK_FILES = defined?(Rack::Files) ? Rack::Files : Rack::File
|
|
68
|
+
|
|
69
|
+
def self.load_dependencies(app, _, opts=OPTS)
|
|
70
|
+
app.plugin(:public, opts)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Use the given directories to setup servers. Any opts are passed to the public plugin.
|
|
74
|
+
def self.configure(app, directories, _=OPTS)
|
|
75
|
+
roots = app.opts[:multi_public_servers] = (app.opts[:multi_public_servers] || {}).dup
|
|
76
|
+
directories.each do |key, path|
|
|
77
|
+
path, headers, mime = path
|
|
78
|
+
roots[key] = RACK_FILES.new(app.expand_path(path), headers||{}, mime||'text/plain')
|
|
79
|
+
end
|
|
80
|
+
roots.freeze
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
module RequestMethods
|
|
84
|
+
# Serve files from the directory corresponding to the given key if the file exists and
|
|
85
|
+
# this is a GET request.
|
|
86
|
+
def multi_public(key)
|
|
87
|
+
public_serve_with(roda_class.opts[:multi_public_servers].fetch(key))
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
register_plugin(:multi_public, MultiPublic)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The multi_route plugin builds on the named_routes plugin and allows for
|
|
7
|
+
# dispatching to multiple named routes # by calling the +r.multi_route+ method,
|
|
8
|
+
# which will check # if the first segment in the path matches a named route,
|
|
9
|
+
# and dispatch to that named route.
|
|
10
|
+
#
|
|
11
|
+
# The hash_branches plugin offers a +r.hash_branches+ method that is similar to
|
|
12
|
+
# and performs better than the +r.multi_route+ method, and it is recommended
|
|
13
|
+
# to consider using that instead of this plugin.
|
|
14
|
+
#
|
|
15
|
+
# Example:
|
|
16
|
+
#
|
|
17
|
+
# plugin :multi_route
|
|
18
|
+
#
|
|
19
|
+
# route('foo') do |r|
|
|
20
|
+
# r.is 'bar' do
|
|
21
|
+
# '/foo/bar'
|
|
22
|
+
# end
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# route('bar') do |r|
|
|
26
|
+
# r.is 'foo' do
|
|
27
|
+
# '/bar/foo'
|
|
28
|
+
# end
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# route do |r|
|
|
32
|
+
# r.multi_route
|
|
33
|
+
# end
|
|
34
|
+
#
|
|
35
|
+
# Note that only named routes with string names will be dispatched to by the
|
|
36
|
+
# +r.multi_route+ method. Named routes with other names can be dispatched to
|
|
37
|
+
# using the named_routes plugin API, but will not be automatically dispatched
|
|
38
|
+
# to by +r.multi_route+.
|
|
39
|
+
#
|
|
40
|
+
# You can provide a block to +r.multi_route+ that is
|
|
41
|
+
# called if the route matches but the named route did not handle the
|
|
42
|
+
# request:
|
|
43
|
+
#
|
|
44
|
+
# r.multi_route do
|
|
45
|
+
# "default body"
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# If a block is not provided to multi_route, the return value of the named
|
|
49
|
+
# route block will be used.
|
|
50
|
+
#
|
|
51
|
+
# == Namespace Support
|
|
52
|
+
#
|
|
53
|
+
# The multi_route plugin also has support for namespaces, allowing you to
|
|
54
|
+
# use +r.multi_route+ at multiple levels in your routing tree. Example:
|
|
55
|
+
#
|
|
56
|
+
# route('foo') do |r|
|
|
57
|
+
# r.multi_route('foo')
|
|
58
|
+
# end
|
|
59
|
+
#
|
|
60
|
+
# route('bar') do |r|
|
|
61
|
+
# r.multi_route('bar')
|
|
62
|
+
# end
|
|
63
|
+
#
|
|
64
|
+
# route('baz', 'foo') do |r|
|
|
65
|
+
# # handles /foo/baz prefix
|
|
66
|
+
# end
|
|
67
|
+
#
|
|
68
|
+
# route('quux', 'foo') do |r|
|
|
69
|
+
# # handles /foo/quux prefix
|
|
70
|
+
# end
|
|
71
|
+
#
|
|
72
|
+
# route('baz', 'bar') do |r|
|
|
73
|
+
# # handles /bar/baz prefix
|
|
74
|
+
# end
|
|
75
|
+
#
|
|
76
|
+
# route('quux', 'bar') do |r|
|
|
77
|
+
# # handles /bar/quux prefix
|
|
78
|
+
# end
|
|
79
|
+
#
|
|
80
|
+
# route do |r|
|
|
81
|
+
# r.multi_route
|
|
82
|
+
# end
|
|
83
|
+
module MultiRoute
|
|
84
|
+
def self.load_dependencies(app)
|
|
85
|
+
app.plugin :named_routes
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Initialize storage for the named routes.
|
|
89
|
+
def self.configure(app)
|
|
90
|
+
app::RodaRequest.instance_variable_set(:@namespaced_route_regexps, {})
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
module ClassMethods
|
|
94
|
+
# Freeze the multi_route regexp matchers so that there can be no thread safety issues at runtime.
|
|
95
|
+
def freeze
|
|
96
|
+
super
|
|
97
|
+
opts[:namespaced_routes].each_key do |k|
|
|
98
|
+
self::RodaRequest.named_route_regexp(k)
|
|
99
|
+
end
|
|
100
|
+
self::RodaRequest.instance_variable_get(:@namespaced_route_regexps).freeze
|
|
101
|
+
self
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Copy the named routes into the subclass when inheriting.
|
|
105
|
+
def inherited(subclass)
|
|
106
|
+
super
|
|
107
|
+
subclass::RodaRequest.instance_variable_set(:@namespaced_route_regexps, {})
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Clear the multi_route regexp matcher for the namespace.
|
|
111
|
+
def route(name=nil, namespace=nil, &block)
|
|
112
|
+
super
|
|
113
|
+
if name
|
|
114
|
+
self::RodaRequest.clear_named_route_regexp!(namespace)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
module RequestClassMethods
|
|
120
|
+
# Clear cached regexp for named routes, it will be regenerated
|
|
121
|
+
# the next time it is needed.
|
|
122
|
+
#
|
|
123
|
+
# This shouldn't be an issue in production applications, but
|
|
124
|
+
# during development it's useful to support new named routes
|
|
125
|
+
# being added while the application is running.
|
|
126
|
+
def clear_named_route_regexp!(namespace=nil)
|
|
127
|
+
@namespaced_route_regexps.delete(namespace)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# A regexp matching any of the current named routes.
|
|
131
|
+
def named_route_regexp(namespace=nil)
|
|
132
|
+
@namespaced_route_regexps[namespace] ||= /(#{Regexp.union(roda_class.named_routes(namespace).select{|s| s.is_a?(String)}.sort.reverse)})/
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
module RequestMethods
|
|
137
|
+
# Check if the first segment in the path matches any of the current
|
|
138
|
+
# named routes. If so, call that named route. If not, do nothing.
|
|
139
|
+
# If the named route does not handle the request, and a block
|
|
140
|
+
# is given, yield to the block.
|
|
141
|
+
def multi_route(namespace=nil)
|
|
142
|
+
on self.class.named_route_regexp(namespace) do |section|
|
|
143
|
+
res = route(section, namespace)
|
|
144
|
+
if defined?(yield)
|
|
145
|
+
yield
|
|
146
|
+
else
|
|
147
|
+
res
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
register_plugin(:multi_route, MultiRoute)
|
|
155
|
+
end
|
|
156
|
+
end
|