roda 3.108.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/_json.rb +22 -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/assets.rb +7 -10
- data/lib/roda/plugins/autoload_hash_branches.rb +9 -3
- data/lib/roda/plugins/autoload_named_routes.rb +9 -3
- 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 +7 -3
- 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 +6 -2
- 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 +19 -23
- data/lib/roda/plugins/environments.rb +3 -7
- data/lib/roda/plugins/error_email.rb +9 -5
- data/lib/roda/plugins/error_handler.rb +5 -3
- data/lib/roda/plugins/error_mail.rb +6 -2
- data/lib/roda/plugins/hash_branch_view_subdir.rb +6 -4
- data/lib/roda/plugins/hash_branches.rb +7 -5
- data/lib/roda/plugins/hash_paths.rb +7 -5
- data/lib/roda/plugins/hash_public.rb +11 -7
- 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 +9 -3
- data/lib/roda/plugins/hooks.rb +13 -10
- data/lib/roda/plugins/host_authorization.rb +7 -2
- data/lib/roda/plugins/host_routing.rb +7 -2
- data/lib/roda/plugins/invalid_request_body.rb +20 -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 +26 -12
- data/lib/roda/plugins/mail_processor.rb +9 -6
- data/lib/roda/plugins/mailer.rb +5 -3
- 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/path.rb +16 -14
- data/lib/roda/plugins/path_rewriter.rb +8 -5
- data/lib/roda/plugins/permissions_policy.rb +7 -3
- data/lib/roda/plugins/public.rb +11 -10
- 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 +34 -49
- data/lib/roda/plugins/render_coverage.rb +6 -3
- 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 +7 -2
- data/lib/roda/plugins/run_append_slash.rb +5 -1
- data/lib/roda/plugins/sec_fetch_site_csrf.rb +6 -2
- data/lib/roda/plugins/sessions.rb +15 -11
- data/lib/roda/plugins/shape_friendly.rb +3 -1
- data/lib/roda/plugins/sinatra_helpers.rb +7 -3
- 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 +9 -5
- 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.rb +10 -0
- data/lib/roda/version.rb +1 -1
- data/lib/roda.rb +25 -14
- metadata +6 -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
|
|
@@ -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
|
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
|
|
@@ -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
|
|
@@ -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'
|
|
@@ -43,6 +43,10 @@ class Roda
|
|
|
43
43
|
# simplecov:enable
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
module ClassMethods
|
|
47
|
+
RodaPlugins.opt_attr_reader(self, :common_logger_meth)
|
|
48
|
+
end
|
|
49
|
+
|
|
46
50
|
module InstanceMethods
|
|
47
51
|
private
|
|
48
52
|
|
|
@@ -67,7 +71,7 @@ class Roda
|
|
|
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
|
|
@@ -289,6 +289,10 @@ class Roda
|
|
|
289
289
|
policy.freeze
|
|
290
290
|
end
|
|
291
291
|
|
|
292
|
+
module ClassMethods
|
|
293
|
+
RodaPlugins.opt_attr_reader(self, :content_security_policy)
|
|
294
|
+
end
|
|
295
|
+
|
|
292
296
|
module InstanceMethods
|
|
293
297
|
# If a block is given, yield the current content security policy. Returns the
|
|
294
298
|
# current content security policy.
|
|
@@ -308,7 +312,7 @@ class Roda
|
|
|
308
312
|
|
|
309
313
|
# The current content security policy to be used for this response.
|
|
310
314
|
def content_security_policy
|
|
311
|
-
@content_security_policy ||= roda_class.
|
|
315
|
+
@content_security_policy ||= roda_class.content_security_policy.dup
|
|
312
316
|
end
|
|
313
317
|
|
|
314
318
|
# Do not set a content security policy header for this response.
|
|
@@ -322,7 +326,7 @@ class Roda
|
|
|
322
326
|
def set_default_headers
|
|
323
327
|
super
|
|
324
328
|
unless @skip_content_security_policy
|
|
325
|
-
(@content_security_policy || roda_class.
|
|
329
|
+
(@content_security_policy || roda_class.content_security_policy).set_header(headers)
|
|
326
330
|
end
|
|
327
331
|
end
|
|
328
332
|
end
|
|
@@ -61,7 +61,7 @@ class Roda
|
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
def self.configure(app, opts=OPTS)
|
|
64
|
-
previous = app.
|
|
64
|
+
previous = app.cookie_flags || DEFAULTS
|
|
65
65
|
opts = app.opts[:cookie_flags] = previous.merge(opts)
|
|
66
66
|
|
|
67
67
|
case opts[:same_site]
|
|
@@ -74,11 +74,15 @@ class Roda
|
|
|
74
74
|
opts.freeze
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
+
module ClassMethods
|
|
78
|
+
RodaPlugins.opt_attr_reader(self, :cookie_flags)
|
|
79
|
+
end
|
|
80
|
+
|
|
77
81
|
module InstanceMethods
|
|
78
82
|
private
|
|
79
83
|
|
|
80
84
|
def _handle_cookie_flags_array(cookies)
|
|
81
|
-
opts = self.class.
|
|
85
|
+
opts = self.class.cookie_flags
|
|
82
86
|
needs_secure = opts[:secure]
|
|
83
87
|
needs_httponly = opts[:httponly]
|
|
84
88
|
if needs_same_site = opts[:same_site]
|
data/lib/roda/plugins/cookies.rb
CHANGED
|
@@ -20,7 +20,11 @@ class Roda
|
|
|
20
20
|
module Cookies
|
|
21
21
|
# Allow setting default cookie options when loading the cookies plugin.
|
|
22
22
|
def self.configure(app, opts={})
|
|
23
|
-
app.opts[:cookies_opts] = (app.
|
|
23
|
+
app.opts[:cookies_opts] = (app.cookies_opts||{}).merge(opts).freeze
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
module ClassMethods
|
|
27
|
+
RodaPlugins.opt_attr_reader(self, :cookies_opts)
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
module ResponseMethods
|
|
@@ -32,7 +36,7 @@ class Roda
|
|
|
32
36
|
# response.delete_cookie('foo')
|
|
33
37
|
# response.delete_cookie('foo', domain: 'example.org')
|
|
34
38
|
def delete_cookie(key, value = {})
|
|
35
|
-
::Rack::Utils.delete_cookie_header!(@headers, key, roda_class.
|
|
39
|
+
::Rack::Utils.delete_cookie_header!(@headers, key, roda_class.cookies_opts.merge(value))
|
|
36
40
|
end
|
|
37
41
|
|
|
38
42
|
# Set the cookie with the given key in the headers.
|
|
@@ -41,7 +45,7 @@ class Roda
|
|
|
41
45
|
# response.set_cookie('foo', value: 'bar', domain: 'example.org')
|
|
42
46
|
def set_cookie(key, value)
|
|
43
47
|
value = { :value=>value } unless value.respond_to?(:keys)
|
|
44
|
-
::Rack::Utils.set_cookie_header!(@headers, key, roda_class.
|
|
48
|
+
::Rack::Utils.set_cookie_header!(@headers, key, roda_class.cookies_opts.merge(value))
|
|
45
49
|
end
|
|
46
50
|
end
|
|
47
51
|
end
|
|
@@ -44,16 +44,18 @@ class Roda
|
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
module ClassMethods
|
|
47
|
+
RodaPlugins.opt_attr_reader(self, :custom_block_results)
|
|
48
|
+
|
|
47
49
|
# Freeze the configured custom block results when freezing the app.
|
|
48
50
|
def freeze
|
|
49
|
-
|
|
51
|
+
custom_block_results.freeze
|
|
50
52
|
super
|
|
51
53
|
end
|
|
52
54
|
|
|
53
55
|
# Specify a block that will be called when an instance of klass
|
|
54
56
|
# is returned as a block result. The block defines a method.
|
|
55
57
|
def handle_block_result(klass, &block)
|
|
56
|
-
|
|
58
|
+
custom_block_results[klass] = define_roda_method(custom_block_results[klass] || "custom_block_result_#{klass}", 1, &block)
|
|
57
59
|
end
|
|
58
60
|
end
|
|
59
61
|
|
|
@@ -63,7 +65,7 @@ class Roda
|
|
|
63
65
|
# Try each configured custom block result, and call the related method
|
|
64
66
|
# to get the block result.
|
|
65
67
|
def unsupported_block_result(result)
|
|
66
|
-
roda_class.
|
|
68
|
+
roda_class.custom_block_results.each do |klass, meth|
|
|
67
69
|
if klass === result
|
|
68
70
|
result = scope.send(meth, result)
|
|
69
71
|
|
|
@@ -58,8 +58,10 @@ class Roda
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
module ClassMethods
|
|
61
|
+
RodaPlugins.opt_attr_reader(self, :custom_matchers)
|
|
62
|
+
|
|
61
63
|
def custom_matcher(match_class, &block)
|
|
62
|
-
custom_matchers = Hash[
|
|
64
|
+
custom_matchers = Hash[self.custom_matchers]
|
|
63
65
|
meth = custom_matchers[match_class] = custom_matchers[match_class] || :"_custom_matcher_#{match_class}"
|
|
64
66
|
opts[:custom_matchers] = custom_matchers.freeze
|
|
65
67
|
self::RodaRequest.send(:define_method, meth, &block)
|
|
@@ -72,7 +74,7 @@ class Roda
|
|
|
72
74
|
|
|
73
75
|
# Try custom matchers before calling super
|
|
74
76
|
def unsupported_matcher(matcher)
|
|
75
|
-
roda_class.
|
|
77
|
+
roda_class.custom_matchers.each do |match_class, meth|
|
|
76
78
|
if match_class === matcher
|
|
77
79
|
return send(meth, matcher)
|
|
78
80
|
end
|
|
@@ -27,15 +27,12 @@ class Roda
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
module ClassMethods
|
|
30
|
-
|
|
31
|
-
def default_headers
|
|
32
|
-
opts[:default_headers]
|
|
33
|
-
end
|
|
30
|
+
RodaPlugins.opt_attr_reader(self, :default_headers)
|
|
34
31
|
|
|
35
32
|
# Optimize the response class set_default_headers method if it hasn't been
|
|
36
33
|
# overridden and all default headers are strings.
|
|
37
34
|
def freeze
|
|
38
|
-
if (headers =
|
|
35
|
+
if (headers = default_headers).all?{|k, v| k.is_a?(String) && v.is_a?(String)} &&
|
|
39
36
|
(self::RodaResponse.instance_method(:set_default_headers).owner == Base::ResponseMethods)
|
|
40
37
|
self::RodaResponse.class_eval(<<-END, __FILE__, __LINE__+1)
|
|
41
38
|
private
|
|
@@ -18,6 +18,7 @@ class Roda
|
|
|
18
18
|
def self.configure(app, &block)
|
|
19
19
|
raise RodaError, "default_status plugin requires a block" unless block
|
|
20
20
|
if check_arity = app.opts.fetch(:check_arity, true)
|
|
21
|
+
# RODA4: Remove support for :check_arity, default to false behavior
|
|
21
22
|
unless block.arity == 0
|
|
22
23
|
if check_arity == :warn
|
|
23
24
|
RodaPlugins.warn "Arity mismatch in block passed to plugin :default_status. Expected Arity 0, but arguments required for #{block.inspect}"
|