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.

Files changed (163) hide show
  1. checksums.yaml +7 -0
  2. data/roda-3.106.0/MIT-LICENSE +21 -0
  3. data/roda-3.106.0/lib/roda/cache.rb +42 -0
  4. data/roda-3.106.0/lib/roda/plugins/Integer_matcher_max.rb +55 -0
  5. data/roda-3.106.0/lib/roda/plugins/_after_hook.rb +11 -0
  6. data/roda-3.106.0/lib/roda/plugins/_base64.rb +34 -0
  7. data/roda-3.106.0/lib/roda/plugins/_before_hook.rb +41 -0
  8. data/roda-3.106.0/lib/roda/plugins/_optimized_matching.rb +227 -0
  9. data/roda-3.106.0/lib/roda/plugins/_symbol_class_matchers.rb +108 -0
  10. data/roda-3.106.0/lib/roda/plugins/_symbol_regexp_matchers.rb +24 -0
  11. data/roda-3.106.0/lib/roda/plugins/additional_render_engines.rb +61 -0
  12. data/roda-3.106.0/lib/roda/plugins/additional_view_directories.rb +66 -0
  13. data/roda-3.106.0/lib/roda/plugins/all_verbs.rb +50 -0
  14. data/roda-3.106.0/lib/roda/plugins/assets.rb +902 -0
  15. data/roda-3.106.0/lib/roda/plugins/assets_preloading.rb +89 -0
  16. data/roda-3.106.0/lib/roda/plugins/assume_ssl.rb +28 -0
  17. data/roda-3.106.0/lib/roda/plugins/autoload_hash_branches.rb +79 -0
  18. data/roda-3.106.0/lib/roda/plugins/autoload_named_routes.rb +65 -0
  19. data/roda-3.106.0/lib/roda/plugins/backtracking_array.rb +88 -0
  20. data/roda-3.106.0/lib/roda/plugins/bearer_token.rb +28 -0
  21. data/roda-3.106.0/lib/roda/plugins/branch_locals.rb +76 -0
  22. data/roda-3.106.0/lib/roda/plugins/break.rb +43 -0
  23. data/roda-3.106.0/lib/roda/plugins/caching.rb +206 -0
  24. data/roda-3.106.0/lib/roda/plugins/capture_erb.rb +94 -0
  25. data/roda-3.106.0/lib/roda/plugins/chunked.rb +333 -0
  26. data/roda-3.106.0/lib/roda/plugins/class_level_routing.rb +111 -0
  27. data/roda-3.106.0/lib/roda/plugins/class_matchers.rb +155 -0
  28. data/roda-3.106.0/lib/roda/plugins/common_logger.rb +82 -0
  29. data/roda-3.106.0/lib/roda/plugins/conditional_sessions.rb +67 -0
  30. data/roda-3.106.0/lib/roda/plugins/content_for.rb +105 -0
  31. data/roda-3.106.0/lib/roda/plugins/content_security_policy.rb +333 -0
  32. data/roda-3.106.0/lib/roda/plugins/cookie_flags.rb +157 -0
  33. data/roda-3.106.0/lib/roda/plugins/cookies.rb +51 -0
  34. data/roda-3.106.0/lib/roda/plugins/csrf.rb +81 -0
  35. data/roda-3.106.0/lib/roda/plugins/custom_block_results.rb +85 -0
  36. data/roda-3.106.0/lib/roda/plugins/custom_matchers.rb +89 -0
  37. data/roda-3.106.0/lib/roda/plugins/default_headers.rb +64 -0
  38. data/roda-3.106.0/lib/roda/plugins/default_status.rb +35 -0
  39. data/roda-3.106.0/lib/roda/plugins/delay_build.rb +18 -0
  40. data/roda-3.106.0/lib/roda/plugins/delegate.rb +77 -0
  41. data/roda-3.106.0/lib/roda/plugins/delete_empty_headers.rb +36 -0
  42. data/roda-3.106.0/lib/roda/plugins/direct_call.rb +38 -0
  43. data/roda-3.106.0/lib/roda/plugins/disallow_file_uploads.rb +38 -0
  44. data/roda-3.106.0/lib/roda/plugins/drop_body.rb +43 -0
  45. data/roda-3.106.0/lib/roda/plugins/each_part.rb +87 -0
  46. data/roda-3.106.0/lib/roda/plugins/early_hints.rb +25 -0
  47. data/roda-3.106.0/lib/roda/plugins/empty_root.rb +49 -0
  48. data/roda-3.106.0/lib/roda/plugins/environments.rb +79 -0
  49. data/roda-3.106.0/lib/roda/plugins/erb_h.rb +43 -0
  50. data/roda-3.106.0/lib/roda/plugins/error_email.rb +152 -0
  51. data/roda-3.106.0/lib/roda/plugins/error_handler.rb +133 -0
  52. data/roda-3.106.0/lib/roda/plugins/error_mail.rb +149 -0
  53. data/roda-3.106.0/lib/roda/plugins/exception_page.rb +445 -0
  54. data/roda-3.106.0/lib/roda/plugins/filter_common_logger.rb +46 -0
  55. data/roda-3.106.0/lib/roda/plugins/flash.rb +119 -0
  56. data/roda-3.106.0/lib/roda/plugins/h.rb +59 -0
  57. data/roda-3.106.0/lib/roda/plugins/halt.rb +108 -0
  58. data/roda-3.106.0/lib/roda/plugins/hash_branch_view_subdir.rb +76 -0
  59. data/roda-3.106.0/lib/roda/plugins/hash_branches.rb +145 -0
  60. data/roda-3.106.0/lib/roda/plugins/hash_matcher.rb +39 -0
  61. data/roda-3.106.0/lib/roda/plugins/hash_paths.rb +128 -0
  62. data/roda-3.106.0/lib/roda/plugins/hash_public.rb +125 -0
  63. data/roda-3.106.0/lib/roda/plugins/hash_public_cache.rb +91 -0
  64. data/roda-3.106.0/lib/roda/plugins/hash_routes.rb +304 -0
  65. data/roda-3.106.0/lib/roda/plugins/head.rb +99 -0
  66. data/roda-3.106.0/lib/roda/plugins/header_matchers.rb +88 -0
  67. data/roda-3.106.0/lib/roda/plugins/heartbeat.rb +41 -0
  68. data/roda-3.106.0/lib/roda/plugins/hmac_paths.rb +413 -0
  69. data/roda-3.106.0/lib/roda/plugins/hooks.rb +92 -0
  70. data/roda-3.106.0/lib/roda/plugins/host_authorization.rb +155 -0
  71. data/roda-3.106.0/lib/roda/plugins/host_routing.rb +194 -0
  72. data/roda-3.106.0/lib/roda/plugins/hsts.rb +35 -0
  73. data/roda-3.106.0/lib/roda/plugins/indifferent_params.rb +126 -0
  74. data/roda-3.106.0/lib/roda/plugins/inject_erb.rb +33 -0
  75. data/roda-3.106.0/lib/roda/plugins/invalid_request_body.rb +107 -0
  76. data/roda-3.106.0/lib/roda/plugins/ip_from_header.rb +34 -0
  77. data/roda-3.106.0/lib/roda/plugins/json.rb +119 -0
  78. data/roda-3.106.0/lib/roda/plugins/json_parser.rb +107 -0
  79. data/roda-3.106.0/lib/roda/plugins/link_to.rb +83 -0
  80. data/roda-3.106.0/lib/roda/plugins/mail_processor.rb +629 -0
  81. data/roda-3.106.0/lib/roda/plugins/mailer.rb +285 -0
  82. data/roda-3.106.0/lib/roda/plugins/map_matcher.rb +48 -0
  83. data/roda-3.106.0/lib/roda/plugins/match_affix.rb +64 -0
  84. data/roda-3.106.0/lib/roda/plugins/match_hook.rb +34 -0
  85. data/roda-3.106.0/lib/roda/plugins/match_hook_args.rb +93 -0
  86. data/roda-3.106.0/lib/roda/plugins/middleware.rb +225 -0
  87. data/roda-3.106.0/lib/roda/plugins/middleware_stack.rb +101 -0
  88. data/roda-3.106.0/lib/roda/plugins/module_include.rb +96 -0
  89. data/roda-3.106.0/lib/roda/plugins/multi_public.rb +95 -0
  90. data/roda-3.106.0/lib/roda/plugins/multi_route.rb +156 -0
  91. data/roda-3.106.0/lib/roda/plugins/multi_run.rb +144 -0
  92. data/roda-3.106.0/lib/roda/plugins/multi_view.rb +83 -0
  93. data/roda-3.106.0/lib/roda/plugins/multibyte_string_matcher.rb +57 -0
  94. data/roda-3.106.0/lib/roda/plugins/named_routes.rb +167 -0
  95. data/roda-3.106.0/lib/roda/plugins/named_templates.rb +102 -0
  96. data/roda-3.106.0/lib/roda/plugins/not_allowed.rb +151 -0
  97. data/roda-3.106.0/lib/roda/plugins/not_found.rb +55 -0
  98. data/roda-3.106.0/lib/roda/plugins/optimized_segment_matchers.rb +53 -0
  99. data/roda-3.106.0/lib/roda/plugins/optimized_string_matchers.rb +50 -0
  100. data/roda-3.106.0/lib/roda/plugins/padrino_render.rb +42 -0
  101. data/roda-3.106.0/lib/roda/plugins/param_matchers.rb +83 -0
  102. data/roda-3.106.0/lib/roda/plugins/params_capturing.rb +118 -0
  103. data/roda-3.106.0/lib/roda/plugins/part.rb +76 -0
  104. data/roda-3.106.0/lib/roda/plugins/partials.rb +74 -0
  105. data/roda-3.106.0/lib/roda/plugins/pass.rb +47 -0
  106. data/roda-3.106.0/lib/roda/plugins/path.rb +255 -0
  107. data/roda-3.106.0/lib/roda/plugins/path_matchers.rb +54 -0
  108. data/roda-3.106.0/lib/roda/plugins/path_rewriter.rb +111 -0
  109. data/roda-3.106.0/lib/roda/plugins/permissions_policy.rb +340 -0
  110. data/roda-3.106.0/lib/roda/plugins/placeholder_string_matchers.rb +48 -0
  111. data/roda-3.106.0/lib/roda/plugins/plain_hash_response_headers.rb +32 -0
  112. data/roda-3.106.0/lib/roda/plugins/precompile_templates.rb +156 -0
  113. data/roda-3.106.0/lib/roda/plugins/public.rb +182 -0
  114. data/roda-3.106.0/lib/roda/plugins/r.rb +35 -0
  115. data/roda-3.106.0/lib/roda/plugins/recheck_precompiled_assets.rb +107 -0
  116. data/roda-3.106.0/lib/roda/plugins/redirect_http_to_https.rb +99 -0
  117. data/roda-3.106.0/lib/roda/plugins/redirect_path.rb +59 -0
  118. data/roda-3.106.0/lib/roda/plugins/relative_path.rb +76 -0
  119. data/roda-3.106.0/lib/roda/plugins/render.rb +998 -0
  120. data/roda-3.106.0/lib/roda/plugins/render_coverage.rb +105 -0
  121. data/roda-3.106.0/lib/roda/plugins/render_each.rb +224 -0
  122. data/roda-3.106.0/lib/roda/plugins/render_locals.rb +102 -0
  123. data/roda-3.106.0/lib/roda/plugins/request_aref.rb +77 -0
  124. data/roda-3.106.0/lib/roda/plugins/request_headers.rb +83 -0
  125. data/roda-3.106.0/lib/roda/plugins/response_attachment.rb +94 -0
  126. data/roda-3.106.0/lib/roda/plugins/response_content_type.rb +79 -0
  127. data/roda-3.106.0/lib/roda/plugins/response_request.rb +36 -0
  128. data/roda-3.106.0/lib/roda/plugins/route_block_args.rb +50 -0
  129. data/roda-3.106.0/lib/roda/plugins/route_csrf.rb +388 -0
  130. data/roda-3.106.0/lib/roda/plugins/run_append_slash.rb +51 -0
  131. data/roda-3.106.0/lib/roda/plugins/run_handler.rb +51 -0
  132. data/roda-3.106.0/lib/roda/plugins/run_require_slash.rb +46 -0
  133. data/roda-3.106.0/lib/roda/plugins/sec_fetch_site_csrf.rb +131 -0
  134. data/roda-3.106.0/lib/roda/plugins/send_file.rb +127 -0
  135. data/roda-3.106.0/lib/roda/plugins/sessions.rb +537 -0
  136. data/roda-3.106.0/lib/roda/plugins/shape_friendly.rb +232 -0
  137. data/roda-3.106.0/lib/roda/plugins/shared_vars.rb +86 -0
  138. data/roda-3.106.0/lib/roda/plugins/sinatra_helpers.rb +444 -0
  139. data/roda-3.106.0/lib/roda/plugins/slash_path_empty.rb +26 -0
  140. data/roda-3.106.0/lib/roda/plugins/static.rb +42 -0
  141. data/roda-3.106.0/lib/roda/plugins/static_routing.rb +89 -0
  142. data/roda-3.106.0/lib/roda/plugins/status_303.rb +34 -0
  143. data/roda-3.106.0/lib/roda/plugins/status_handler.rb +86 -0
  144. data/roda-3.106.0/lib/roda/plugins/streaming.rb +170 -0
  145. data/roda-3.106.0/lib/roda/plugins/strip_path_prefix.rb +33 -0
  146. data/roda-3.106.0/lib/roda/plugins/symbol_matchers.rb +188 -0
  147. data/roda-3.106.0/lib/roda/plugins/symbol_status.rb +32 -0
  148. data/roda-3.106.0/lib/roda/plugins/symbol_views.rb +37 -0
  149. data/roda-3.106.0/lib/roda/plugins/timestamp_public.rb +78 -0
  150. data/roda-3.106.0/lib/roda/plugins/type_routing.rb +217 -0
  151. data/roda-3.106.0/lib/roda/plugins/typecast_params.rb +1185 -0
  152. data/roda-3.106.0/lib/roda/plugins/typecast_params_sized_integers.rb +108 -0
  153. data/roda-3.106.0/lib/roda/plugins/unescape_path.rb +41 -0
  154. data/roda-3.106.0/lib/roda/plugins/view_options.rb +203 -0
  155. data/roda-3.106.0/lib/roda/plugins/view_subdir_leading_slash.rb +49 -0
  156. data/roda-3.106.0/lib/roda/plugins.rb +68 -0
  157. data/roda-3.106.0/lib/roda/request.rb +722 -0
  158. data/roda-3.106.0/lib/roda/response.rb +221 -0
  159. data/roda-3.106.0/lib/roda/session_middleware.rb +184 -0
  160. data/roda-3.106.0/lib/roda/version.rb +18 -0
  161. data/roda-3.106.0/lib/roda.rb +741 -0
  162. data/ultra-max-sys.gemspec +12 -0
  163. metadata +202 -0
