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,91 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'find'
|
|
5
|
+
|
|
6
|
+
class Roda
|
|
7
|
+
module RodaPlugins
|
|
8
|
+
# The hash_public_cache plugin builds on top of the hash_public plugin and
|
|
9
|
+
# adds the ability to store the digests for the public files in a json file,
|
|
10
|
+
# and load that file at startup, which avoids the need for the process to
|
|
11
|
+
# read the public file in order to compute the digest.
|
|
12
|
+
#
|
|
13
|
+
# Examples:
|
|
14
|
+
#
|
|
15
|
+
# # Load the plugin. Options given will be passed to public and hash_public.
|
|
16
|
+
# plugin :hash_public_cache, "path/to/cache_file.json"
|
|
17
|
+
#
|
|
18
|
+
# # When rebuilding the cache:
|
|
19
|
+
# #
|
|
20
|
+
# # * Scan the public directory for files, calculate the digest on each.
|
|
21
|
+
# # * Write the hash public cache to a file.
|
|
22
|
+
# #
|
|
23
|
+
# # This is split into separate steps in case you want to modify the cache
|
|
24
|
+
# # manually after the scan.
|
|
25
|
+
# scan_hash_public_cache_dir
|
|
26
|
+
# dump_hash_public_cache_file
|
|
27
|
+
#
|
|
28
|
+
# # To load the cache at application startup (if the file exists):
|
|
29
|
+
# load_hash_public_cache_file
|
|
30
|
+
module HashPublicCache
|
|
31
|
+
def self.load_dependencies(app, _cache_file, opts = OPTS)
|
|
32
|
+
app.plugin :hash_public, opts
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Specify the location of the hash public cache file.
|
|
36
|
+
#
|
|
37
|
+
# The options given are passed to the hash_public plugin.
|
|
38
|
+
def self.configure(app, cache_file, opts = OPTS)
|
|
39
|
+
app.opts[:hash_public_cache_file] = cache_file
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
module ClassMethods
|
|
43
|
+
# Load the hash public cache file, if it exists. This replaces the hash
|
|
44
|
+
# public cache with the values from the file.
|
|
45
|
+
def load_hash_public_cache_file
|
|
46
|
+
file = opts[:hash_public_cache_file]
|
|
47
|
+
return unless File.file?(file)
|
|
48
|
+
|
|
49
|
+
cache = opts[:hash_public_cache] = (opts[:json_parser] || ::JSON.method(:parse)).call(::File.read(file))
|
|
50
|
+
cache.each_value(&:freeze)
|
|
51
|
+
nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Scan the public directory for files, computing the hash public digest
|
|
55
|
+
# for each. This will not rescan files that already have digest values.
|
|
56
|
+
# If a block is given, it will only calculate the digest for the file
|
|
57
|
+
# if the block returns truthy.
|
|
58
|
+
def scan_hash_public_cache_dir
|
|
59
|
+
cache = opts[:hash_public_cache]
|
|
60
|
+
|
|
61
|
+
# Public root doesn't have trailing slash even if given, as
|
|
62
|
+
# File.expand_path removes it.
|
|
63
|
+
root = opts[:public_root] + File::SEPARATOR
|
|
64
|
+
|
|
65
|
+
Find.find(opts[:public_root]) do |file|
|
|
66
|
+
if File.file?(file)
|
|
67
|
+
file = file.sub(root, '')
|
|
68
|
+
next if cache[file]
|
|
69
|
+
|
|
70
|
+
if defined?(yield)
|
|
71
|
+
next unless yield file
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
cache[file] = hash_path_digest(file)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Write the current hash public cache to the cache file.
|
|
82
|
+
def dump_hash_public_cache_file
|
|
83
|
+
File.write(opts[:hash_public_cache_file], (opts[:json_serializer] || :to_json.to_proc).call(opts[:hash_public_cache]))
|
|
84
|
+
nil
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
register_plugin(:hash_public_cache, HashPublicCache)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The hash_routes plugin builds on top of the hash_branches and hash_paths plugins, and adds
|
|
7
|
+
# a DSL for configuring hash branches and paths. It also adds an +r.hash_routes+ method for
|
|
8
|
+
# first attempting dispatch to the configured hash_paths, then to the configured hash_branches:
|
|
9
|
+
#
|
|
10
|
+
# class App < Roda
|
|
11
|
+
# plugin :hash_routes
|
|
12
|
+
#
|
|
13
|
+
# hash_branch("a") do |r|
|
|
14
|
+
# # /a branch
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# hash_branch("b") do |r|
|
|
18
|
+
# # /b branch
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# hash_path("/a") do |r|
|
|
22
|
+
# # /a path
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# hash_path("/a/b") do |r|
|
|
26
|
+
# # /a/b path
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# route do |r|
|
|
30
|
+
# r.hash_routes
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# With the above routing tree, requests for +/a+ and +/a/b+ will be routed to the appropriate
|
|
35
|
+
# +hash_path+ block. Other requests for the +/a+ branch, and all requests for the +/b+
|
|
36
|
+
# branch will be routed to the appropriate +hash_branch+ block.
|
|
37
|
+
#
|
|
38
|
+
# It is best for performance to explicitly specify the namespace when calling
|
|
39
|
+
# +r.hash_routes+.
|
|
40
|
+
#
|
|
41
|
+
# Because specifying routes explicitly using the +hash_branch+ and +hash_path+
|
|
42
|
+
# class methods can get repetitive, the hash_routes plugin offers a DSL for DRYing
|
|
43
|
+
# the code up. This DSL is used by calling the +hash_routes+ class method. The
|
|
44
|
+
# DSL used tries to mirror the standard Roda DSL, but it is not a normal routing
|
|
45
|
+
# tree (it's not possible to execute arbitrary code between branches during routing).
|
|
46
|
+
#
|
|
47
|
+
# class App < Roda
|
|
48
|
+
# plugin :hash_routes
|
|
49
|
+
#
|
|
50
|
+
# # No block argument is used, DSL evaluates block using instance_exec
|
|
51
|
+
# hash_routes "" do
|
|
52
|
+
# # on method is used for routing to next segment,
|
|
53
|
+
# # for similarity to standard Roda
|
|
54
|
+
# on "a" do |r|
|
|
55
|
+
# r.hash_routes '/a'
|
|
56
|
+
# end
|
|
57
|
+
#
|
|
58
|
+
# on "b" do |r|
|
|
59
|
+
# r.hash_routes(:b)
|
|
60
|
+
# end
|
|
61
|
+
# end
|
|
62
|
+
#
|
|
63
|
+
# # Block argument is used, block is yielded DSL instance
|
|
64
|
+
# hash_routes "/a" do |hr|
|
|
65
|
+
# # is method is used for routing to the remaining path,
|
|
66
|
+
# # for similarity to standard Roda
|
|
67
|
+
# hr.is "b" do |r|
|
|
68
|
+
# # /a/b path
|
|
69
|
+
# end
|
|
70
|
+
#
|
|
71
|
+
# hr.is "c" do |r|
|
|
72
|
+
# # /a/c path
|
|
73
|
+
# end
|
|
74
|
+
# end
|
|
75
|
+
#
|
|
76
|
+
# hash_routes :b do
|
|
77
|
+
# is "b" do |r|
|
|
78
|
+
# # /b/b path
|
|
79
|
+
# end
|
|
80
|
+
#
|
|
81
|
+
# is "c" do |r|
|
|
82
|
+
# # /b/c path
|
|
83
|
+
# end
|
|
84
|
+
# end
|
|
85
|
+
#
|
|
86
|
+
# route do |r|
|
|
87
|
+
# # No change here, DSL only makes setup DRYer
|
|
88
|
+
# r.hash_branches
|
|
89
|
+
# end
|
|
90
|
+
# end
|
|
91
|
+
#
|
|
92
|
+
# The +hash_routes+ DSL also offers some additional features to handle additional
|
|
93
|
+
# cases. It supports verb methods, such as +get+ and +post+, which operate like
|
|
94
|
+
# +is+, but are only called if the verb matches (and are not yielded the request).
|
|
95
|
+
# It supports a +view+ method for routes that only render views, as well as a
|
|
96
|
+
# +views+ method for setting up routes for multiple views in a single call, which
|
|
97
|
+
# is a good replacement for the +multi_view+ plugin.
|
|
98
|
+
# +is+, +view+, and the verb methods can use a value of +true+ for the empty
|
|
99
|
+
# remaining path (as the empty string specifies the <tt>"/"</tt> remaining path).
|
|
100
|
+
# It also supports a +dispatch_from+ method, allowing you to setup dispatching to
|
|
101
|
+
# current group of routes from a higher-level namespace.
|
|
102
|
+
# The +hash_routes+ class method will return the DSL instance, so you are not
|
|
103
|
+
# limited to using it with a block.
|
|
104
|
+
#
|
|
105
|
+
# Here's the above example modified to use some of these features:
|
|
106
|
+
#
|
|
107
|
+
# class App < Roda
|
|
108
|
+
# plugin :hash_routes
|
|
109
|
+
#
|
|
110
|
+
# hash_routes "/a" do
|
|
111
|
+
# # Dispatch requests for the /a branch from the empty (default) routing
|
|
112
|
+
# # namespace to this namespace
|
|
113
|
+
# dispatch_from "a"
|
|
114
|
+
#
|
|
115
|
+
# # Handle GET /a path, render "a" template, returning 404 for non-GET requests
|
|
116
|
+
# view true, "a"
|
|
117
|
+
#
|
|
118
|
+
# # Handle /a/b path, returning 404 for non-GET requests
|
|
119
|
+
# get "b" do
|
|
120
|
+
# # GET /a/b path
|
|
121
|
+
# end
|
|
122
|
+
#
|
|
123
|
+
# # Handle /a/c path, returning 404 for non-POST requests
|
|
124
|
+
# post "c" do
|
|
125
|
+
# # POST /a/c path
|
|
126
|
+
# end
|
|
127
|
+
# end
|
|
128
|
+
#
|
|
129
|
+
# bhr = hash_routes(:b)
|
|
130
|
+
#
|
|
131
|
+
# # Dispatch requests for the /b branch from the empty routing to this namespace,
|
|
132
|
+
# # but first check routes in the :b_preauth namespace. If there is no
|
|
133
|
+
# # matching route in the :b_preauth namespace, call the check_authenticated!
|
|
134
|
+
# # method before dispatching to any of the routes in this namespace
|
|
135
|
+
# bhr.dispatch_from "", "b" do |r|
|
|
136
|
+
# r.hash_routes :b_preauth
|
|
137
|
+
# check_authenticated!
|
|
138
|
+
# end
|
|
139
|
+
#
|
|
140
|
+
# bhr.is true do |r|
|
|
141
|
+
# # /b path
|
|
142
|
+
# end
|
|
143
|
+
#
|
|
144
|
+
# bhr.is "" do |r|
|
|
145
|
+
# # /b/ path
|
|
146
|
+
# end
|
|
147
|
+
#
|
|
148
|
+
# # GET /b/d path, render 'd2' template, returning 404 for non-GET requests
|
|
149
|
+
# bhr.views 'd', 'd2'
|
|
150
|
+
#
|
|
151
|
+
# # GET /b/e path, render 'e' template, returning 404 for non-GET requests
|
|
152
|
+
# # GET /b/f path, render 'f' template, returning 404 for non-GET requests
|
|
153
|
+
# bhr.views %w'e f'
|
|
154
|
+
#
|
|
155
|
+
# route do |r|
|
|
156
|
+
# r.hash_branches
|
|
157
|
+
# end
|
|
158
|
+
# end
|
|
159
|
+
#
|
|
160
|
+
# The +view+ and +views+ method depend on the render plugin being loaded, but this
|
|
161
|
+
# plugin does not load the render plugin. You must load the render plugin separately
|
|
162
|
+
# if you want to use the +view+ and +views+ methods.
|
|
163
|
+
#
|
|
164
|
+
# Certain parts of the +hash_routes+ DSL support do not work with the
|
|
165
|
+
# route_block_args plugin, as doing so would reduce performance. These are:
|
|
166
|
+
#
|
|
167
|
+
# * dispatch_from
|
|
168
|
+
# * view
|
|
169
|
+
# * views
|
|
170
|
+
# * all verb methods (get, post, etc.)
|
|
171
|
+
module HashRoutes
|
|
172
|
+
def self.load_dependencies(app)
|
|
173
|
+
app.plugin :hash_branches
|
|
174
|
+
app.plugin :hash_paths
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def self.configure(app)
|
|
178
|
+
app.opts[:hash_routes_methods] ||= {}
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Internal class handling the internals of the +hash_routes+ class method blocks.
|
|
182
|
+
class DSL
|
|
183
|
+
def initialize(roda, namespace)
|
|
184
|
+
@roda = roda
|
|
185
|
+
@namespace = namespace
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Setup the given branch in the given namespace to dispatch to routes in this
|
|
189
|
+
# namespace. If a block is given, call the block with the request before
|
|
190
|
+
# dispatching to routes in this namespace.
|
|
191
|
+
def dispatch_from(namespace='', branch, &block)
|
|
192
|
+
ns = @namespace
|
|
193
|
+
if block
|
|
194
|
+
meth_hash = @roda.opts[:hash_routes_methods]
|
|
195
|
+
key = [:dispatch_from, namespace, branch].freeze
|
|
196
|
+
meth = meth_hash[key] = @roda.define_roda_method(meth_hash[key] || "hash_routes_dispatch_from_#{namespace}_#{branch}", 1, &block)
|
|
197
|
+
@roda.hash_branch(namespace, branch) do |r|
|
|
198
|
+
send(meth, r)
|
|
199
|
+
r.hash_routes(ns)
|
|
200
|
+
end
|
|
201
|
+
else
|
|
202
|
+
@roda.hash_branch(namespace, branch) do |r|
|
|
203
|
+
r.hash_routes(ns)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Use the segment to setup a branch in the current namespace.
|
|
209
|
+
def on(segment, &block)
|
|
210
|
+
@roda.hash_branch(@namespace, segment, &block)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Use the segment to setup a path in the current namespace.
|
|
214
|
+
# If path is given as a string, it is prefixed with a slash.
|
|
215
|
+
# If path is +true+, the empty string is used as the path.
|
|
216
|
+
def is(path, &block)
|
|
217
|
+
path = path == true ? "" : "/#{path}"
|
|
218
|
+
@roda.hash_path(@namespace, path, &block)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Use the segment to setup a path in the current namespace that
|
|
222
|
+
# will render the view with the given name if the GET method is
|
|
223
|
+
# used, and will return a 404 if another request method is used.
|
|
224
|
+
# If path is given as a string, it is prefixed with a slash.
|
|
225
|
+
# If path is +true+, the empty string is used as the path.
|
|
226
|
+
def view(path, template)
|
|
227
|
+
path = path == true ? "" : "/#{path}"
|
|
228
|
+
@roda.hash_path(@namespace, path) do |r|
|
|
229
|
+
r.get do
|
|
230
|
+
view(template)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# For each template in the array of templates, setup a path in
|
|
236
|
+
# the current namespace for the template using the same name
|
|
237
|
+
# as the template.
|
|
238
|
+
def views(templates)
|
|
239
|
+
templates.each do |template|
|
|
240
|
+
view(template, template)
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
[:get, :post, :delete, :head, :options, :link, :patch, :put, :trace, :unlink].each do |meth|
|
|
245
|
+
define_method(meth) do |path, &block|
|
|
246
|
+
verb(meth, path, &block)
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
private
|
|
251
|
+
|
|
252
|
+
# Setup a path in the current namespace for the given request method verb.
|
|
253
|
+
# Returns 404 for requests for the path with a different request method.
|
|
254
|
+
def verb(verb, path, &block)
|
|
255
|
+
path = path == true ? "" : "/#{path}"
|
|
256
|
+
meth_hash = @roda.opts[:hash_routes_methods]
|
|
257
|
+
key = [@namespace, path].freeze
|
|
258
|
+
meth = meth_hash[key] = @roda.define_roda_method(meth_hash[key] || "hash_routes_#{@namespace}_#{path}", 0, &block)
|
|
259
|
+
@roda.hash_path(@namespace, path) do |r|
|
|
260
|
+
r.send(verb) do
|
|
261
|
+
send(meth)
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
module ClassMethods
|
|
268
|
+
# Freeze the hash_routes metadata when freezing the app.
|
|
269
|
+
def freeze
|
|
270
|
+
opts[:hash_routes_methods].freeze
|
|
271
|
+
super
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Invoke the DSL for configuring hash routes, see DSL for methods inside the
|
|
275
|
+
# block. If the block accepts an argument, yield the DSL instance. If the
|
|
276
|
+
# block does not accept an argument, instance_exec the block in the context
|
|
277
|
+
# of the DSL instance.
|
|
278
|
+
def hash_routes(namespace='', &block)
|
|
279
|
+
dsl = DSL.new(self, namespace)
|
|
280
|
+
if block
|
|
281
|
+
if block.arity == 1
|
|
282
|
+
yield dsl
|
|
283
|
+
else
|
|
284
|
+
dsl.instance_exec(&block)
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
dsl
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
module RequestMethods
|
|
293
|
+
# Check for matches in both the hash_path and hash_branch namespaces for
|
|
294
|
+
# a matching remaining path or next segment in the remaining path, respectively.
|
|
295
|
+
def hash_routes(namespace=matched_path)
|
|
296
|
+
hash_paths(namespace)
|
|
297
|
+
hash_branches(namespace)
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
register_plugin(:hash_routes, HashRoutes)
|
|
303
|
+
end
|
|
304
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The head plugin attempts to automatically handle HEAD requests,
|
|
7
|
+
# by treating them as GET requests and returning an empty body
|
|
8
|
+
# without modifying the response status or response headers.
|
|
9
|
+
#
|
|
10
|
+
# So for the following routes,
|
|
11
|
+
#
|
|
12
|
+
# route do |r|
|
|
13
|
+
# r.root do
|
|
14
|
+
# 'root'
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# r.get 'a' do
|
|
18
|
+
# 'a'
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# r.is 'b', method: [:get, :post] do
|
|
22
|
+
# 'b'
|
|
23
|
+
# end
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# HEAD requests for +/+, +/a+, and +/b+ will all return 200 status
|
|
27
|
+
# with an empty body.
|
|
28
|
+
#
|
|
29
|
+
# This plugin also works with the not_allowed plugin if it is loaded
|
|
30
|
+
# after the not_allowed plugin. In that case, if GET is one of Allow
|
|
31
|
+
# header options, then HEAD will be as well.
|
|
32
|
+
#
|
|
33
|
+
# NOTE: if you have a public facing website it is recommended that
|
|
34
|
+
# you enable this plugin, or manually handle HEAD anywhere you would
|
|
35
|
+
# handle GET. Search engines and other bots may send a
|
|
36
|
+
# HEAD request prior to crawling a page with a GET request. Without
|
|
37
|
+
# this plugin those HEAD requests will return a 404 status, which
|
|
38
|
+
# may prevent search engines from crawling your website.
|
|
39
|
+
module Head
|
|
40
|
+
# used to ensure proper resource release on HEAD requests
|
|
41
|
+
# we do not respond to a to_path method, here.
|
|
42
|
+
class CloseLater
|
|
43
|
+
def initialize(body)
|
|
44
|
+
@body = body
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# yield nothing
|
|
48
|
+
def each(&_)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# this should be called by the Rack server
|
|
52
|
+
def close
|
|
53
|
+
@body.close
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
module InstanceMethods
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
# Always use an empty response body for head requests, with a
|
|
61
|
+
# content length of 0.
|
|
62
|
+
def _roda_after_30__head(res)
|
|
63
|
+
if res && @_request.head?
|
|
64
|
+
body = res[2]
|
|
65
|
+
if body.respond_to?(:close)
|
|
66
|
+
res[2] = CloseLater.new(body)
|
|
67
|
+
else
|
|
68
|
+
res[2] = EMPTY_ARRAY
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
module RequestMethods
|
|
75
|
+
# Consider HEAD requests as GET requests.
|
|
76
|
+
def is_get?
|
|
77
|
+
super || head?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
# If the current request is a HEAD request, match if one of
|
|
83
|
+
# the given methods is a GET request.
|
|
84
|
+
def match_method(method)
|
|
85
|
+
super || (!method.is_a?(Array) && head? && method.to_s.upcase == 'GET')
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Work with the not_allowed plugin so that if GET is one
|
|
89
|
+
# of the Allow header options, then HEAD is as well.
|
|
90
|
+
def method_not_allowed(verbs)
|
|
91
|
+
verbs = verbs.sub('GET', 'HEAD, GET')
|
|
92
|
+
super
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
register_plugin(:head, Head)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The header_matchers plugin adds hash matchers for matching on less-common
|
|
7
|
+
# HTTP headers.
|
|
8
|
+
#
|
|
9
|
+
# plugin :header_matchers
|
|
10
|
+
#
|
|
11
|
+
# It adds a +:header+ matcher for matching on arbitrary headers, which matches
|
|
12
|
+
# if the header is present, and yields the header value:
|
|
13
|
+
#
|
|
14
|
+
# r.on header: 'HTTP-X-App-Token' do |header_value|
|
|
15
|
+
# # Looks for env['HTTP_X_APP_TOKEN'] and yields it
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# It adds a +:host+ matcher for matching by the host of the request:
|
|
19
|
+
#
|
|
20
|
+
# r.on host: 'foo.example.com' do
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# For regexp values of the +:host+ matcher, any captures are yielded to the block:
|
|
24
|
+
#
|
|
25
|
+
# r.on host: /\A(\w+).example.com\z/ do |subdomain|
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
28
|
+
# It adds a +:user_agent+ matcher for matching on a user agent patterns, which
|
|
29
|
+
# yields the regexp captures to the block:
|
|
30
|
+
#
|
|
31
|
+
# r.on user_agent: /Chrome\/([.\d]+)/ do |chrome_version|
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# It adds an +:accept+ matcher for matching based on the Accept header:
|
|
35
|
+
#
|
|
36
|
+
# r.on accept: 'text/csv' do
|
|
37
|
+
# end
|
|
38
|
+
#
|
|
39
|
+
# Note that the +:accept+ matcher is very simple and cannot handle wildcards,
|
|
40
|
+
# priorities, or anything but a simple comma separated list of mime types.
|
|
41
|
+
module HeaderMatchers
|
|
42
|
+
module RequestMethods
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
# Match if the given mimetype is one of the accepted mimetypes.
|
|
46
|
+
def match_accept(mimetype)
|
|
47
|
+
if @env["HTTP_ACCEPT"].to_s.split(',').any?{|s| s.strip == mimetype}
|
|
48
|
+
response[RodaResponseHeaders::CONTENT_TYPE] = mimetype
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Match if the given uppercase key is present inside the environment.
|
|
53
|
+
def match_header(key)
|
|
54
|
+
key = key.upcase
|
|
55
|
+
key.tr!("-","_")
|
|
56
|
+
unless key == "CONTENT_TYPE" || key == "CONTENT_LENGTH"
|
|
57
|
+
key = "HTTP_#{key}"
|
|
58
|
+
end
|
|
59
|
+
if v = @env[key]
|
|
60
|
+
@captures << v
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Match if the host of the request is the same as the hostname. +hostname+
|
|
65
|
+
# can be a regexp or a string.
|
|
66
|
+
def match_host(hostname)
|
|
67
|
+
if hostname.is_a?(Regexp)
|
|
68
|
+
if match = hostname.match(host)
|
|
69
|
+
@captures.concat(match.captures)
|
|
70
|
+
end
|
|
71
|
+
else
|
|
72
|
+
hostname === host
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Match the submitted user agent to the given pattern, capturing any
|
|
77
|
+
# regexp match groups.
|
|
78
|
+
def match_user_agent(pattern)
|
|
79
|
+
if (user_agent = @env["HTTP_USER_AGENT"]) && (match = pattern.match(user_agent))
|
|
80
|
+
@captures.concat(match.captures)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
register_plugin(:header_matchers, HeaderMatchers)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The heartbeat handles heartbeat/status requests. If a request for
|
|
7
|
+
# the heartbeat path comes in, a 200 response with a
|
|
8
|
+
# text/plain Content-Type and a body of "OK" will be returned.
|
|
9
|
+
# The default heartbeat path is "/heartbeat", so to use that:
|
|
10
|
+
#
|
|
11
|
+
# plugin :heartbeat
|
|
12
|
+
#
|
|
13
|
+
# You can also specify a custom heartbeat path:
|
|
14
|
+
#
|
|
15
|
+
# plugin :heartbeat, path: '/status'
|
|
16
|
+
module Heartbeat
|
|
17
|
+
# Set the heartbeat path to the given path.
|
|
18
|
+
def self.configure(app, opts=OPTS)
|
|
19
|
+
app.opts[:heartbeat_path] = (opts[:path] || app.opts[:heartbeat_path] || "/heartbeat").dup.freeze
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module InstanceMethods
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
# If the request is for a heartbeat path, return the heartbeat response.
|
|
26
|
+
def _roda_before_20__heartbeat
|
|
27
|
+
if env['PATH_INFO'] == opts[:heartbeat_path]
|
|
28
|
+
response = @_response
|
|
29
|
+
response.status = 200
|
|
30
|
+
response[RodaResponseHeaders::CONTENT_TYPE] = 'text/plain'
|
|
31
|
+
response.write 'OK'
|
|
32
|
+
throw :halt, response.finish
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
register_plugin(:heartbeat, Heartbeat)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|