roda 3.106.0 → 3.108.0
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.
- checksums.yaml +4 -4
- data/lib/roda/plugins/_base64.rb +2 -2
- data/lib/roda/plugins/_optimized_matching.rb +1 -0
- data/lib/roda/plugins/all_verbs.rb +2 -2
- data/lib/roda/plugins/assets.rb +50 -6
- data/lib/roda/plugins/bearer_token.rb +2 -2
- data/lib/roda/plugins/break.rb +9 -1
- data/lib/roda/plugins/caching.rb +12 -12
- data/lib/roda/plugins/common_logger.rb +4 -4
- data/lib/roda/plugins/cookie_flags.rb +2 -2
- data/lib/roda/plugins/csrf.rb +3 -0
- data/lib/roda/plugins/delay_build.rb +2 -0
- data/lib/roda/plugins/each_part.rb +4 -4
- data/lib/roda/plugins/error_email.rb +2 -2
- data/lib/roda/plugins/exception_page.rb +2 -2
- data/lib/roda/plugins/h.rb +4 -4
- data/lib/roda/plugins/hash_branches.rb +8 -4
- data/lib/roda/plugins/hash_paths.rb +4 -2
- data/lib/roda/plugins/hash_public.rb +2 -2
- data/lib/roda/plugins/hmac_paths.rb +27 -29
- data/lib/roda/plugins/host_routing.rb +29 -4
- data/lib/roda/plugins/invalid_request_body.rb +2 -0
- data/lib/roda/plugins/json_parser.rb +20 -2
- data/lib/roda/plugins/mail_processor.rb +2 -2
- data/lib/roda/plugins/mailer.rb +4 -4
- data/lib/roda/plugins/middleware.rb +1 -0
- data/lib/roda/plugins/optimized_segment_matchers.rb +13 -6
- data/lib/roda/plugins/optimized_string_matchers.rb +6 -3
- data/lib/roda/plugins/params_capturing.rb +16 -7
- data/lib/roda/plugins/params_capturing_restore.rb +72 -0
- data/lib/roda/plugins/part.rb +4 -4
- data/lib/roda/plugins/pass.rb +4 -1
- data/lib/roda/plugins/path.rb +6 -6
- data/lib/roda/plugins/path_matchers.rb +5 -1
- data/lib/roda/plugins/public.rb +4 -4
- data/lib/roda/plugins/render.rb +24 -12
- data/lib/roda/plugins/render_coverage.rb +7 -6
- data/lib/roda/plugins/render_each.rb +2 -2
- data/lib/roda/plugins/route_block_args.rb +6 -0
- data/lib/roda/plugins/route_csrf.rb +35 -3
- data/lib/roda/plugins/run_append_slash.rb +8 -4
- data/lib/roda/plugins/sec_fetch_site_csrf.rb +5 -2
- data/lib/roda/plugins/sessions.rb +9 -4
- data/lib/roda/plugins/shape_friendly.rb +4 -4
- data/lib/roda/plugins/static.rb +14 -0
- data/lib/roda/plugins/type_routing.rb +1 -1
- data/lib/roda/plugins/url_escape.rb +39 -0
- data/lib/roda/plugins/view_options.rb +3 -5
- data/lib/roda/plugins.rb +4 -4
- data/lib/roda/request.rb +27 -10
- data/lib/roda/version.rb +1 -1
- data/lib/roda.rb +17 -12
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 88f17808e272159aaa6d5f1239eeb3453935aa188c0933b753e5a66046212e03
|
|
4
|
+
data.tar.gz: 952920ff3e1dafeefea80acefcbd3fb5e03f0033c2ca909757c697e2acd7c955
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fdd21d3152a257f21d1cfb33562334b71de82e1f017899dae0d5e9974f9b1028824c017f82d54405d5f88bed4d53607f6c238bb21c1907492da38b3b755e1a73
|
|
7
|
+
data.tar.gz: 61ed1ac97df5919e486a82abb62ad47b45603ec3c46d230ce6aa6f7ac697cd52b45af167a597ad691ec6de5267886e6b420efc0d3117a3604ba45f613703e80d
|
data/lib/roda/plugins/_base64.rb
CHANGED
|
@@ -6,7 +6,7 @@ class Roda
|
|
|
6
6
|
# The all_verbs plugin adds methods for http verbs other than
|
|
7
7
|
# get and post. The following verbs are added, assuming
|
|
8
8
|
# rack handles them: delete, head, options, link, patch, put,
|
|
9
|
-
# trace, unlink.
|
|
9
|
+
# query, trace, unlink.
|
|
10
10
|
#
|
|
11
11
|
# These methods operate just like Roda's default get and post
|
|
12
12
|
# methods, so using them without any arguments just checks for
|
|
@@ -33,7 +33,7 @@ class Roda
|
|
|
33
33
|
# isn't documentation for the individual methods created.
|
|
34
34
|
module AllVerbs
|
|
35
35
|
module RequestMethods
|
|
36
|
-
%w'delete head options link patch put trace unlink'.each do |verb|
|
|
36
|
+
%w'delete head options link patch put query trace unlink'.each do |verb|
|
|
37
37
|
if ::Rack::Request.method_defined?("#{verb}?")
|
|
38
38
|
class_eval(<<-END, __FILE__, __LINE__+1)
|
|
39
39
|
def #{verb}(*args, &block)
|
data/lib/roda/plugins/assets.rb
CHANGED
|
@@ -159,6 +159,35 @@ class Roda
|
|
|
159
159
|
# plugin :assets,
|
|
160
160
|
# css_opts: {style: :compressed}
|
|
161
161
|
#
|
|
162
|
+
# In Roda 4, automatic compression of assets will not be attempted. You will
|
|
163
|
+
# need to specify the compressor to use using a Proc or Method. Here are values
|
|
164
|
+
# that you can use.
|
|
165
|
+
#
|
|
166
|
+
# ==== yui
|
|
167
|
+
#
|
|
168
|
+
# require 'yuicompressor'
|
|
169
|
+
# plugin :assets,
|
|
170
|
+
# css_compressor: lambda{|v| ::YUICompressor.compress_css(v, munge: true) },
|
|
171
|
+
# js_compressor: lambda{|v| ::YUICompressor.compress_js(v, munge: true) }
|
|
172
|
+
#
|
|
173
|
+
# ==== closure-compiler
|
|
174
|
+
#
|
|
175
|
+
# require 'closure-compiler'
|
|
176
|
+
# plugin :assets, js_compressor: ::Closure::Compiler.new.method(:compile)
|
|
177
|
+
#
|
|
178
|
+
# ==== uglifier
|
|
179
|
+
#
|
|
180
|
+
# require 'uglifier'
|
|
181
|
+
# plugin :assets, js_compressor: Uglifier.method(:compile)
|
|
182
|
+
#
|
|
183
|
+
# ==== minjs
|
|
184
|
+
#
|
|
185
|
+
# require 'minjs'
|
|
186
|
+
# plugin :assets,
|
|
187
|
+
# js_compressor: proc { |content|
|
|
188
|
+
# Minjs::Compressor::Compressor.new(debug: false).compress(content).to_js
|
|
189
|
+
# }
|
|
190
|
+
#
|
|
162
191
|
# === Source Maps (CSS)
|
|
163
192
|
#
|
|
164
193
|
# The assets plugin does not have direct support for source maps, so it is
|
|
@@ -274,7 +303,7 @@ class Roda
|
|
|
274
303
|
# :compiled_path:: Path inside public folder in which compiled files are stored (default: :prefix)
|
|
275
304
|
# :concat_only :: Whether to just concatenate instead of concatenating
|
|
276
305
|
# and compressing files (default: false)
|
|
277
|
-
# :css_compressor :: Compressor to use for compressing CSS, either :yui, :none, or nil (the default, which will try
|
|
306
|
+
# :css_compressor :: Compressor to use for compressing CSS, either a Proc, Method, :yui, :none, or nil (the default, which will try
|
|
278
307
|
# :yui if available, but not fail if it is not available)
|
|
279
308
|
# :css_dir :: Directory name containing your css source, inside :path (default: 'css')
|
|
280
309
|
# :css_headers :: A hash of additional headers for your rendered css files
|
|
@@ -288,7 +317,7 @@ class Roda
|
|
|
288
317
|
# related group are contained in a subdirectory with the same name (default: true)
|
|
289
318
|
# :gzip :: Store gzipped compiled assets files, and serve those to clients who accept gzip encoding.
|
|
290
319
|
# :headers :: A hash of additional headers for both js and css rendered files
|
|
291
|
-
# :js_compressor :: Compressor to use for compressing javascript, either :yui, :closure, :uglifier, :minjs,
|
|
320
|
+
# :js_compressor :: Compressor to use for compressing javascript, either a Proc, Method, :yui, :closure, :uglifier, :minjs,
|
|
292
321
|
# :none, or nil (the default, which will try :yui, :closure, :uglifier, then :minjs, but
|
|
293
322
|
# not fail if any of them is not available)
|
|
294
323
|
# :js_dir :: Directory name containing your javascript source, inside :path (default: 'js')
|
|
@@ -454,6 +483,17 @@ class Roda
|
|
|
454
483
|
opts[:js_suffix] = (opts[:add_suffix] ? '.js' : '').freeze
|
|
455
484
|
opts[:css_suffix] = (opts[:add_suffix] ? '.css' : '').freeze
|
|
456
485
|
|
|
486
|
+
unless opts[:concat_only]
|
|
487
|
+
[:css_compressor, :js_compressor].each do |s|
|
|
488
|
+
case v = opts[s]
|
|
489
|
+
when nil, :none, Proc, Method
|
|
490
|
+
nil
|
|
491
|
+
else
|
|
492
|
+
RodaPlugins.warn "Support for the assets plugin #{s}: #{v.inspect} option will be removed in Roda 4. See the assets plugin documentation for how to use an appropriate proc or method."
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
|
|
457
497
|
opts.freeze
|
|
458
498
|
end
|
|
459
499
|
|
|
@@ -535,6 +575,7 @@ class Roda
|
|
|
535
575
|
app.read_asset_file(file, type)
|
|
536
576
|
end.join("\n")
|
|
537
577
|
|
|
578
|
+
# RODA4: Remove :concat_only option
|
|
538
579
|
unless o[:concat_only]
|
|
539
580
|
content = compress_asset(content, type)
|
|
540
581
|
end
|
|
@@ -564,6 +605,8 @@ class Roda
|
|
|
564
605
|
return content
|
|
565
606
|
when nil
|
|
566
607
|
# default, try different compressors
|
|
608
|
+
when Proc, Method
|
|
609
|
+
return compressor.call(content)
|
|
567
610
|
else
|
|
568
611
|
# Allow calling private compress methods
|
|
569
612
|
return send("compress_#{type}_#{compressor}", content)
|
|
@@ -579,6 +622,7 @@ class Roda
|
|
|
579
622
|
begin
|
|
580
623
|
# Allow calling private compress methods
|
|
581
624
|
if c = send("compress_#{type}_#{comp}", content)
|
|
625
|
+
RodaPlugins.warn "Support for automatic compression of assets by trying common asset compressor libraries will be removed in Roda 4. The #{comp} #{type.to_s.upcase} compressor is currently used. See the assets plugin documentation for how to use an appropriate value for the assets plugin :#{type}_compressor option."
|
|
582
626
|
return c
|
|
583
627
|
end
|
|
584
628
|
rescue LoadError, CompressorNotFound
|
|
@@ -615,9 +659,9 @@ class Roda
|
|
|
615
659
|
begin
|
|
616
660
|
require 'uglifier'
|
|
617
661
|
rescue => e
|
|
618
|
-
# :
|
|
662
|
+
# simplecov:disable
|
|
619
663
|
raise CompressorNotFound, "#{e.class}: #{e.message}", e.backtrace
|
|
620
|
-
# :
|
|
664
|
+
# simplecov:enable
|
|
621
665
|
end
|
|
622
666
|
|
|
623
667
|
Uglifier.compile(content)
|
|
@@ -645,11 +689,11 @@ class Roda
|
|
|
645
689
|
digest = begin
|
|
646
690
|
require 'openssl'
|
|
647
691
|
::OpenSSL::Digest
|
|
648
|
-
# :
|
|
692
|
+
# simplecov:disable
|
|
649
693
|
rescue LoadError
|
|
650
694
|
require 'digest/sha2'
|
|
651
695
|
::Digest
|
|
652
|
-
# :
|
|
696
|
+
# simplecov:enable
|
|
653
697
|
end
|
|
654
698
|
digest.const_get(algo.to_s.upcase).hexdigest(content)
|
|
655
699
|
end
|
|
@@ -8,9 +8,9 @@ class Roda
|
|
|
8
8
|
# in the authorization header will be recognized as long as they start
|
|
9
9
|
# with the case insensitive string "bearer ".
|
|
10
10
|
module BearerToken
|
|
11
|
-
# :
|
|
11
|
+
# simplecov:disable
|
|
12
12
|
METHOD = RUBY_VERSION >= "2.4" ? :match? : :match
|
|
13
|
-
# :
|
|
13
|
+
# simplecov:enable
|
|
14
14
|
|
|
15
15
|
module RequestMethods
|
|
16
16
|
# Return the bearer token for the request if there is one in the
|
data/lib/roda/plugins/break.rb
CHANGED
|
@@ -22,12 +22,20 @@ class Roda
|
|
|
22
22
|
# end
|
|
23
23
|
#
|
|
24
24
|
# This provides the same basic feature as the pass plugin, but
|
|
25
|
-
# uses Ruby's standard control flow
|
|
25
|
+
# uses Ruby's standard control flow primitive instead of a
|
|
26
26
|
# separate method.
|
|
27
27
|
module Break
|
|
28
28
|
module RequestMethods
|
|
29
29
|
private
|
|
30
30
|
|
|
31
|
+
# Handle passing inside the match block.
|
|
32
|
+
def always
|
|
33
|
+
rp = @remaining_path
|
|
34
|
+
super
|
|
35
|
+
ensure
|
|
36
|
+
@remaining_path = rp
|
|
37
|
+
end
|
|
38
|
+
|
|
31
39
|
# Handle break inside match blocks, restoring remaining path.
|
|
32
40
|
def if_match(_)
|
|
33
41
|
rp = @remaining_path
|
data/lib/roda/plugins/caching.rb
CHANGED
|
@@ -75,28 +75,27 @@ class Roda
|
|
|
75
75
|
# Set the last modified time of the resource using the Last-Modified header.
|
|
76
76
|
# The +time+ argument should be a Time instance.
|
|
77
77
|
#
|
|
78
|
-
# If the current request includes an If-Modified-Since header that is
|
|
79
|
-
# equal or later than the time specified, immediately returns a response
|
|
80
|
-
# with a 304 status.
|
|
81
|
-
#
|
|
82
78
|
# If the current request includes an If-Unmodified-Since header that is
|
|
83
79
|
# before than the time specified, immediately returns a response
|
|
84
80
|
# with a 412 status.
|
|
81
|
+
#
|
|
82
|
+
# If the current request does not include an If-None-Match header and
|
|
83
|
+
# includes an If-Modified-Since header that is equal or later than the
|
|
84
|
+
# time specified, immediately returns a response with a 304 status.
|
|
85
85
|
def last_modified(time)
|
|
86
86
|
return unless time
|
|
87
87
|
res = response
|
|
88
88
|
e = env
|
|
89
89
|
res[RodaResponseHeaders::LAST_MODIFIED] = time.httpdate
|
|
90
|
-
return if e['HTTP_IF_NONE_MATCH']
|
|
91
90
|
status = res.status
|
|
92
91
|
|
|
93
|
-
if (!status || status
|
|
94
|
-
res.status =
|
|
92
|
+
if (!status || (status >= 200 && status < 300) || status == 412) && (ius = time_from_header(e['HTTP_IF_UNMODIFIED_SINCE'])) && ius < time.to_i
|
|
93
|
+
res.status = 412
|
|
95
94
|
halt
|
|
96
95
|
end
|
|
97
96
|
|
|
98
|
-
if
|
|
99
|
-
res.status =
|
|
97
|
+
if !e['HTTP_IF_NONE_MATCH'] && (!status || status == 200) && (ims = time_from_header(e['HTTP_IF_MODIFIED_SINCE'])) && ims >= time.to_i
|
|
98
|
+
res.status = 304
|
|
100
99
|
halt
|
|
101
100
|
end
|
|
102
101
|
end
|
|
@@ -113,8 +112,9 @@ class Roda
|
|
|
113
112
|
# matching etag, immediately returns a response with a 304 or 412 status,
|
|
114
113
|
# depending on the request method.
|
|
115
114
|
#
|
|
116
|
-
# When the current request includes an If-Match header with
|
|
117
|
-
#
|
|
115
|
+
# When the current request includes an If-Match header with an etag that
|
|
116
|
+
# doesn't match, or where the :weak option was used, immediately returns a
|
|
117
|
+
# response with a 412 status.
|
|
118
118
|
def etag(value, opts=OPTS)
|
|
119
119
|
# Before touching this code, please double check RFC 2616 14.24 and 14.26.
|
|
120
120
|
weak = opts[:weak]
|
|
@@ -132,7 +132,7 @@ class Roda
|
|
|
132
132
|
end
|
|
133
133
|
|
|
134
134
|
if ifm = e['HTTP_IF_MATCH']
|
|
135
|
-
|
|
135
|
+
if weak || !etag_matches?(ifm, etag, new_resource)
|
|
136
136
|
res.status = 412
|
|
137
137
|
halt
|
|
138
138
|
end
|
|
@@ -36,11 +36,11 @@ class Roda
|
|
|
36
36
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
37
37
|
end
|
|
38
38
|
else
|
|
39
|
-
# :
|
|
39
|
+
# simplecov:disable
|
|
40
40
|
def self.start_timer # :nodoc:
|
|
41
41
|
Time.now
|
|
42
42
|
end
|
|
43
|
-
# :
|
|
43
|
+
# simplecov:enable
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
module InstanceMethods
|
|
@@ -61,10 +61,10 @@ class Roda
|
|
|
61
61
|
line = "#{env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-"} - #{env["REMOTE_USER"] || "-"} [#{Time.now.strftime("%d/%b/%Y:%H:%M:%S %z")}] \"#{env["REQUEST_METHOD"]} #{env["SCRIPT_NAME"]}#{env["PATH_INFO"]}#{"?#{env["QUERY_STRING"]}" if ((qs = env["QUERY_STRING"]) && !qs.empty?)} #{@_request.http_version}\" #{status} #{((length = headers[RodaResponseHeaders::CONTENT_LENGTH]) && (length unless length == '0')) || '-'} #{elapsed_time} "
|
|
62
62
|
if MUTATE_LINE
|
|
63
63
|
line.gsub!(/[^[:print:]]/){|c| sprintf("\\x%x", c.ord)}
|
|
64
|
-
# :
|
|
64
|
+
# simplecov:disable
|
|
65
65
|
else
|
|
66
66
|
line = line.gsub(/[^[:print:]]/){|c| sprintf("\\x%x", c.ord)}
|
|
67
|
-
# :
|
|
67
|
+
# simplecov:enable
|
|
68
68
|
end
|
|
69
69
|
line[-1] = "\n"
|
|
70
70
|
opts[:common_logger_meth].call(line)
|
|
@@ -48,9 +48,9 @@ class Roda
|
|
|
48
48
|
# Note that this plugin only affects cookies set by the application, and does not
|
|
49
49
|
# affect cookies set by middleware the application is using.
|
|
50
50
|
module CookieFlags
|
|
51
|
-
# :
|
|
51
|
+
# simplecov:disable
|
|
52
52
|
MATCH_METH = RUBY_VERSION >= '2.4' ? :match? : :match
|
|
53
|
-
# :
|
|
53
|
+
# simplecov:enable
|
|
54
54
|
private_constant :MATCH_METH
|
|
55
55
|
|
|
56
56
|
DEFAULTS = {:secure=>true, :httponly=>true, :same_site=>'strict', :action=>:modify}.freeze
|
data/lib/roda/plugins/csrf.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen-string-literal: true
|
|
2
2
|
|
|
3
|
+
# RODA4: Remove plugin
|
|
4
|
+
|
|
3
5
|
require 'rack/csrf'
|
|
4
6
|
|
|
5
7
|
class Roda
|
|
@@ -7,6 +9,7 @@ class Roda
|
|
|
7
9
|
# This plugin is no longer recommended for use, it exists only for
|
|
8
10
|
# backwards compatibility. Consider using the route_csrf plugin
|
|
9
11
|
# instead, as that provides stronger CSRF protection.
|
|
12
|
+
# This plugin will no longer ship with Roda starting in Roda 4.
|
|
10
13
|
#
|
|
11
14
|
# The csrf plugin adds CSRF protection using rack_csrf, along with
|
|
12
15
|
# some csrf helper methods to use in your views. To use it, load
|
|
@@ -43,19 +43,19 @@ class Roda
|
|
|
43
43
|
render_each(enum, template, :locals=>locals, &block)
|
|
44
44
|
end
|
|
45
45
|
RUBY
|
|
46
|
-
# :
|
|
46
|
+
# simplecov:disable
|
|
47
47
|
else
|
|
48
48
|
def each_part(enum, template, locals=OPTS, &block)
|
|
49
49
|
render_each(enum, template, :locals=>locals, &block)
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
|
-
# :
|
|
52
|
+
# simplecov:enable
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
module AssumeFixedLocalsInstanceMethods
|
|
56
|
-
# :
|
|
56
|
+
# simplecov:disable
|
|
57
57
|
if RUBY_VERSION >= '3.0'
|
|
58
|
-
# :
|
|
58
|
+
# simplecov:enable
|
|
59
59
|
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
|
60
60
|
def each_part(enum, template, **locals, &block)
|
|
61
61
|
if optimized_method = _cached_render_each_template_method(template)
|
|
@@ -44,9 +44,9 @@ class Roda
|
|
|
44
44
|
:filter=>lambda{|k,v| false},
|
|
45
45
|
:headers=>OPTS,
|
|
46
46
|
:host=>'localhost',
|
|
47
|
-
# :
|
|
47
|
+
# simplecov:disable
|
|
48
48
|
:emailer=>lambda{|h| Net::SMTP.start(h[:host]){|s| s.send_message(h[:message], h[:from], h[:to])}},
|
|
49
|
-
# :
|
|
49
|
+
# simplecov:enable
|
|
50
50
|
:default_headers=>lambda do |h, e|
|
|
51
51
|
subject = if e.respond_to?(:message)
|
|
52
52
|
"#{e.class}: #{e.message}"
|
|
@@ -415,14 +415,14 @@ END
|
|
|
415
415
|
def exception_page_exception_message(exception)
|
|
416
416
|
exception.detailed_message(highlight: false).to_s
|
|
417
417
|
end
|
|
418
|
-
# :
|
|
418
|
+
# simplecov:disable
|
|
419
419
|
else
|
|
420
420
|
# Return message to use for exception.
|
|
421
421
|
def exception_page_exception_message(exception)
|
|
422
422
|
exception.message.to_s
|
|
423
423
|
end
|
|
424
424
|
end
|
|
425
|
-
# :
|
|
425
|
+
# simplecov:enable
|
|
426
426
|
end
|
|
427
427
|
|
|
428
428
|
module RequestMethods
|
data/lib/roda/plugins/h.rb
CHANGED
|
@@ -17,10 +17,10 @@ class Roda
|
|
|
17
17
|
begin
|
|
18
18
|
require 'cgi/escape'
|
|
19
19
|
unless CGI.respond_to?(:escapeHTML) # work around for JRuby 9.1
|
|
20
|
-
# :
|
|
20
|
+
# simplecov:disable
|
|
21
21
|
CGI = Object.new
|
|
22
22
|
CGI.extend(defined?(::CGI::Escape) ? ::CGI::Escape : ::CGI::Util)
|
|
23
|
-
# :
|
|
23
|
+
# simplecov:enable
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
module InstanceMethods
|
|
@@ -30,7 +30,7 @@ class Roda
|
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
rescue LoadError
|
|
33
|
-
# :
|
|
33
|
+
# simplecov:disable
|
|
34
34
|
|
|
35
35
|
# A Hash of entities and their escaped equivalents,
|
|
36
36
|
# to be escaped by h().
|
|
@@ -50,7 +50,7 @@ class Roda
|
|
|
50
50
|
string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
|
-
# :
|
|
53
|
+
# simplecov:enable
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
|
@@ -128,12 +128,16 @@ class Roda
|
|
|
128
128
|
if routes = roda_class.opts[:hash_branches][namespace]
|
|
129
129
|
if segment_end = rp.index('/', 1)
|
|
130
130
|
if meth = routes[rp[0, segment_end]]
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
always do
|
|
132
|
+
@remaining_path = rp[segment_end, 100000000]
|
|
133
|
+
scope.send(meth, self)
|
|
134
|
+
end
|
|
133
135
|
end
|
|
134
136
|
elsif meth = routes[rp]
|
|
135
|
-
|
|
136
|
-
|
|
137
|
+
always do
|
|
138
|
+
@remaining_path = ''
|
|
139
|
+
scope.send(meth, self)
|
|
140
|
+
end
|
|
137
141
|
end
|
|
138
142
|
end
|
|
139
143
|
end
|
|
@@ -116,8 +116,10 @@ class Roda
|
|
|
116
116
|
# remaining path, and dispatch to that block if there is one.
|
|
117
117
|
def hash_paths(namespace=matched_path)
|
|
118
118
|
if (routes = roda_class.opts[:hash_paths][namespace]) && (meth = routes[@remaining_path])
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
always do
|
|
120
|
+
@remaining_path = ''
|
|
121
|
+
scope.send(meth, self)
|
|
122
|
+
end
|
|
121
123
|
end
|
|
122
124
|
end
|
|
123
125
|
end
|
|
@@ -51,11 +51,11 @@ class Roda
|
|
|
51
51
|
Digest = begin
|
|
52
52
|
require 'openssl'
|
|
53
53
|
::OpenSSL::Digest
|
|
54
|
-
# :
|
|
54
|
+
# simplecov:disable
|
|
55
55
|
rescue LoadError
|
|
56
56
|
require 'digest/sha2'
|
|
57
57
|
::Digest
|
|
58
|
-
# :
|
|
58
|
+
# simplecov:enable
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def self.load_dependencies(app, opts = OPTS)
|
|
@@ -346,43 +346,41 @@ class Roda
|
|
|
346
346
|
|
|
347
347
|
if submitted_hmac.bytesize == 64
|
|
348
348
|
on String do |flags|
|
|
349
|
-
if flags.
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
end
|
|
349
|
+
if flags.include?('n') ^ !scope.hmac_path_namespace(opts).nil?
|
|
350
|
+
# Namespace required and not provided, or provided and not required.
|
|
351
|
+
# Bail early to avoid unnecessary HMAC calculation.
|
|
352
|
+
@remaining_path = orig_path
|
|
353
|
+
return
|
|
354
|
+
end
|
|
356
355
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
356
|
+
if flags.include?('m')
|
|
357
|
+
rpath = "#{env['REQUEST_METHOD'].to_s.upcase}:#{rpath}"
|
|
358
|
+
end
|
|
360
359
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
360
|
+
if flags.include?('p')
|
|
361
|
+
rpath = "#{rpath}?#{env["QUERY_STRING"]}"
|
|
362
|
+
end
|
|
364
363
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
end
|
|
364
|
+
if hmac_path_valid?(mpath, rpath, submitted_hmac, opts)
|
|
365
|
+
if flags.include?('t')
|
|
366
|
+
on Integer do |int|
|
|
367
|
+
if int >= Time.now.to_i
|
|
368
|
+
always(&block)
|
|
369
|
+
else
|
|
370
|
+
# Return from method without matching
|
|
371
|
+
@remaining_path = orig_path
|
|
372
|
+
return
|
|
375
373
|
end
|
|
376
|
-
else
|
|
377
|
-
always(&block)
|
|
378
374
|
end
|
|
375
|
+
else
|
|
376
|
+
always(&block)
|
|
379
377
|
end
|
|
380
378
|
end
|
|
381
|
-
|
|
382
|
-
# Return from method without matching
|
|
383
|
-
@remaining_path = orig_path
|
|
384
|
-
return
|
|
385
379
|
end
|
|
380
|
+
|
|
381
|
+
# Return from method without matching
|
|
382
|
+
@remaining_path = orig_path
|
|
383
|
+
return
|
|
386
384
|
end
|
|
387
385
|
|
|
388
386
|
# Return from method without matching
|
|
@@ -68,8 +68,29 @@ class Roda
|
|
|
68
68
|
# end
|
|
69
69
|
# end
|
|
70
70
|
#
|
|
71
|
-
# This plugin uses the host method on the request to get the hostname (this method
|
|
72
|
-
# is defined by Rack).
|
|
71
|
+
# This plugin uses the +host+ method on the request to get the hostname (this method
|
|
72
|
+
# is defined by Rack). Note that as of Rack 3.2, Rack's default approach to determine
|
|
73
|
+
# the hostname is insecure in many cases, since:
|
|
74
|
+
#
|
|
75
|
+
# * It will use a forwarded header instead of the +host+ header by default if the
|
|
76
|
+
# request was from a trusted proxy.
|
|
77
|
+
# * Rack trust proxies from any private IP address range by default
|
|
78
|
+
# (this can be disabled using <tt>Rack::Request.ip_filter=</tt>).
|
|
79
|
+
# * Rack supports both +forwarded+ and <tt>x-forwarded-host</tt> headers, will check
|
|
80
|
+
# both by default, and the order of checking depends on Rack's configuration
|
|
81
|
+
# (this can be configured using <tt>Rack::Request.forwarded_priority</tt>).
|
|
82
|
+
# * If the application can be reached via an arbitrary +host+ header, the attacker
|
|
83
|
+
# has full control over the <tt>Rack::Request#host</tt> value even when forwarded
|
|
84
|
+
# host usage is disabled.
|
|
85
|
+
#
|
|
86
|
+
# You should configure Rack appropriately for your deployment, not allowing the use
|
|
87
|
+
# of forwarded information unless your deployment is using a reverse proxy, and only
|
|
88
|
+
# allowing the specific forwarded header set by the expected reverse proxy if a
|
|
89
|
+
# reverse proxy is used. Rack 3.3 should include more control in this area,
|
|
90
|
+
# and Rack 4 should ship with more secure defaults in regard to forwarding headers.
|
|
91
|
+
#
|
|
92
|
+
# It is recommended to use the host_authorization plugin to check that the requested
|
|
93
|
+
# host is allowed when using this plugin.
|
|
73
94
|
module HostRouting
|
|
74
95
|
REQUEST_INSTANCE_VARIABLES = [:@_host_routing_host].freeze
|
|
75
96
|
|
|
@@ -140,7 +161,7 @@ class Roda
|
|
|
140
161
|
# Treat all given hostnames as routing to the give host.
|
|
141
162
|
def to(host, *hostnames)
|
|
142
163
|
hostnames.each do |hostname|
|
|
143
|
-
@host_hash[hostname] = host
|
|
164
|
+
@host_hash[hostname.downcase.freeze] = host
|
|
144
165
|
end
|
|
145
166
|
end
|
|
146
167
|
|
|
@@ -180,7 +201,11 @@ class Roda
|
|
|
180
201
|
# * The return value of the +hosts.default+ block, if given
|
|
181
202
|
# * The default value provided in the +hosts.default+ call
|
|
182
203
|
def _get_host_routing_host
|
|
183
|
-
host = self.host
|
|
204
|
+
if host = self.host
|
|
205
|
+
host = host.downcase
|
|
206
|
+
else
|
|
207
|
+
host = ""
|
|
208
|
+
end
|
|
184
209
|
|
|
185
210
|
roda_class.opts[:host_routing_hash][host] ||
|
|
186
211
|
scope._host_routing_default(host) ||
|