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,46 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The run_require_slash plugin makes +r.run+ a no-op if the remaining
|
|
7
|
+
# path is not empty and does not start with +/+. The Rack SPEC requires that
|
|
8
|
+
# +PATH_INFO+ start with a slash if not empty, so this plugin prevents
|
|
9
|
+
# dispatching to the application with an environment that would violate the
|
|
10
|
+
# Rack SPEC.
|
|
11
|
+
#
|
|
12
|
+
# You are unlikely to want to use this plugin unless you are consuming partial
|
|
13
|
+
# segments of the request path, or using the match_affix plugin to change
|
|
14
|
+
# how routing is done:
|
|
15
|
+
#
|
|
16
|
+
# plugin :match_affix, "", /(\/|\z)/
|
|
17
|
+
# route do |r|
|
|
18
|
+
# r.on "/a" do
|
|
19
|
+
# r.on "b" do
|
|
20
|
+
# r.run App
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# # with run_require_slash:
|
|
26
|
+
# # GET /a/b/e => Not dispatched to application
|
|
27
|
+
# # GET /a/b => App gets "" as PATH_INFO
|
|
28
|
+
#
|
|
29
|
+
# # without run_require_slash:
|
|
30
|
+
# # GET /a/b/e => App gets "e" as PATH_INFO, violating rack SPEC
|
|
31
|
+
# # GET /a/b => App gets "" as PATH_INFO
|
|
32
|
+
module RunRequireSlash
|
|
33
|
+
module RequestMethods
|
|
34
|
+
# Calls the given rack app only if the remaining patch is empty or
|
|
35
|
+
# starts with a slash.
|
|
36
|
+
def run(*)
|
|
37
|
+
if @remaining_path.empty? || @remaining_path.start_with?('/')
|
|
38
|
+
super
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
register_plugin(:run_require_slash, RunRequireSlash)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
class Roda
|
|
4
|
+
module RodaPlugins
|
|
5
|
+
# The sec_fetch_site_csrf plugin allows for CSRF protection using the
|
|
6
|
+
# Sec-Fetch-Site header added in modern browsers. It allows for CSRF
|
|
7
|
+
# protection without the use of CSRF tokens, which can simplify
|
|
8
|
+
# form creation.
|
|
9
|
+
#
|
|
10
|
+
# The protection offered by the sec_fetch_site_csrf plugin is weaker than
|
|
11
|
+
# the protection offered by the route_csrf plugin with default settings,
|
|
12
|
+
# since it doesn't support per-request tokens. Be aware you are trading
|
|
13
|
+
# security for simplicity when using the sec_fetch_site_csrf plugin instead
|
|
14
|
+
# of the route_csrf plugin. Other caveats in using the sec_fetch_site_csrf
|
|
15
|
+
# plugin:
|
|
16
|
+
#
|
|
17
|
+
# * Not all browsers set the Sec-Fetch-Site header. Some browsers
|
|
18
|
+
# didn't start setting the header until 2023. In these cases, you
|
|
19
|
+
# need to decide how to handle the request. The default is to deny
|
|
20
|
+
# the request, though you can use the :allow_missing option to allow
|
|
21
|
+
# it.
|
|
22
|
+
#
|
|
23
|
+
# * Sec-Fetch-Site headers are not set for http requests, only https
|
|
24
|
+
# requests, so this doesn't offer protection for http requests.
|
|
25
|
+
#
|
|
26
|
+
# * It isn't possible to share a CSRF secret between applications in
|
|
27
|
+
# different origins to allow cross-site requests between the
|
|
28
|
+
# applications.
|
|
29
|
+
#
|
|
30
|
+
# This plugin adds the +check_sec_fetch_site!+ method to the routing
|
|
31
|
+
# block scope. You should call this method at the appropriate place
|
|
32
|
+
# in the routing tree to enforce the CSRF protection. The method can
|
|
33
|
+
# accept a block to override the :csrf_failure plugin option behavior
|
|
34
|
+
# on a per-call basis.
|
|
35
|
+
#
|
|
36
|
+
# When loading the plugin with no options:
|
|
37
|
+
#
|
|
38
|
+
# plugin :sec_fetch_site_csrf
|
|
39
|
+
#
|
|
40
|
+
# Only same-origin requests are allowed by default.
|
|
41
|
+
#
|
|
42
|
+
# This plugin supports the following options:
|
|
43
|
+
#
|
|
44
|
+
# :allow_missing :: Whether to allow requests lacking the Sec-Fetch-Site
|
|
45
|
+
# header (false by default).
|
|
46
|
+
# :allow_none :: Whether to allow requests where Sec-Fetch-Value is none
|
|
47
|
+
# (false by default).
|
|
48
|
+
# :allow_same_site :: Whether to allow requests where Sec-Fetch-Value is
|
|
49
|
+
# same-site (false by default)
|
|
50
|
+
# :check_request_methods :: Which request methods require CSRF protection
|
|
51
|
+
# (default: <tt>['POST', 'DELETE', 'PATCH', 'PUT']</tt>)
|
|
52
|
+
# :csrf_failure :: The action to taken if a request does not have a valid header
|
|
53
|
+
# (default: :raise). Options:
|
|
54
|
+
# :raise :: raise a Roda::RodaPlugins::SecFetchSiteCsrf::CsrfFailure
|
|
55
|
+
# exception
|
|
56
|
+
# :empty_403 :: return a blank 403 page
|
|
57
|
+
# :clear_session :: clear the current session
|
|
58
|
+
#
|
|
59
|
+
# The plugin also supports a block, in which case failures will call the block
|
|
60
|
+
# as a routing block (the block should accept the request object).
|
|
61
|
+
module SecFetchSiteCsrf
|
|
62
|
+
DEFAULTS = {
|
|
63
|
+
:csrf_failure => :raise,
|
|
64
|
+
:check_request_methods => %w'POST DELETE PATCH PUT'.freeze.each(&:freeze)
|
|
65
|
+
}.freeze
|
|
66
|
+
|
|
67
|
+
# Exception class raised when :csrf_failure option is :raise and
|
|
68
|
+
# the Sec-Fetch-Site header is not considered valid.
|
|
69
|
+
class CsrfFailure < RodaError; end
|
|
70
|
+
|
|
71
|
+
def self.configure(app, opts=OPTS, &block)
|
|
72
|
+
options = app.opts[:sec_fetch_site_csrf] = (app.opts[:sec_fetch_site_csrf] || DEFAULTS).merge(opts)
|
|
73
|
+
|
|
74
|
+
allowed_values = options[:allowed_values] = ["same-origin"]
|
|
75
|
+
allowed_values << "same-site" if opts[:allow_same_site]
|
|
76
|
+
allowed_values << "none" if opts[:allow_none]
|
|
77
|
+
allowed_values << nil if opts[:allow_missing]
|
|
78
|
+
allowed_values.freeze
|
|
79
|
+
|
|
80
|
+
if block
|
|
81
|
+
options[:csrf_failure] = :method
|
|
82
|
+
app.define_roda_method(:_roda_sec_fetch_site_csrf_failure, 1, &app.send(:convert_route_block, block))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
case options[:csrf_failure]
|
|
86
|
+
when :raise, :empty_403, :clear_session, :method
|
|
87
|
+
# nothing
|
|
88
|
+
else
|
|
89
|
+
raise RodaError, "Unsupported :csrf_failure plugin option: #{options[:csrf_failure].inspect}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
options.freeze
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
module InstanceMethods
|
|
96
|
+
# Check that the Sec-Fetch-Site header is valid, if the request requires it.
|
|
97
|
+
# If the header is valid or the request does not require the header, return nil.
|
|
98
|
+
# Otherwise, if a block is given, treat it as a routing block and yield to it, and
|
|
99
|
+
# if a block is not given, use the plugin :csrf_failure option to determine how to
|
|
100
|
+
# handle it.
|
|
101
|
+
def check_sec_fetch_site!(&block)
|
|
102
|
+
plugin_opts = self.class.opts[:sec_fetch_site_csrf]
|
|
103
|
+
return unless plugin_opts[:check_request_methods].include?(request.request_method)
|
|
104
|
+
|
|
105
|
+
sec_fetch_site = env["HTTP_SEC_FETCH_SITE"]
|
|
106
|
+
return if plugin_opts[:allowed_values].include?(sec_fetch_site)
|
|
107
|
+
|
|
108
|
+
@_request.on(&block) if block
|
|
109
|
+
|
|
110
|
+
case failure_action = plugin_opts[:csrf_failure]
|
|
111
|
+
when :raise
|
|
112
|
+
raise CsrfFailure, "potential cross-site request, Sec-Fetch-Site value: #{sec_fetch_site.inspect}"
|
|
113
|
+
when :empty_403
|
|
114
|
+
@_response.status = 403
|
|
115
|
+
headers = @_response.headers
|
|
116
|
+
headers.clear
|
|
117
|
+
headers[RodaResponseHeaders::CONTENT_TYPE] = 'text/html'
|
|
118
|
+
headers[RodaResponseHeaders::CONTENT_LENGTH] ='0'
|
|
119
|
+
throw :halt, @_response.finish_with_body([])
|
|
120
|
+
when :clear_session
|
|
121
|
+
session.clear
|
|
122
|
+
else # when :method
|
|
123
|
+
@_request.on{_roda_sec_fetch_site_csrf_failure(@_request)}
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
register_plugin(:sec_fetch_site_csrf, SecFetchSiteCsrf)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
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 send_file plugin adds a send_file method, used for
|
|
13
|
+
# returning the contents of a file as the body of a request.
|
|
14
|
+
# It also loads the response_attachment plugin to set the
|
|
15
|
+
# Content-Disposition and Content-Type based on the file's
|
|
16
|
+
# extension.
|
|
17
|
+
#
|
|
18
|
+
# senf_file will serve the file with the given path from the file system:
|
|
19
|
+
#
|
|
20
|
+
# send_file 'path/to/file.txt'
|
|
21
|
+
#
|
|
22
|
+
# Options:
|
|
23
|
+
#
|
|
24
|
+
# :disposition :: Set the Content-Disposition to the given disposition.
|
|
25
|
+
# :filename :: Set the Content-Disposition to attachment (unless :disposition is set),
|
|
26
|
+
# and set the filename parameter to the value.
|
|
27
|
+
# :last_modified :: Explicitly set the Last-Modified header to the given value, and
|
|
28
|
+
# return a not modified response if there has not been modified since
|
|
29
|
+
# the previous request. This option requires the caching plugin.
|
|
30
|
+
# :status :: Override the status for the response.
|
|
31
|
+
# :type :: Set the Content-Type to use for this response.
|
|
32
|
+
#
|
|
33
|
+
# == License
|
|
34
|
+
#
|
|
35
|
+
# The implementation was originally taken from Sinatra,
|
|
36
|
+
# which is also released under the MIT License:
|
|
37
|
+
#
|
|
38
|
+
# Copyright (c) 2007, 2008, 2009 Blake Mizerany
|
|
39
|
+
# Copyright (c) 2010, 2011, 2012, 2013, 2014 Konstantin Haase
|
|
40
|
+
#
|
|
41
|
+
# Permission is hereby granted, free of charge, to any person
|
|
42
|
+
# obtaining a copy of this software and associated documentation
|
|
43
|
+
# files (the "Software"), to deal in the Software without
|
|
44
|
+
# restriction, including without limitation the rights to use,
|
|
45
|
+
# copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
46
|
+
# copies of the Software, and to permit persons to whom the
|
|
47
|
+
# Software is furnished to do so, subject to the following
|
|
48
|
+
# conditions:
|
|
49
|
+
#
|
|
50
|
+
# The above copyright notice and this permission notice shall be
|
|
51
|
+
# included in all copies or substantial portions of the Software.
|
|
52
|
+
#
|
|
53
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
54
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
55
|
+
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
56
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
57
|
+
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
58
|
+
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
59
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
60
|
+
# OTHER DEALINGS IN THE SOFTWARE.
|
|
61
|
+
module SendFile
|
|
62
|
+
RACK_FILES = defined?(Rack::Files) ? Rack::Files : Rack::File
|
|
63
|
+
|
|
64
|
+
# Depend on the status_303 plugin.
|
|
65
|
+
def self.load_dependencies(app)
|
|
66
|
+
app.plugin :response_attachment
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
module InstanceMethods
|
|
70
|
+
# Use the contents of the file at +path+ as the response body. See plugin documentation for options.
|
|
71
|
+
def send_file(path, opts = OPTS)
|
|
72
|
+
r = @_request
|
|
73
|
+
res = @_response
|
|
74
|
+
headers = res.headers
|
|
75
|
+
if (type = opts[:type]) || !headers[RodaResponseHeaders::CONTENT_TYPE]
|
|
76
|
+
type_str = type.to_s
|
|
77
|
+
|
|
78
|
+
if type_str.include?('/')
|
|
79
|
+
type = type_str
|
|
80
|
+
else
|
|
81
|
+
if type
|
|
82
|
+
type = ".#{type}" unless type_str.start_with?(".")
|
|
83
|
+
else
|
|
84
|
+
type = ::File.extname(path)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
type &&= Rack::Mime.mime_type(type, nil)
|
|
88
|
+
type ||= 'application/octet-stream'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
headers[RodaResponseHeaders::CONTENT_TYPE] = type
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
disposition = opts[:disposition]
|
|
95
|
+
filename = opts[:filename]
|
|
96
|
+
if disposition || filename
|
|
97
|
+
disposition ||= 'attachment'
|
|
98
|
+
filename = path if filename.nil?
|
|
99
|
+
res.attachment(filename, disposition)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if lm = opts[:last_modified]
|
|
103
|
+
r.last_modified(lm)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
file = RACK_FILES.new nil
|
|
107
|
+
s, h, b = if Rack.release > '2'
|
|
108
|
+
file.serving(r, path)
|
|
109
|
+
else
|
|
110
|
+
file.path = path
|
|
111
|
+
file.serving(env)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
res.status = opts[:status] || s
|
|
115
|
+
headers.delete(RodaResponseHeaders::CONTENT_LENGTH)
|
|
116
|
+
headers.replace(h.merge!(headers))
|
|
117
|
+
r.halt res.finish_with_body(b)
|
|
118
|
+
rescue Errno::ENOENT
|
|
119
|
+
response.status = 404
|
|
120
|
+
r.halt
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
register_plugin(:send_file, SendFile)
|
|
126
|
+
end
|
|
127
|
+
end
|