roda 3.107.0 → 3.109.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/opts.rb +22 -0
- data/lib/roda/plugins/Integer_matcher_max.rb +1 -1
- data/lib/roda/plugins/_add_script_name.rb +14 -0
- data/lib/roda/plugins/_base64.rb +2 -2
- data/lib/roda/plugins/_json.rb +22 -0
- data/lib/roda/plugins/_optimized_matching.rb +1 -0
- data/lib/roda/plugins/_symbol_class_matchers.rb +6 -6
- data/lib/roda/plugins/additional_render_engines.rb +5 -1
- data/lib/roda/plugins/additional_view_directories.rb +5 -1
- data/lib/roda/plugins/all_verbs.rb +2 -2
- data/lib/roda/plugins/assets.rb +11 -14
- data/lib/roda/plugins/autoload_hash_branches.rb +9 -3
- data/lib/roda/plugins/autoload_named_routes.rb +9 -3
- 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/capture_erb.rb +5 -1
- data/lib/roda/plugins/chunked.rb +11 -5
- data/lib/roda/plugins/class_level_routing.rb +5 -3
- data/lib/roda/plugins/class_matchers.rb +3 -1
- data/lib/roda/plugins/common_logger.rb +11 -7
- data/lib/roda/plugins/conditional_sessions.rb +1 -1
- data/lib/roda/plugins/content_for.rb +5 -1
- data/lib/roda/plugins/content_security_policy.rb +6 -2
- data/lib/roda/plugins/cookie_flags.rb +8 -4
- data/lib/roda/plugins/cookies.rb +7 -3
- data/lib/roda/plugins/custom_block_results.rb +5 -3
- data/lib/roda/plugins/custom_matchers.rb +4 -2
- data/lib/roda/plugins/default_headers.rb +2 -5
- data/lib/roda/plugins/default_status.rb +1 -0
- data/lib/roda/plugins/each_part.rb +23 -27
- data/lib/roda/plugins/environments.rb +3 -7
- data/lib/roda/plugins/error_email.rb +11 -7
- data/lib/roda/plugins/error_handler.rb +5 -3
- data/lib/roda/plugins/error_mail.rb +6 -2
- data/lib/roda/plugins/exception_page.rb +2 -2
- data/lib/roda/plugins/h.rb +4 -4
- data/lib/roda/plugins/hash_branch_view_subdir.rb +6 -4
- data/lib/roda/plugins/hash_branches.rb +15 -9
- data/lib/roda/plugins/hash_paths.rb +11 -7
- data/lib/roda/plugins/hash_public.rb +13 -9
- data/lib/roda/plugins/hash_public_cache.rb +9 -7
- data/lib/roda/plugins/hash_routes.rb +5 -3
- data/lib/roda/plugins/heartbeat.rb +6 -2
- data/lib/roda/plugins/hmac_paths.rb +36 -32
- data/lib/roda/plugins/hooks.rb +13 -10
- data/lib/roda/plugins/host_authorization.rb +7 -2
- data/lib/roda/plugins/host_routing.rb +36 -6
- data/lib/roda/plugins/invalid_request_body.rb +22 -4
- data/lib/roda/plugins/ip_from_header.rb +5 -1
- data/lib/roda/plugins/json.rb +10 -8
- data/lib/roda/plugins/json_parser.rb +43 -11
- data/lib/roda/plugins/mail_processor.rb +11 -8
- data/lib/roda/plugins/mailer.rb +9 -7
- data/lib/roda/plugins/match_affix.rb +6 -1
- data/lib/roda/plugins/match_hook_args.rb +7 -5
- data/lib/roda/plugins/middleware.rb +13 -7
- data/lib/roda/plugins/module_include.rb +1 -1
- data/lib/roda/plugins/multi_public.rb +6 -2
- data/lib/roda/plugins/multi_route.rb +1 -1
- data/lib/roda/plugins/multi_run.rb +13 -17
- data/lib/roda/plugins/named_routes.rb +8 -6
- data/lib/roda/plugins/named_templates.rb +5 -3
- 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 +22 -20
- data/lib/roda/plugins/path_matchers.rb +5 -1
- data/lib/roda/plugins/path_rewriter.rb +8 -5
- data/lib/roda/plugins/permissions_policy.rb +7 -3
- data/lib/roda/plugins/public.rb +15 -14
- data/lib/roda/plugins/recheck_precompiled_assets.rb +1 -1
- data/lib/roda/plugins/redirect_http_to_https.rb +6 -3
- data/lib/roda/plugins/render.rb +58 -61
- data/lib/roda/plugins/render_coverage.rb +12 -8
- data/lib/roda/plugins/render_each.rb +2 -2
- data/lib/roda/plugins/render_locals.rb +12 -6
- data/lib/roda/plugins/request_aref.rb +1 -1
- data/lib/roda/plugins/response_content_type.rb +7 -3
- data/lib/roda/plugins/route_csrf.rb +42 -5
- data/lib/roda/plugins/run_append_slash.rb +12 -4
- data/lib/roda/plugins/sec_fetch_site_csrf.rb +11 -4
- data/lib/roda/plugins/sessions.rb +17 -13
- data/lib/roda/plugins/shape_friendly.rb +7 -5
- data/lib/roda/plugins/sinatra_helpers.rb +7 -3
- data/lib/roda/plugins/static.rb +3 -0
- data/lib/roda/plugins/status_handler.rb +5 -3
- data/lib/roda/plugins/strip_path_prefix.rb +4 -2
- data/lib/roda/plugins/symbol_matchers.rb +3 -1
- data/lib/roda/plugins/symbol_views.rb +1 -1
- data/lib/roda/plugins/timestamp_public.rb +8 -4
- data/lib/roda/plugins/type_routing.rb +10 -6
- data/lib/roda/plugins/typecast_params.rb +2 -2
- data/lib/roda/plugins/typecast_params_sized_integers.rb +1 -1
- data/lib/roda/plugins/url_escape.rb +2 -14
- data/lib/roda/plugins/view_options.rb +3 -5
- data/lib/roda/plugins.rb +14 -4
- data/lib/roda/request.rb +25 -9
- data/lib/roda/version.rb +1 -1
- data/lib/roda.rb +32 -21
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f8fe0436b7983ecbf3bbbf1cf8d7d8867f87184550ef097d6fad894a17211c5e
|
|
4
|
+
data.tar.gz: a19800b130b13b745d3ff6a77c22ac88e4c44b70a778c243e07212c0fcebd019
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e0778c049972903e98c14287074ed0833eb63b201834c61ed8731cafb9be5da523963e931eb8ed668a975f61682d866c6ffcd1e61a4aaa19d62ec663f2318fc1
|
|
7
|
+
data.tar.gz: 17e2cd71b7593a18b398fd2965a2673280e11f76db7f02f9de1eaa604e4632857fbe8c1875cfd9fc3ec9d6af2152ad4a63d757065a1ae53cb46766de5690238a
|
data/lib/roda/opts.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
class Roda
|
|
4
|
+
class RodaOpts < Hash
|
|
5
|
+
# The Roda class to set instance variables on when calling #[]=
|
|
6
|
+
attr_writer :roda_class
|
|
7
|
+
|
|
8
|
+
# If duplicating the hash, detach the Roda class.
|
|
9
|
+
def initialize_copy(_)
|
|
10
|
+
super
|
|
11
|
+
@roda_class = nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Set an <tt>@opt_*</tt> instance variable in the Roda class if it is tied
|
|
15
|
+
# to a Roda class.
|
|
16
|
+
def []=(k, v)
|
|
17
|
+
super
|
|
18
|
+
@roda_class.instance_variable_set(:"@opt_#{k}", v) if @roda_class && Symbol === k
|
|
19
|
+
v
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
module AddScriptName_
|
|
7
|
+
module ClassMethods
|
|
8
|
+
RodaPlugins.opt_attr_reader(self, :add_script_name, name: :add_script_name?)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
register_plugin(:_add_script_name, AddScriptName_)
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/roda/plugins/_base64.rb
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
class Roda
|
|
7
|
+
module RodaPlugins
|
|
8
|
+
module JSON_
|
|
9
|
+
module ClassMethods
|
|
10
|
+
def json_parser
|
|
11
|
+
@opt_json_parser || ::JSON.method(:parse)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def json_serializer
|
|
15
|
+
@opt_json_serializer || :to_json.to_proc
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
register_plugin(:_json, JSON_)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -26,11 +26,11 @@ class Roda
|
|
|
26
26
|
regexp = matcher
|
|
27
27
|
consume_regexp = self::RodaRequest.send(:consume_pattern, regexp)
|
|
28
28
|
when Symbol
|
|
29
|
-
unless
|
|
29
|
+
unless respond_to?(:symbol_matchers)
|
|
30
30
|
raise RodaError, "cannot provide Symbol matcher to class_matcher unless using symbol_matchers plugin: #{matcher.inspect}"
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
regexp, consume_regexp, convert_meth, consume_meth =
|
|
33
|
+
regexp, consume_regexp, convert_meth, consume_meth = symbol_matchers[matcher]
|
|
34
34
|
|
|
35
35
|
unless regexp
|
|
36
36
|
raise RodaError, "unregistered symbol matcher given to #{type}_matcher: #{matcher.inspect}"
|
|
@@ -38,11 +38,11 @@ class Roda
|
|
|
38
38
|
|
|
39
39
|
block = _merge_matcher_blocks(type, obj, block, convert_meth)
|
|
40
40
|
when Class
|
|
41
|
-
unless
|
|
41
|
+
unless respond_to?(:class_matchers)
|
|
42
42
|
raise RodaError, "cannot provide Class matcher to symbol_matcher unless using class_matchers plugin: #{matcher.inspect}"
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
regexp, consume_regexp, convert_meth, consume_meth =
|
|
45
|
+
regexp, consume_regexp, convert_meth, consume_meth = class_matchers[matcher]
|
|
46
46
|
unless regexp
|
|
47
47
|
raise RodaError, "unregistered class matcher given to #{type}_matcher: #{matcher.inspect}"
|
|
48
48
|
end
|
|
@@ -60,9 +60,9 @@ class Roda
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
consume_meth ||= options[:segment] ? :_consume_single_segment : :consume
|
|
63
|
-
array =
|
|
63
|
+
array = (obj.is_a?(Symbol) ? symbol_matchers : class_matchers)[obj] = [regexp, consume_regexp, convert_meth, consume_meth].freeze
|
|
64
64
|
|
|
65
|
-
self::RodaRequest.
|
|
65
|
+
self::RodaRequest.class_exec do
|
|
66
66
|
class_exec(meth, array, &request_class_block)
|
|
67
67
|
private meth
|
|
68
68
|
end
|
|
@@ -34,6 +34,10 @@ class Roda
|
|
|
34
34
|
app.opts[:additional_render_engines] = render_engines.dup.freeze
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
module ClassMethods
|
|
38
|
+
RodaPlugins.opt_attr_reader(self, :additional_render_engines)
|
|
39
|
+
end
|
|
40
|
+
|
|
37
41
|
module InstanceMethods
|
|
38
42
|
private
|
|
39
43
|
|
|
@@ -45,7 +49,7 @@ class Roda
|
|
|
45
49
|
orig_path = super
|
|
46
50
|
|
|
47
51
|
unless File.file?(orig_path)
|
|
48
|
-
self.
|
|
52
|
+
self.class.additional_render_engines.each do |engine|
|
|
49
53
|
path = super(opts.merge(:engine=>engine))
|
|
50
54
|
return path if File.file?(path)
|
|
51
55
|
end
|
|
@@ -39,6 +39,10 @@ class Roda
|
|
|
39
39
|
app.plugin :render, :allowed_paths=>(app.opts[:render][:allowed_paths] + view_dirs).uniq.freeze
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
module ClassMethods
|
|
43
|
+
RodaPlugins.opt_attr_reader(self, :additional_view_directories)
|
|
44
|
+
end
|
|
45
|
+
|
|
42
46
|
module InstanceMethods
|
|
43
47
|
private
|
|
44
48
|
|
|
@@ -50,7 +54,7 @@ class Roda
|
|
|
50
54
|
orig_path = super
|
|
51
55
|
|
|
52
56
|
unless File.file?(orig_path)
|
|
53
|
-
self.
|
|
57
|
+
self.class.additional_view_directories.each do |view_dir|
|
|
54
58
|
path = super(opts.merge(:views=>view_dir))
|
|
55
59
|
return path if File.file?(path)
|
|
56
60
|
end
|
|
@@ -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
|
@@ -371,6 +371,8 @@ class Roda
|
|
|
371
371
|
# Load the render, caching, and h plugins, since the assets plugin
|
|
372
372
|
# depends on them.
|
|
373
373
|
def self.load_dependencies(app, opts = OPTS)
|
|
374
|
+
app.plugin :_json
|
|
375
|
+
app.plugin :_add_script_name
|
|
374
376
|
app.plugin :render
|
|
375
377
|
app.plugin :caching
|
|
376
378
|
app.plugin :h
|
|
@@ -401,7 +403,7 @@ class Roda
|
|
|
401
403
|
app.opts[:assets] = opts.dup
|
|
402
404
|
app.opts[:assets][:orig_opts] = opts
|
|
403
405
|
end
|
|
404
|
-
opts = app.
|
|
406
|
+
opts = app.assets_opts
|
|
405
407
|
opts[:path] = app.expand_path(opts[:path]||"assets").freeze
|
|
406
408
|
opts[:public] = app.expand_path(opts[:public]||"public").freeze
|
|
407
409
|
|
|
@@ -420,7 +422,6 @@ class Roda
|
|
|
420
422
|
end
|
|
421
423
|
|
|
422
424
|
if opts[:precompiled] && !opts[:compiled] && ::File.exist?(opts[:precompiled])
|
|
423
|
-
require 'json'
|
|
424
425
|
opts[:compiled] = app.send(:_precompiled_asset_metadata, opts[:precompiled])
|
|
425
426
|
end
|
|
426
427
|
|
|
@@ -498,10 +499,7 @@ class Roda
|
|
|
498
499
|
end
|
|
499
500
|
|
|
500
501
|
module ClassMethods
|
|
501
|
-
|
|
502
|
-
def assets_opts
|
|
503
|
-
opts[:assets]
|
|
504
|
-
end
|
|
502
|
+
RodaPlugins.opt_attr_reader(self, :assets, name: :assets_opts)
|
|
505
503
|
|
|
506
504
|
# Compile options for the given asset type. If no asset_type
|
|
507
505
|
# is given, compile both the :css and :js asset types. You
|
|
@@ -522,10 +520,9 @@ class Roda
|
|
|
522
520
|
end
|
|
523
521
|
|
|
524
522
|
if precompile_file = assets_opts[:precompiled]
|
|
525
|
-
require 'json'
|
|
526
523
|
::FileUtils.mkdir_p(File.dirname(precompile_file))
|
|
527
524
|
tmp_file = "#{precompile_file}.tmp"
|
|
528
|
-
::File.open(tmp_file, 'wb'){|f| f.write(
|
|
525
|
+
::File.open(tmp_file, 'wb'){|f| f.write(json_serializer.call(assets_opts[:compiled]))}
|
|
529
526
|
::File.rename(tmp_file, precompile_file)
|
|
530
527
|
end
|
|
531
528
|
|
|
@@ -558,7 +555,7 @@ class Roda
|
|
|
558
555
|
|
|
559
556
|
# The precompiled asset metadata stored in the given file
|
|
560
557
|
def _precompiled_asset_metadata(file)
|
|
561
|
-
|
|
558
|
+
json_parser.call(::File.read(file))
|
|
562
559
|
end
|
|
563
560
|
|
|
564
561
|
# Compile each array of files for the given type into a single
|
|
@@ -659,9 +656,9 @@ class Roda
|
|
|
659
656
|
begin
|
|
660
657
|
require 'uglifier'
|
|
661
658
|
rescue => e
|
|
662
|
-
# :
|
|
659
|
+
# simplecov:disable
|
|
663
660
|
raise CompressorNotFound, "#{e.class}: #{e.message}", e.backtrace
|
|
664
|
-
# :
|
|
661
|
+
# simplecov:enable
|
|
665
662
|
end
|
|
666
663
|
|
|
667
664
|
Uglifier.compile(content)
|
|
@@ -689,11 +686,11 @@ class Roda
|
|
|
689
686
|
digest = begin
|
|
690
687
|
require 'openssl'
|
|
691
688
|
::OpenSSL::Digest
|
|
692
|
-
# :
|
|
689
|
+
# simplecov:disable
|
|
693
690
|
rescue LoadError
|
|
694
691
|
require 'digest/sha2'
|
|
695
692
|
::Digest
|
|
696
|
-
# :
|
|
693
|
+
# simplecov:enable
|
|
697
694
|
end
|
|
698
695
|
digest.const_get(algo.to_s.upcase).hexdigest(content)
|
|
699
696
|
end
|
|
@@ -711,7 +708,7 @@ class Roda
|
|
|
711
708
|
end
|
|
712
709
|
stype = ltype.to_s
|
|
713
710
|
|
|
714
|
-
url_prefix = request.script_name if self.class.
|
|
711
|
+
url_prefix = request.script_name if self.class.add_script_name?
|
|
715
712
|
relative_paths = o[:relative_paths]
|
|
716
713
|
|
|
717
714
|
paths = if o[:compiled]
|
|
@@ -38,13 +38,15 @@ class Roda
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
module ClassMethods
|
|
41
|
+
RodaPlugins.opt_attr_reader(self, :autoload_hash_branch_files)
|
|
42
|
+
|
|
41
43
|
# Autoload the given file when there is request for the hash branch.
|
|
42
44
|
# The given file should configure the hash branch specified.
|
|
43
45
|
def autoload_hash_branch(namespace='', segment, file)
|
|
44
46
|
segment = "/#{segment}"
|
|
45
47
|
file = File.expand_path(file)
|
|
46
|
-
|
|
47
|
-
routes =
|
|
48
|
+
autoload_hash_branch_files << file
|
|
49
|
+
routes = hash_branches[namespace] ||= {}
|
|
48
50
|
meth = routes[segment] = define_roda_method(routes[segment] || "hash_branch_#{namespace}_#{segment}", 1) do |r|
|
|
49
51
|
loc = method(routes[segment]).source_location
|
|
50
52
|
require file
|
|
@@ -68,7 +70,11 @@ class Roda
|
|
|
68
70
|
|
|
69
71
|
# Eagerly load all hash branches when freezing the application.
|
|
70
72
|
def freeze
|
|
71
|
-
|
|
73
|
+
unless opts.frozen?
|
|
74
|
+
autoload_hash_branch_files.each{|file| require file}
|
|
75
|
+
opts[:autoload_hash_branch_files] = nil
|
|
76
|
+
opts.delete(:autoload_hash_branch_files)
|
|
77
|
+
end
|
|
72
78
|
super
|
|
73
79
|
end
|
|
74
80
|
end
|
|
@@ -35,12 +35,14 @@ class Roda
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
module ClassMethods
|
|
38
|
+
RodaPlugins.opt_attr_reader(self, :autoload_named_route_files)
|
|
39
|
+
|
|
38
40
|
# Autoload the given file when there is request for the named route.
|
|
39
41
|
# The given file should configure the named route specified.
|
|
40
42
|
def autoload_named_route(namespace=nil, name, file)
|
|
41
43
|
file = File.expand_path(file)
|
|
42
|
-
|
|
43
|
-
routes =
|
|
44
|
+
autoload_named_route_files << file
|
|
45
|
+
routes = namespaced_routes[namespace] ||= {}
|
|
44
46
|
meth = routes[name] = define_roda_method(routes[name] || "named_routes_#{namespace}_#{name}", 1) do |r|
|
|
45
47
|
loc = method(routes[name]).source_location
|
|
46
48
|
require file
|
|
@@ -54,7 +56,11 @@ class Roda
|
|
|
54
56
|
|
|
55
57
|
# Eagerly load all autoloaded named routes when freezing the application.
|
|
56
58
|
def freeze
|
|
57
|
-
|
|
59
|
+
unless opts.frozen?
|
|
60
|
+
autoload_named_route_files.each{|file| require file}
|
|
61
|
+
opts[:autoload_named_route_files] = nil
|
|
62
|
+
opts.delete(:autoload_named_route_files)
|
|
63
|
+
end
|
|
58
64
|
super
|
|
59
65
|
end
|
|
60
66
|
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
|
|
@@ -51,6 +51,10 @@ class Roda
|
|
|
51
51
|
app.opts[:capture_erb_returns] = opts[:returns] if opts.has_key?(:returns)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
module ClassMethods
|
|
55
|
+
RodaPlugins.opt_attr_reader(self, :capture_erb_returns)
|
|
56
|
+
end
|
|
57
|
+
|
|
54
58
|
module InstanceMethods
|
|
55
59
|
# Temporarily replace the ERB output buffer
|
|
56
60
|
# with an empty string, and then yield to the block.
|
|
@@ -71,7 +75,7 @@ class Roda
|
|
|
71
75
|
if buf_was.respond_to?(:capture) && !buf_was.instance_of?(String)
|
|
72
76
|
buf_was.capture(&block)
|
|
73
77
|
else
|
|
74
|
-
returns = opts.fetch(:returns) { self.
|
|
78
|
+
returns = opts.fetch(:returns) { self.class.capture_erb_returns }
|
|
75
79
|
|
|
76
80
|
begin
|
|
77
81
|
instance_variable_set(outvar, String.new)
|
data/lib/roda/plugins/chunked.rb
CHANGED
|
@@ -162,7 +162,7 @@ class Roda
|
|
|
162
162
|
app.opts[:chunk_by_default] = opts[:chunk_by_default]
|
|
163
163
|
app.opts[:force_chunked_encoding] = opts[:force_chunked_encoding]
|
|
164
164
|
if opts[:headers]
|
|
165
|
-
app.opts[:chunk_headers] = (app.
|
|
165
|
+
app.opts[:chunk_headers] = (app.chunk_headers || {}).merge(opts[:headers]).freeze
|
|
166
166
|
end
|
|
167
167
|
end
|
|
168
168
|
|
|
@@ -207,6 +207,12 @@ class Roda
|
|
|
207
207
|
end
|
|
208
208
|
end
|
|
209
209
|
|
|
210
|
+
module ClassMethods
|
|
211
|
+
RodaPlugins.opt_attr_reader(self, :chunk_by_default, name: :chunk_by_default?)
|
|
212
|
+
RodaPlugins.opt_attr_reader(self, :force_chunked_encoding, name: :force_chunked_encoding?)
|
|
213
|
+
RodaPlugins.opt_attr_reader(self, :chunk_headers)
|
|
214
|
+
end
|
|
215
|
+
|
|
210
216
|
module InstanceMethods
|
|
211
217
|
# Disable chunking for the current request. Mostly useful when
|
|
212
218
|
# chunking is turned on by default.
|
|
@@ -217,7 +223,7 @@ class Roda
|
|
|
217
223
|
# If chunking by default, call chunked if it hasn't yet been
|
|
218
224
|
# called and chunking is not specifically disabled.
|
|
219
225
|
def view(*a)
|
|
220
|
-
if
|
|
226
|
+
if self.class.chunk_by_default? && @_chunked != false && !defined?(yield)
|
|
221
227
|
chunked(*a)
|
|
222
228
|
else
|
|
223
229
|
super
|
|
@@ -228,7 +234,7 @@ class Roda
|
|
|
228
234
|
# an overview. If a block is given, it is passed to #delay.
|
|
229
235
|
def chunked(template, opts=OPTS, &block)
|
|
230
236
|
if @_chunked.nil?
|
|
231
|
-
@_chunked = !self.
|
|
237
|
+
@_chunked = !self.class.force_chunked_encoding? || @_request.http_version == "HTTP/1.1"
|
|
232
238
|
end
|
|
233
239
|
|
|
234
240
|
if block
|
|
@@ -255,10 +261,10 @@ class Roda
|
|
|
255
261
|
|
|
256
262
|
res = response
|
|
257
263
|
headers = res.headers
|
|
258
|
-
if chunk_headers = self.
|
|
264
|
+
if chunk_headers = self.class.chunk_headers
|
|
259
265
|
headers.merge!(chunk_headers)
|
|
260
266
|
end
|
|
261
|
-
if self.
|
|
267
|
+
if self.class.force_chunked_encoding?
|
|
262
268
|
res[RodaResponseHeaders::TRANSFER_ENCODING] = 'chunked'
|
|
263
269
|
body = Body.new(self)
|
|
264
270
|
else
|
|
@@ -60,17 +60,19 @@ class Roda
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
module ClassMethods
|
|
63
|
+
RodaPlugins.opt_attr_reader(self, :class_level_routes)
|
|
64
|
+
|
|
63
65
|
# Define routing methods that will store class level routes.
|
|
64
66
|
[:root, :on, :is, :get, :post, :delete, :head, :options, :link, :patch, :put, :trace, :unlink].each do |request_meth|
|
|
65
67
|
define_method(request_meth) do |*args, &block|
|
|
66
68
|
meth = define_roda_method("class_level_routing_#{request_meth}", :any, &block)
|
|
67
|
-
|
|
69
|
+
class_level_routes << [request_meth, args, meth].freeze
|
|
68
70
|
end
|
|
69
71
|
end
|
|
70
72
|
|
|
71
73
|
# Freeze the class level routes so that there can be no thread safety issues at runtime.
|
|
72
74
|
def freeze
|
|
73
|
-
|
|
75
|
+
class_level_routes.freeze
|
|
74
76
|
super
|
|
75
77
|
end
|
|
76
78
|
end
|
|
@@ -93,7 +95,7 @@ class Roda
|
|
|
93
95
|
@_response.status = nil
|
|
94
96
|
result.replace(_roda_handle_route do
|
|
95
97
|
r = @_request
|
|
96
|
-
|
|
98
|
+
self.class.class_level_routes.each do |request_meth, args, meth|
|
|
97
99
|
r.instance_variable_set(:@remaining_path, @_original_remaining_path)
|
|
98
100
|
r.public_send(request_meth, *args) do |*a|
|
|
99
101
|
send(meth, *a)
|
|
@@ -93,6 +93,8 @@ class Roda
|
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
module ClassMethods
|
|
96
|
+
RodaPlugins.opt_attr_reader(self, :class_matchers)
|
|
97
|
+
|
|
96
98
|
# Set the matcher and block to use for the given class.
|
|
97
99
|
# The matcher can be a regexp, registered class matcher, or registered symbol
|
|
98
100
|
# matcher (if using the symbol_matchers plugin).
|
|
@@ -119,7 +121,7 @@ class Roda
|
|
|
119
121
|
|
|
120
122
|
# Freeze the class_matchers hash when freezing the app.
|
|
121
123
|
def freeze
|
|
122
|
-
|
|
124
|
+
class_matchers.freeze
|
|
123
125
|
super
|
|
124
126
|
end
|
|
125
127
|
end
|
|
@@ -26,8 +26,8 @@ class Roda
|
|
|
26
26
|
private_constant :MUTATE_LINE
|
|
27
27
|
|
|
28
28
|
def self.configure(app, logger=nil, opts=OPTS)
|
|
29
|
-
app.opts[:common_logger] = logger || app.opts[:common_logger] || $stderr
|
|
30
|
-
app.opts[:common_logger_meth] =
|
|
29
|
+
common_logger = app.opts[:common_logger] = logger || app.opts[:common_logger] || $stderr # RODA4: drop setting of option, no longer used
|
|
30
|
+
app.opts[:common_logger_meth] = common_logger.method(opts.fetch(:method){logger.respond_to?(:write) ? :write : :<<})
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
if RUBY_VERSION >= '2.1'
|
|
@@ -36,11 +36,15 @@ 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
|
+
end
|
|
45
|
+
|
|
46
|
+
module ClassMethods
|
|
47
|
+
RodaPlugins.opt_attr_reader(self, :common_logger_meth)
|
|
44
48
|
end
|
|
45
49
|
|
|
46
50
|
module InstanceMethods
|
|
@@ -61,13 +65,13 @@ class Roda
|
|
|
61
65
|
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
66
|
if MUTATE_LINE
|
|
63
67
|
line.gsub!(/[^[:print:]]/){|c| sprintf("\\x%x", c.ord)}
|
|
64
|
-
# :
|
|
68
|
+
# simplecov:disable
|
|
65
69
|
else
|
|
66
70
|
line = line.gsub(/[^[:print:]]/){|c| sprintf("\\x%x", c.ord)}
|
|
67
|
-
# :
|
|
71
|
+
# simplecov:enable
|
|
68
72
|
end
|
|
69
73
|
line[-1] = "\n"
|
|
70
|
-
|
|
74
|
+
self.class.common_logger_meth.call(line)
|
|
71
75
|
end
|
|
72
76
|
|
|
73
77
|
# Create timer instance used for timing
|
|
@@ -23,7 +23,7 @@ class Roda
|
|
|
23
23
|
# a request method for whether sessions are allowed.
|
|
24
24
|
def self.load_dependencies(app, opts=OPTS, &block)
|
|
25
25
|
app.plugin :sessions, opts
|
|
26
|
-
app::RodaRequest.
|
|
26
|
+
app::RodaRequest.class_exec do
|
|
27
27
|
define_method(:use_sessions?, &block)
|
|
28
28
|
alias use_sessions? use_sessions?
|
|
29
29
|
end
|
|
@@ -69,13 +69,17 @@ class Roda
|
|
|
69
69
|
app.opts[:append_content_for] = opts.fetch(:append, true)
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
+
module ClassMethods
|
|
73
|
+
RodaPlugins.opt_attr_reader(self, :append_content_for, name: :append_content_for?)
|
|
74
|
+
end
|
|
75
|
+
|
|
72
76
|
module InstanceMethods
|
|
73
77
|
# If called with a block, store content enclosed by block
|
|
74
78
|
# under the given key. If called without a block, retrieve
|
|
75
79
|
# stored content with the given key, or return nil if there
|
|
76
80
|
# is no content stored with that key.
|
|
77
81
|
def content_for(key, value=nil, &block)
|
|
78
|
-
append =
|
|
82
|
+
append = self.class.append_content_for?
|
|
79
83
|
|
|
80
84
|
if block || value
|
|
81
85
|
if block
|