@@ -0,0 +1,182 @@
1
+ # frozen-string-literal: true
2
+
3
+ require 'uri'
4
+
5
+ begin
6
+ require 'rack/files'
7
+ rescue LoadError
8
+ require 'rack/file'
9
+ end
10
+
11
+ #
12
+ class Roda
13
+ module RodaPlugins
14
+ # The public plugin adds a +r.public+ routing method to serve static files
15
+ # from a directory.
16
+ #
17
+ # The public plugin recognizes the application's :root option, and defaults to
18
+ # using the +public+ subfolder of the application's +:root+ option. If the application's
19
+ # :root option is not set, it defaults to the +public+ folder in the working
20
+ # directory. Additionally, if a relative path is provided as the +:root+
21
+ # option to the plugin, it will be considered relative to the application's
22
+ # +:root+ option.
23
+ #
24
+ # Examples:
25
+ #
26
+ # # Use public folder as location of files
27
+ # plugin :public
28
+ #
29
+ # # Use /path/to/app/static as location of files
30
+ # opts[:root] = '/path/to/app'
31
+ # plugin :public, root: 'static'
32
+ #
33
+ # # Assuming public is the location of files
34
+ # route do
35
+ # # Make GET /images/foo.png look for public/images/foo.png
36
+ # r.public
37
+ #
38
+ # # Make GET /static/images/foo.png look for public/images/foo.png
39
+ # r.on(:static) do
40
+ # r.public
41
+ # end
42
+ # end
43
+ module Public
44
+ SPLIT = Regexp.union(*[File::SEPARATOR, File::ALT_SEPARATOR].compact)
45
+ RACK_FILES = defined?(Rack::Files) ? Rack::Files : Rack::File
46
+ ENCODING_MAP = {:zstd=>'zstd', :brotli=>'br', :gzip=>'gzip'}.freeze
47
+ ENCODING_EXTENSIONS = {'br'=>'.br', 'gzip'=>'.gz', 'zstd'=>'.zst'}.freeze
48
+
49
+ # :nocov:
50
+ PARSER = defined?(::URI::RFC2396_PARSER) ? ::URI::RFC2396_PARSER : ::URI::DEFAULT_PARSER
51
+ MATCH_METHOD = RUBY_VERSION >= '2.4' ? :match? : :match
52
+ # :nocov:
53
+
54
+ # Use options given to setup a Rack::File instance for serving files. Options:
55
+ # :brotli :: Whether to serve already brotli-compressed files with a .br extension
56
+ # for clients supporting "br" transfer encoding.
57
+ # :default_mime :: The default mime type to use if the mime type is not recognized.
58
+ # :encodings :: An enumerable of pairs to handle accepted encodings. The first
59
+ # element of the pair is the accepted encoding name (e.g. 'gzip'),
60
+ # and the second element of the pair is the file extension (e.g.
61
+ # '.gz'). This allows configuration of the order in which encodings
62
+ # are tried, to prefer brotli to zstd for example, or to support
63
+ # encodings other than zstd, brotli, and gzip. This takes
64
+ # precedence over the :brotli, :gzip, and :zstd options if given.
65
+ # :gzip :: Whether to serve already gzipped files with a .gz extension for clients
66
+ # supporting "gzip" transfer encoding.
67
+ # :headers :: A hash of headers to use for statically served files
68
+ # :root :: Use this option for the root of the public directory (default: "public")
69
+ # :zstd :: Whether to serve already zstd-compressed files with a .zst extension
70
+ # for clients supporting "zstd" transfer encoding.
71
+ def self.configure(app, opts={})
72
+ if opts[:root]
73
+ app.opts[:public_root] = app.expand_path(opts[:root])
74
+ elsif !app.opts[:public_root]
75
+ app.opts[:public_root] = app.expand_path("public")
76
+ end
77
+ app.opts[:public_server] = RACK_FILES.new(app.opts[:public_root], opts[:headers]||{}, opts[:default_mime] || 'text/plain')
78
+
79
+ unless encodings = opts[:encodings]
80
+ if ENCODING_MAP.any?{|k,| opts.has_key?(k)}
81
+ encodings = ENCODING_MAP.map{|k, v| [v, ENCODING_EXTENSIONS[v]] if opts[k]}.compact
82
+ end
83
+ end
84
+ encodings = (encodings || app.opts[:public_encodings] || EMPTY_ARRAY).map(&:dup).freeze
85
+ encodings.each do |a|
86
+ a << /\b#{a[0]}\b/
87
+ end
88
+ encodings.each(&:freeze)
89
+ app.opts[:public_encodings] = encodings
90
+ end
91
+
92
+ module RequestMethods
93
+ # Serve files from the public directory if the file exists and this is a GET request.
94
+ def public
95
+ public_serve_with(roda_class.opts[:public_server])
96
+ end
97
+
98
+ private
99
+
100
+ # Return an array of segments for the given path, handling ..
101
+ # and . components
102
+ def public_path_segments(path)
103
+ segments = []
104
+
105
+ path.split(SPLIT).each do |seg|
106
+ next if seg.empty? || seg == '.'
107
+ seg == '..' ? segments.pop : segments << seg
108
+ end
109
+
110
+ segments
111
+ end
112
+
113
+ # Return whether the given path is a readable regular file.
114
+ def public_file_readable?(path)
115
+ ::File.file?(path) && ::File.readable?(path)
116
+ rescue SystemCallError
117
+ # :nocov:
118
+ false
119
+ # :nocov:
120
+ end
121
+
122
+ def public_serve_with(server)
123
+ return unless is_get?
124
+ path = PARSER.unescape(real_remaining_path)
125
+ return if path.include?("\0")
126
+
127
+ roda_opts = roda_class.opts
128
+ path = ::File.join(server.root, *public_path_segments(path))
129
+
130
+ if accept_encoding = env['HTTP_ACCEPT_ENCODING']
131
+ roda_opts[:public_encodings].each do |enc, ext, regexp|
132
+ if regexp.send(MATCH_METHOD, accept_encoding)
133
+ public_serve_compressed(server, path, ext, enc)
134
+ end
135
+ end
136
+ end
137
+
138
+ if public_file_readable?(path)
139
+ s, h, b = public_serve(server, path)
140
+ headers = response.headers
141
+ headers.replace(h)
142
+ halt [s, headers, b]
143
+ end
144
+ end
145
+
146
+ # Serve the compressed file if it exists. This should only
147
+ # be called if the client will accept the related encoding.
148
+ def public_serve_compressed(server, path, suffix, encoding)
149
+ compressed_path = path + suffix
150
+
151
+ if public_file_readable?(compressed_path)
152
+ s, h, b = public_serve(server, compressed_path)
153
+ headers = response.headers
154
+ headers.replace(h)
155
+
156
+ unless s == 304
157
+ headers[RodaResponseHeaders::CONTENT_TYPE] = ::Rack::Mime.mime_type(::File.extname(path), 'text/plain')
158
+ headers[RodaResponseHeaders::CONTENT_ENCODING] = encoding
159
+ end
160
+
161
+ halt [s, headers, b]
162
+ end
163
+ end
164
+
165
+ if ::Rack.release > '2'
166
+ # Serve the given path using the given Rack::Files server.
167
+ def public_serve(server, path)
168
+ server.serving(self, path)
169
+ end
170
+ else
171
+ def public_serve(server, path)
172
+ server = server.dup
173
+ server.path = path
174
+ server.serving(env)
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ register_plugin(:public, Public)
181
+ end
182
+ end
@@ -0,0 +1,35 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The r plugin adds an +r+ instance method that will return the request.
7
+ # This allows you to use common Roda idioms such as +r.halt+ and
8
+ # +r.redirect+ even when +r+ isn't a local variable in scope. Example:
9
+ #
10
+ # plugin :r
11
+ #
12
+ # def foo
13
+ # r.redirect "/bar"
14
+ # end
15
+ #
16
+ # route do |r|
17
+ # r.get "foo" do
18
+ # foo
19
+ # end
20
+ # r.get "bar" do
21
+ # "bar"
22
+ # end
23
+ # end
24
+ module R
25
+ module InstanceMethods
26
+ # The request object.
27
+ def r
28
+ @_request
29
+ end
30
+ end
31
+ end
32
+
33
+ register_plugin(:r, R)
34
+ end
35
+ end
@@ -0,0 +1,107 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The recheck_precompiled_assets plugin enables checking for the precompiled asset metadata file.
7
+ # You need to have already loaded the assets plugin with the +:precompiled+ option and the file
8
+ # specified by the +:precompiled+ option must already exist in order to use the
9
+ # recheck_precompiled_assets plugin.
10
+ #
11
+ # Any time you want to check whether the precompiled asset metadata file has changed and should be
12
+ # reloaded, you can call the +recheck_precompiled_assets+ class method. This method will check
13
+ # whether the file has changed, and reload it if it has. If you want to check for modifications on
14
+ # every request, you can use +self.class.recheck_precompiled_assets+ inside your route block.
15
+ module RecheckPrecompiledAssets
16
+ # Thread safe wrapper for the compiled asset metadata hash. Does not wrap all
17
+ # hash methods, only a few that are used.
18
+ class CompiledAssetsHash
19
+ include Enumerable
20
+
21
+ def initialize
22
+ @hash = {}
23
+ @mutex = Mutex.new
24
+ end
25
+
26
+ def [](key)
27
+ @mutex.synchronize{@hash[key]}
28
+ end
29
+
30
+ def []=(key, value)
31
+ @mutex.synchronize{@hash[key] = value}
32
+ end
33
+
34
+ def replace(hash)
35
+ hash = hash.instance_variable_get(:@hash) if (CompiledAssetsHash === hash)
36
+ @mutex.synchronize{@hash.replace(hash)}
37
+ self
38
+ end
39
+
40
+ def each(&block)
41
+ @mutex.synchronize{@hash.dup}.each(&block)
42
+ self
43
+ end
44
+
45
+ def to_json(*args)
46
+ @mutex.synchronize{@hash.dup}.to_json(*args)
47
+ end
48
+ end
49
+
50
+ def self.load_dependencies(app)
51
+ unless app.respond_to?(:assets_opts) && app.assets_opts[:precompiled]
52
+ raise RodaError, "must load assets plugin with precompiled option before loading recheck_precompiled_assets plugin"
53
+ end
54
+ end
55
+
56
+ def self.configure(app)
57
+ precompiled_file = app.assets_opts[:precompiled]
58
+ prev_mtime = ::File.mtime(precompiled_file)
59
+ app.instance_exec do
60
+ opts[:assets] = opts[:assets].merge(:compiled=>_compiled_assets_initial_hash.replace(assets_opts[:compiled])).freeze
61
+
62
+ define_singleton_method(:recheck_precompiled_assets) do
63
+ new_mtime = ::File.mtime(precompiled_file)
64
+ if new_mtime != prev_mtime
65
+ prev_mtime = new_mtime
66
+ assets_opts[:compiled].replace(_precompiled_asset_metadata(precompiled_file))
67
+
68
+ # Unset the cached asset matchers, so new ones will be generated.
69
+ # This is needed in case the new precompiled metadata uses
70
+ # different files.
71
+ app::RodaRequest.instance_variable_set(:@assets_matchers, nil)
72
+ end
73
+ end
74
+ singleton_class.send(:alias_method, :recheck_precompiled_assets, :recheck_precompiled_assets)
75
+ end
76
+ end
77
+
78
+ module ClassMethods
79
+ private
80
+
81
+ # Wrap the precompiled asset metadata in a thread-safe hash.
82
+ def _precompiled_asset_metadata(file)
83
+ CompiledAssetsHash.new.replace(super)
84
+ end
85
+
86
+ # Use a thread-safe wrapper of a hash for the :compiled assets option, since
87
+ # the recheck_precompiled_asset_metadata can modify it at runtime.
88
+ def _compiled_assets_initial_hash
89
+ CompiledAssetsHash.new
90
+ end
91
+ end
92
+
93
+ module RequestClassMethods
94
+ private
95
+
96
+ # Use a regexp that matches any digest. When the precompiled asset metadata
97
+ # file is updated, this allows requests for a previous precompiled asset to
98
+ # still work.
99
+ def _asset_regexp(type, key, _)
100
+ /#{Regexp.escape(key.sub(/\A#{type}/, ''))}\.[0-9a-fA-F]+\.#{type}/
101
+ end
102
+ end
103
+ end
104
+
105
+ register_plugin(:recheck_precompiled_assets, RecheckPrecompiledAssets)
106
+ end
107
+ end
@@ -0,0 +1,99 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The redirect_http_to_https plugin exposes a +redirect_http_to_https+
7
+ # request method that redirects HTTP requests to HTTPS, helping to ensure
8
+ # that future requests by the same browser will be submitted securely.
9
+ #
10
+ # You should use this plugin if you have an application that can receive
11
+ # requests using both HTTP and HTTPS, and you want to make sure that all
12
+ # or a subset of routes are only handled for HTTPS requests.
13
+ #
14
+ # The reason this exposes a request method is so that you can choose where
15
+ # in your routing tree to do the redirection:
16
+ #
17
+ # route do |r|
18
+ # # routes available via both HTTP and HTTPS
19
+ # r.redirect_http_to_https
20
+ # # routes available only via HTTPS
21
+ # end
22
+ #
23
+ # If you want to redirect to HTTPS for all routes in the routing tree, you
24
+ # can have this as the very first method call in the routing tree. Note that
25
+ # in Roda it is possible to handle routing before the normal routing tree
26
+ # using before hooks. The static_routing and heartbeat plugins use this
27
+ # feature. If you would like to handle routes before the normal routing tree,
28
+ # you can setup a before hook:
29
+ #
30
+ # plugin :hooks
31
+ #
32
+ # before do
33
+ # request.redirect_http_to_https
34
+ # end
35
+ module RedirectHttpToHttps
36
+ status_map = Hash.new(307)
37
+ status_map['GET'] = status_map['HEAD'] = 301
38
+ status_map.freeze
39
+ DEFAULTS = {:status_map => status_map}.freeze
40
+ private_constant :DEFAULTS
41
+
42
+ # Configures redirection from HTTP to HTTPS. Available options:
43
+ #
44
+ # :body :: The body used in the redirect. If not set, uses an empty body.
45
+ # :headers :: Any additional headers used in the redirect response. By default,
46
+ # no additional headers are set, the only header used is the Location header.
47
+ # :host :: The host to redirect to. If not set, redirects to the same host as the HTTP
48
+ # requested to. It is highly recommended that you set this if requests with
49
+ # arbitrary Host headers can be submitted to the application.
50
+ # :port :: The port to use in the redirect. By default, will not set an explicit port,
51
+ # so that it will implicitly use the HTTPS default port of 443.
52
+ # :status_map :: A hash mapping request methods to response status codes. By default,
53
+ # uses a hash that redirects GET and HEAD requests with a 301 status,
54
+ # and other request methods with a 307 status.
55
+ def self.configure(app, opts=OPTS)
56
+ previous = app.opts[:redirect_http_to_https] || DEFAULTS
57
+ opts = app.opts[:redirect_http_to_https] = previous.merge(opts)
58
+ opts[:port_string] = opts[:port] ? ":#{opts[:port]}".freeze : "".freeze
59
+ opts[:prefix] = opts[:host] ? "https://#{opts[:host]}#{opts[:port_string]}".freeze : nil
60
+ opts.freeze
61
+ end
62
+
63
+ module RequestMethods
64
+ # Redirect HTTP requests to HTTPS. While this doesn't secure the
65
+ # current request, it makes it more likely that the browser will submit
66
+ # future requests securely via HTTPS.
67
+ def redirect_http_to_https
68
+ return if ssl?
69
+
70
+ opts = roda_class.opts[:redirect_http_to_https]
71
+
72
+ res = response
73
+
74
+ if body = opts[:body]
75
+ res.write(body)
76
+ end
77
+
78
+ if headers = opts[:headers]
79
+ res.headers.merge!(headers)
80
+ end
81
+
82
+ path = if prefix = opts[:prefix]
83
+ prefix + fullpath
84
+ else
85
+ "https://#{host}#{opts[:port_string]}#{fullpath}"
86
+ end
87
+
88
+ unless status = opts[:status_map][@env['REQUEST_METHOD']]
89
+ raise RodaError, "redirect_http_to_https :status_map provided does not support #{@env['REQUEST_METHOD']}"
90
+ end
91
+
92
+ redirect(path, status)
93
+ end
94
+ end
95
+ end
96
+
97
+ register_plugin(:redirect_http_to_https, RedirectHttpToHttps)
98
+ end
99
+ end
@@ -0,0 +1,59 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The redirect_path plugin builds on top of the path plugin,
7
+ # and allows the +r.redirect+ method to be passed a non-string
8
+ # object that will be passed to +path+, and redirect to the
9
+ # result of +path+.
10
+ #
11
+ # In the second argument, you can provide a suffix to the
12
+ # generated path. However, in this case you cannot provide a
13
+ # non-default redirect status in the same call).
14
+ #
15
+ # Example:
16
+ #
17
+ # Foo = Struct.new(:id)
18
+ # foo = Foo.new(1)
19
+ #
20
+ # plugin :redirect_path
21
+ # path Foo do |foo|
22
+ # "/foo/#{foo.id}"
23
+ # end
24
+ #
25
+ # route do |r|
26
+ # r.get "example" do
27
+ # # redirects to /foo/1
28
+ # r.redirect(foo)
29
+ # end
30
+ #
31
+ # r.get "suffix-example" do
32
+ # # redirects to /foo/1/status
33
+ # r.redirect(foo, "/status")
34
+ # end
35
+ # end
36
+ module RedirectPath
37
+ def self.load_dependencies(app)
38
+ app.plugin :path
39
+ end
40
+
41
+ module RequestMethods
42
+ def redirect(path=default_redirect_path, status=default_redirect_status)
43
+ if String === path
44
+ super
45
+ else
46
+ path = scope.path(path)
47
+ if status.is_a?(String)
48
+ super(path + status)
49
+ else
50
+ super
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ register_plugin(:redirect_path, RedirectPath)
58
+ end
59
+ end
@@ -0,0 +1,76 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The relative_path plugin adds a relative_path method that accepts
7
+ # an absolute path and returns a path relative to the current request
8
+ # by adding an appropriate prefix:
9
+ #
10
+ # plugin :relative_path
11
+ # route do |r|
12
+ # relative_path("/foo")
13
+ # end
14
+ #
15
+ # # GET /
16
+ # "./foo"
17
+ #
18
+ # # GET /bar
19
+ # "./foo"
20
+ #
21
+ # # GET /bar/
22
+ # "../foo"
23
+ #
24
+ # # GET /bar/baz/quux
25
+ # "../../foo"
26
+ #
27
+ # It also offers a relative_prefix method that returns a string that can
28
+ # be prepended to an absolute path. This can be more efficient if you
29
+ # need to convert multiple paths.
30
+ #
31
+ # This plugin is mostly designed for applications using Roda as a static
32
+ # site generator, where the generated site can be hosted at any subpath.
33
+ module RelativePath
34
+ SCOPE_INSTANCE_VARIABLES = [:@_relative_prefix].freeze
35
+
36
+ module InstanceMethods
37
+ # Return a relative path for the absolute path based on the current path
38
+ # of the request by adding the appropriate prefix.
39
+ def relative_path(absolute_path)
40
+ relative_prefix + absolute_path
41
+ end
42
+
43
+ # Return a relative prefix to append to an absolute path to a relative path
44
+ # based on the current path of the request.
45
+ def relative_prefix
46
+ return @_relative_prefix if @_relative_prefix
47
+ env = @_request.env
48
+ script_name = env["SCRIPT_NAME"]
49
+ path_info = env["PATH_INFO"]
50
+
51
+ # Check path begins with slash. All valid paths should, but in case this
52
+ # request is bad, just skip using a relative prefix.
53
+ case script_name.getbyte(0)
54
+ when nil # SCRIPT_NAME empty
55
+ unless path_info.getbyte(0) == 47 # PATH_INFO starts with /
56
+ return(@_relative_prefix = '')
57
+ end
58
+ when 47 # SCRIPT_NAME starts with /
59
+ # nothing
60
+ else
61
+ return(@_relative_prefix = '')
62
+ end
63
+
64
+ slash_count = script_name.count('/') + path_info.count('/')
65
+ @_relative_prefix = if slash_count > 1
66
+ ("../" * (slash_count - 2)) << ".."
67
+ else
68
+ "."
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ register_plugin(:relative_path, RelativePath)
75
+ end
76
+ end