roda 3.59.0 → 3.61.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +10 -0
- data/README.rdoc +40 -15
- data/doc/release_notes/3.60.0.txt +56 -0
- data/doc/release_notes/3.61.0.txt +24 -0
- data/lib/roda/plugins/_optimized_matching.rb +2 -2
- data/lib/roda/plugins/all_verbs.rb +0 -2
- data/lib/roda/plugins/common_logger.rb +1 -1
- data/lib/roda/plugins/disallow_file_uploads.rb +0 -2
- data/lib/roda/plugins/indifferent_params.rb +2 -8
- data/lib/roda/plugins/json_parser.rb +1 -3
- data/lib/roda/plugins/link_to.rb +83 -0
- data/lib/roda/plugins/multi_public.rb +0 -4
- data/lib/roda/plugins/not_allowed.rb +0 -2
- data/lib/roda/plugins/public.rb +0 -6
- data/lib/roda/plugins/render.rb +3 -13
- data/lib/roda/plugins/render_each.rb +0 -2
- data/lib/roda/plugins/render_locals.rb +0 -2
- data/lib/roda/plugins/sinatra_helpers.rb +0 -6
- data/lib/roda/plugins/status_handler.rb +1 -3
- data/lib/roda/plugins/typecast_params.rb +102 -53
- data/lib/roda/plugins/view_options.rb +0 -2
- data/lib/roda/request.rb +4 -8
- data/lib/roda/response.rb +0 -4
- data/lib/roda/version.rb +1 -1
- metadata +11 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 337e7cc074ffe0c300a4dbf9a14f72552caa5b9446fdf0ca04b9f22d9117c9c7
|
4
|
+
data.tar.gz: 53a8b4ec124df8ef0efdc7efcc7bec3e0e7ea7d13fa60fb5d6adf06f50ed081e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78671d90145cf431a7deff333e6b75ad681252cae159b5ff09dfaba70d4b3fc17ec1f7362c52454c3f8e94e2343bd4b4d419a5c23738a6b525e9fdd79dc8846c
|
7
|
+
data.tar.gz: 55b5bc0be878d58d66e0834110b47313f522e1f109b95c23348b2cb09430b01383595197db8f8db6587f10d3d9e4a7a353a2d70fb1ed4a099573309a5aabcae6
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
= 3.61.0 (2022-10-12)
|
2
|
+
|
3
|
+
* Make Integer matcher limit integer segments to 100 characters by default (jeremyevans)
|
4
|
+
|
5
|
+
* Limit input bytesize by default for integer, float, and date/time typecasts in typecast_params (jeremyevans)
|
6
|
+
|
7
|
+
= 3.60.0 (2022-09-13)
|
8
|
+
|
9
|
+
* Add link_to plugin with link_to method for creating HTML links (jeremyevans)
|
10
|
+
|
1
11
|
= 3.59.0 (2022-08-12)
|
2
12
|
|
3
13
|
* Add additional_render_engines plugin, for considering multiple render engines for templates (jeremyevans)
|
data/README.rdoc
CHANGED
@@ -1,9 +1,35 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
rdoc-image:https://roda.jeremyevans.net/images/roda-logo.svg
|
2
|
+
|
3
|
+
A routing tree web toolkit, designed for building fast and maintainable web applications in Ruby.
|
4
|
+
|
5
|
+
== Table of contents
|
6
|
+
|
7
|
+
- {Installation}[#label-Installation]
|
8
|
+
- {Resources}[#label-Resources]
|
9
|
+
- {Goals}[#label-Goals]
|
10
|
+
- {Usage}[#label-Usage]
|
11
|
+
- {Running the application}[#label-Running+the+Application]
|
12
|
+
- {The routing tree}[#label-The+Routing+Tree]
|
13
|
+
- {Matchers}[#label-Matchers]
|
14
|
+
- {Optional segments}[#label-Optional+segments]
|
15
|
+
- {Match/Route Block Return Values}[#label-Match-2FRoute+Block+Return+Values]
|
16
|
+
- {Status codes}[#label-Status+Codes]
|
17
|
+
- {Verb methods}[#label-Verb+Methods]
|
18
|
+
- {Root method}[#label-Root+Method]
|
19
|
+
- {Request and Response}[#label-Request+and+Response]
|
20
|
+
- {Pollution}[#label-Pollution]
|
21
|
+
- {Composition}[#label-Composition]
|
22
|
+
- {Testing}[#label-Testing]
|
23
|
+
- {Settings}[#label-Settings]
|
24
|
+
- {Rendering}[#label-Rendering]
|
25
|
+
- {Security}[#label-Security]
|
26
|
+
- {Code Reloading}[#label-Code+Reloading]
|
27
|
+
- {Plugins}[#label-Plugins]
|
28
|
+
- {No introspection}[#label-No+Introspection]
|
29
|
+
- {Inspiration}[#label-Inspiration]
|
30
|
+
- {Ruby Support Policy}[#label-Ruby+Support+Policy]
|
31
|
+
|
32
|
+
== Installation
|
7
33
|
|
8
34
|
$ gem install roda
|
9
35
|
|
@@ -140,13 +166,11 @@ for every request.
|
|
140
166
|
== Running the Application
|
141
167
|
|
142
168
|
Running a Roda application is similar to running any other rack-based application
|
143
|
-
that uses a +config.ru+ file. You can start a basic server using +rackup
|
169
|
+
that uses a +config.ru+ file. You can start a basic server using +rackup+, +puma+,
|
170
|
+
+unicorn+, +passenger+, or any other webserver that can handle +config.ru+ files:
|
144
171
|
|
145
172
|
$ rackup
|
146
173
|
|
147
|
-
Ruby web servers such as Unicorn and Puma also ship with their own programs
|
148
|
-
that you can use to run a Roda application.
|
149
|
-
|
150
174
|
== The Routing Tree
|
151
175
|
|
152
176
|
Roda is called a routing tree web toolkit because the way most sites are structured,
|
@@ -454,7 +478,7 @@ shared branch:
|
|
454
478
|
|
455
479
|
This works well for many cases, but there are also cases where you really want to
|
456
480
|
treat it as one route with an optional segment. One simple way to do that is to
|
457
|
-
use a parameter instead of an optional segment (e.g.
|
481
|
+
use a parameter instead of an optional segment (e.g. <tt>/items/123?opt=456</tt>).
|
458
482
|
|
459
483
|
r.is "items", Integer do |item_id|
|
460
484
|
optional_data = r.params['opt'].to_s
|
@@ -647,14 +671,14 @@ If you have a lot of rack applications that you want to dispatch to, and
|
|
647
671
|
which one to dispatch to is based on the request path prefix, look into the
|
648
672
|
+multi_run+ plugin.
|
649
673
|
|
650
|
-
===
|
674
|
+
=== hash_branches plugin
|
651
675
|
|
652
676
|
If you are just looking to split up the main route block up by branches,
|
653
|
-
you should use the +
|
677
|
+
you should use the +hash_branches+ plugin,
|
654
678
|
which keeps the current scope of the +route+ block:
|
655
679
|
|
656
680
|
class App < Roda
|
657
|
-
plugin :
|
681
|
+
plugin :hash_branches
|
658
682
|
|
659
683
|
hash_branch "api" do |r|
|
660
684
|
r.is do
|
@@ -663,7 +687,7 @@ which keeps the current scope of the +route+ block:
|
|
663
687
|
end
|
664
688
|
|
665
689
|
route do |r|
|
666
|
-
r.
|
690
|
+
r.hash_branches
|
667
691
|
end
|
668
692
|
end
|
669
693
|
|
@@ -1120,3 +1144,4 @@ MIT
|
|
1120
1144
|
== Maintainer
|
1121
1145
|
|
1122
1146
|
Jeremy Evans <code@jeremyevans.net>
|
1147
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A link_to plugin has been added with a link_to method for
|
4
|
+
creating HTML links.
|
5
|
+
|
6
|
+
The simplest usage of link_to is passing the body and the location
|
7
|
+
to link to as strings:
|
8
|
+
|
9
|
+
# Instance level
|
10
|
+
link_to("body", "/path")
|
11
|
+
# => "<a href=\"/path\">body</a>"
|
12
|
+
|
13
|
+
The link_to plugin depends on the path plugin, and allows you to
|
14
|
+
pass symbols for named paths:
|
15
|
+
|
16
|
+
# Class level
|
17
|
+
path :foo, "/path/to/too"
|
18
|
+
|
19
|
+
# Instance level
|
20
|
+
link_to("body", :foo)
|
21
|
+
# => "<a href=\"/path/to/foo\">body</a>"
|
22
|
+
|
23
|
+
It also allows you to pass instances of classes that you have
|
24
|
+
registered with the path plugin:
|
25
|
+
|
26
|
+
# Class level
|
27
|
+
A = Struct.new(:id)
|
28
|
+
path A do
|
29
|
+
"/path/to/a/#{id}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Instance level
|
33
|
+
link_to("body", A.new(1))
|
34
|
+
# => "<a href=\"/path/to/a/1\">body</a>"
|
35
|
+
|
36
|
+
To set additional HTML attributes on the tag, you can pass them as
|
37
|
+
an options hash:
|
38
|
+
|
39
|
+
link_to("body", "/path", foo: "bar")
|
40
|
+
# => "<a href=\"/path\" foo=\"bar\">body</a>"
|
41
|
+
|
42
|
+
If the body is nil, it will be set to the same as the path:
|
43
|
+
|
44
|
+
link_to(nil, "/path")
|
45
|
+
# => "<a href=\"/path\">/path</a>"
|
46
|
+
|
47
|
+
The plugin will automatically HTML escape the path and any HTML
|
48
|
+
attribute values, using the h plugin:
|
49
|
+
|
50
|
+
link_to("body", "/path?a=1&b=2", foo: '"bar"')
|
51
|
+
# => "<a href=\"/path?a=1&b=2\" foo=\""bar"\">body</a>"
|
52
|
+
|
53
|
+
= Other Improvements
|
54
|
+
|
55
|
+
* Coverage testing has been expanded to multiple rack versions, instead
|
56
|
+
of just the current rack release.
|
@@ -0,0 +1,24 @@
|
|
1
|
+
= Improvements
|
2
|
+
|
3
|
+
* The typecast_params plugin now limits input bytesize for integer,
|
4
|
+
float, and date/time typecasts. If the input is over the allowed
|
5
|
+
bytesize, typecasting will fail. This prevents issues with trying
|
6
|
+
to typecast arbitrarily large input.
|
7
|
+
|
8
|
+
* The default Integer class matcher now limits integer segments to
|
9
|
+
100 characters by default, also to prevent issues with typecasting
|
10
|
+
arbitrarily large input. Segments larger than 100 characters will
|
11
|
+
no longer be matched by the Integer class matcher.
|
12
|
+
|
13
|
+
= Backwards Compatibility
|
14
|
+
|
15
|
+
* If the input bytesize limits in the typecast_params plugin cause
|
16
|
+
issues in your application, you can use the :skip_bytesize_checking
|
17
|
+
option when loading the plugin to disable the checks.
|
18
|
+
|
19
|
+
* If the default Integer class matcher limit causes problems in your
|
20
|
+
application, you can use the class_matchers plugin to override the
|
21
|
+
matcher to not use a limit:
|
22
|
+
|
23
|
+
plugin :class_matchers
|
24
|
+
class_matcher(Integer, /(\d+)/){|a| [a.to_i]}
|
@@ -52,7 +52,7 @@ class Roda
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
elsif matcher == Integer
|
55
|
-
if matchdata = /\A\/(\d
|
55
|
+
if matchdata = /\A\/(\d{1,100})(?=\/|\z)/.match(@remaining_path)
|
56
56
|
@remaining_path = matchdata.post_match
|
57
57
|
always{yield(matchdata[1].to_i)}
|
58
58
|
end
|
@@ -151,7 +151,7 @@ class Roda
|
|
151
151
|
always{yield rp[1, len]}
|
152
152
|
end
|
153
153
|
elsif matcher == Integer
|
154
|
-
if matchdata = /\A\/(\d
|
154
|
+
if matchdata = /\A\/(\d{1,100})\z/.match(@remaining_path)
|
155
155
|
@remaining_path = ''
|
156
156
|
always{yield(matchdata[1].to_i)}
|
157
157
|
end
|
@@ -34,9 +34,7 @@ class Roda
|
|
34
34
|
module AllVerbs
|
35
35
|
module RequestMethods
|
36
36
|
%w'delete head options link patch put trace unlink'.each do |verb|
|
37
|
-
# :nocov:
|
38
37
|
if ::Rack::Request.method_defined?("#{verb}?")
|
39
|
-
# :nocov:
|
40
38
|
class_eval(<<-END, __FILE__, __LINE__+1)
|
41
39
|
def #{verb}(*args, &block)
|
42
40
|
_verb(args, &block) if #{verb}?
|
@@ -11,7 +11,7 @@ class Roda
|
|
11
11
|
# * Doesn't include middleware timing
|
12
12
|
# * Doesn't proxy the body
|
13
13
|
# * Doesn't support different capitalization of the Content-Length response header
|
14
|
-
# * Logs to
|
14
|
+
# * Logs to +$stderr+ instead of <tt>env['rack.errors']</tt> if explicit logger not passed
|
15
15
|
#
|
16
16
|
# Example:
|
17
17
|
#
|
@@ -52,14 +52,12 @@ class Roda
|
|
52
52
|
end
|
53
53
|
|
54
54
|
class Params < Rack::QueryParser::Params
|
55
|
-
|
56
|
-
if Rack.release >= '2.3'
|
55
|
+
if Rack.release >= '3'
|
57
56
|
def initialize
|
58
57
|
@size = 0
|
59
58
|
@params = Hash.new(&INDIFFERENT_PROC)
|
60
59
|
end
|
61
60
|
else
|
62
|
-
# :nocov:
|
63
61
|
def initialize(limit = Rack::Utils.key_space_limit)
|
64
62
|
@limit = limit
|
65
63
|
@size = 0
|
@@ -71,9 +69,7 @@ class Roda
|
|
71
69
|
end
|
72
70
|
|
73
71
|
module RequestMethods
|
74
|
-
|
75
|
-
query_parser = Rack.release >= '2.3' ? QueryParser.new(QueryParser::Params, 32) : QueryParser.new(QueryParser::Params, 65536, 32)
|
76
|
-
# :nocov:
|
72
|
+
query_parser = Rack.release >= '3' ? QueryParser.new(QueryParser::Params, 32) : QueryParser.new(QueryParser::Params, 65536, 32)
|
77
73
|
QUERY_PARSER = Rack::Utils.default_query_parser = query_parser
|
78
74
|
|
79
75
|
private
|
@@ -89,7 +85,6 @@ class Roda
|
|
89
85
|
end
|
90
86
|
end
|
91
87
|
else
|
92
|
-
# :nocov:
|
93
88
|
module InstanceMethods
|
94
89
|
# A copy of the request params that will automatically
|
95
90
|
# convert symbols to strings.
|
@@ -115,7 +110,6 @@ class Roda
|
|
115
110
|
end
|
116
111
|
end
|
117
112
|
end
|
118
|
-
# :nocov:
|
119
113
|
end
|
120
114
|
end
|
121
115
|
|
@@ -86,12 +86,10 @@ class Roda
|
|
86
86
|
|
87
87
|
|
88
88
|
# Rack 3 dropped requirement that input be rewindable
|
89
|
-
if Rack.release >= '
|
90
|
-
# :nocov:
|
89
|
+
if Rack.release >= '3'
|
91
90
|
def _read_json_input(input)
|
92
91
|
input.read
|
93
92
|
end
|
94
|
-
# :nocov:
|
95
93
|
else
|
96
94
|
def _read_json_input(input)
|
97
95
|
input.rewind
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The link_to plugin adds the +link_to+ instance method, which can be used for constructing
|
7
|
+
# HTML links (+a+ tag with +href+ attribute).
|
8
|
+
#
|
9
|
+
# The simplest usage of +link_to+ is passing the body and the location to link to as strings:
|
10
|
+
#
|
11
|
+
# link_to("body", "/path")
|
12
|
+
# # => "<a href=\"/path\">body</a>"
|
13
|
+
#
|
14
|
+
# The link_to plugin depends on the path plugin, and allows you to pass symbols for named paths:
|
15
|
+
#
|
16
|
+
# # Class level
|
17
|
+
# path :foo, "/path/to/too"
|
18
|
+
#
|
19
|
+
# # Instance level
|
20
|
+
# link_to("body", :foo)
|
21
|
+
# # => "<a href=\"/path/to/foo\">body</a>"
|
22
|
+
#
|
23
|
+
# It also allows you to pass instances of classes that you have registered with the path plugin:
|
24
|
+
#
|
25
|
+
# # Class level
|
26
|
+
# A = Struct.new(:id)
|
27
|
+
# path A do
|
28
|
+
# "/path/to/a/#{id}"
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# # Instance level
|
32
|
+
# link_to("body", A.new(1))
|
33
|
+
# # => "<a href=\"/path/to/a/1\">body</a>"
|
34
|
+
#
|
35
|
+
# To set additional HTML attributes on the +a+ tag, you can pass them as an options hash:
|
36
|
+
#
|
37
|
+
# link_to("body", "/path", foo: "bar")
|
38
|
+
# # => "<a href=\"/path\" foo=\"bar\">body</a>"
|
39
|
+
#
|
40
|
+
# If the body is nil, it will be set to the same as the path:
|
41
|
+
#
|
42
|
+
# link_to(nil, "/path")
|
43
|
+
# # => "<a href=\"/path\">/path</a>"
|
44
|
+
#
|
45
|
+
# The plugin will automatically HTML escape the path and any HTML attribute values, using the h plugin:
|
46
|
+
#
|
47
|
+
# link_to("body", "/path?a=1&b=2", foo: '"bar"')
|
48
|
+
# # => "<a href=\"/path?a=1&b=2\" foo=\""bar"\">body</a>"
|
49
|
+
module LinkTo
|
50
|
+
def self.load_dependencies(app)
|
51
|
+
app.plugin :h
|
52
|
+
app.plugin :path
|
53
|
+
end
|
54
|
+
|
55
|
+
module InstanceMethods
|
56
|
+
# Return a string with an HTML +a+ tag with an +href+ attribute. See LinkTo
|
57
|
+
# module documentation for details.
|
58
|
+
def link_to(body, href, attributes=OPTS)
|
59
|
+
case href
|
60
|
+
when Symbol
|
61
|
+
href = public_send(:"#{href}_path")
|
62
|
+
when String
|
63
|
+
# nothing
|
64
|
+
else
|
65
|
+
href = path(href)
|
66
|
+
end
|
67
|
+
|
68
|
+
href = h(href)
|
69
|
+
|
70
|
+
body = href if body.nil?
|
71
|
+
|
72
|
+
buf = String.new << "<a href=\"#{href}\""
|
73
|
+
attributes.each do |k, v|
|
74
|
+
buf << " " << k.to_s << "=\"" << h(v) << "\""
|
75
|
+
end
|
76
|
+
buf << ">" << body << "</a>"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
register_plugin(:link_to, LinkTo)
|
82
|
+
end
|
83
|
+
end
|
@@ -3,9 +3,7 @@
|
|
3
3
|
begin
|
4
4
|
require 'rack/files'
|
5
5
|
rescue LoadError
|
6
|
-
# :nocov:
|
7
6
|
require 'rack/file'
|
8
|
-
# :nocov:
|
9
7
|
end
|
10
8
|
|
11
9
|
#
|
@@ -66,9 +64,7 @@ class Roda
|
|
66
64
|
# end
|
67
65
|
# end
|
68
66
|
module MultiPublic
|
69
|
-
# :nocov:
|
70
67
|
RACK_FILES = defined?(Rack::Files) ? Rack::Files : Rack::File
|
71
|
-
# :nocov:
|
72
68
|
|
73
69
|
def self.load_dependencies(app, _, opts=OPTS)
|
74
70
|
app.plugin(:public, opts)
|
@@ -116,9 +116,7 @@ class Roda
|
|
116
116
|
# arguments, record the verb used. If given an argument, add an is
|
117
117
|
# check with the arguments.
|
118
118
|
%w'get post delete head options link patch put trace unlink'.each do |verb|
|
119
|
-
# :nocov:
|
120
119
|
if ::Rack::Request.method_defined?("#{verb}?")
|
121
|
-
# :nocov:
|
122
120
|
class_eval(<<-END, __FILE__, __LINE__+1)
|
123
121
|
def #{verb}(*args, &block)
|
124
122
|
if (empty = args.empty?) && @_is_verbs
|
data/lib/roda/plugins/public.rb
CHANGED
@@ -5,9 +5,7 @@ require 'uri'
|
|
5
5
|
begin
|
6
6
|
require 'rack/files'
|
7
7
|
rescue LoadError
|
8
|
-
# :nocov:
|
9
8
|
require 'rack/file'
|
10
|
-
# :nocov:
|
11
9
|
end
|
12
10
|
|
13
11
|
#
|
@@ -45,9 +43,7 @@ class Roda
|
|
45
43
|
module Public
|
46
44
|
SPLIT = Regexp.union(*[File::SEPARATOR, File::ALT_SEPARATOR].compact)
|
47
45
|
PARSER = URI::DEFAULT_PARSER
|
48
|
-
# :nocov:
|
49
46
|
RACK_FILES = defined?(Rack::Files) ? Rack::Files : Rack::File
|
50
|
-
# :nocov:
|
51
47
|
|
52
48
|
# Use options given to setup a Rack::File instance for serving files. Options:
|
53
49
|
# :default_mime :: The default mime type to use if the mime type is not recognized.
|
@@ -142,13 +138,11 @@ class Roda
|
|
142
138
|
server.serving(self, path)
|
143
139
|
end
|
144
140
|
else
|
145
|
-
# :nocov:
|
146
141
|
def public_serve(server, path)
|
147
142
|
server = server.dup
|
148
143
|
server.path = path
|
149
144
|
server.serving(env)
|
150
145
|
end
|
151
|
-
# :nocov:
|
152
146
|
end
|
153
147
|
end
|
154
148
|
end
|
data/lib/roda/plugins/render.rb
CHANGED
@@ -214,18 +214,18 @@ class Roda
|
|
214
214
|
tilt_compiled_method_support = defined?(Tilt::VERSION) && Tilt::VERSION >= '1.2' &&
|
215
215
|
([1, -2].include?(((compiled_method_arity = Tilt::Template.instance_method(:compiled_method).arity) rescue false)))
|
216
216
|
NO_CACHE = {:cache=>false}.freeze
|
217
|
-
COMPILED_METHOD_SUPPORT = RUBY_VERSION >= '2.3' && tilt_compiled_method_support
|
217
|
+
COMPILED_METHOD_SUPPORT = RUBY_VERSION >= '2.3' && tilt_compiled_method_support && ENV['RODA_RENDER_COMPILED_METHOD_SUPPORT'] != 'no'
|
218
218
|
|
219
219
|
if compiled_method_arity == -2
|
220
220
|
def self.tilt_template_compiled_method(template, locals_keys, scope_class)
|
221
221
|
template.send(:compiled_method, locals_keys, scope_class)
|
222
222
|
end
|
223
|
+
# :nocov:
|
223
224
|
else
|
224
|
-
# :nocov:
|
225
225
|
def self.tilt_template_compiled_method(template, locals_keys, scope_class)
|
226
226
|
template.send(:compiled_method, locals_keys)
|
227
227
|
end
|
228
|
-
|
228
|
+
# :nocov:
|
229
229
|
end
|
230
230
|
|
231
231
|
# Setup default rendering options. See Render for details.
|
@@ -366,9 +366,7 @@ class Roda
|
|
366
366
|
false
|
367
367
|
end
|
368
368
|
|
369
|
-
# :nocov:
|
370
369
|
if COMPILED_METHOD_SUPPORT
|
371
|
-
# :nocov:
|
372
370
|
# Compile a method in the given module with the given name that will
|
373
371
|
# call the compiled template method, updating the compiled template method
|
374
372
|
def define_compiled_method(roda_class, method_name, locals_keys=EMPTY_ARRAY)
|
@@ -412,9 +410,7 @@ class Roda
|
|
412
410
|
end
|
413
411
|
|
414
412
|
module ClassMethods
|
415
|
-
# :nocov:
|
416
413
|
if COMPILED_METHOD_SUPPORT
|
417
|
-
# :nocov:
|
418
414
|
# If using compiled methods and there is an optimized layout, speed up
|
419
415
|
# access to the layout method to improve the performance of view.
|
420
416
|
def freeze
|
@@ -437,9 +433,7 @@ class Roda
|
|
437
433
|
def inherited(subclass)
|
438
434
|
super
|
439
435
|
opts = subclass.opts[:render] = subclass.opts[:render].dup
|
440
|
-
# :nocov:
|
441
436
|
if COMPILED_METHOD_SUPPORT
|
442
|
-
# :nocov:
|
443
437
|
opts[:template_method_cache] = (opts[:cache_class] || RodaCache).new
|
444
438
|
end
|
445
439
|
opts[:cache] = opts[:cache].dup
|
@@ -459,9 +453,7 @@ class Roda
|
|
459
453
|
instance = allocate
|
460
454
|
instance.send(:retrieve_template, instance.send(:view_layout_opts, OPTS))
|
461
455
|
|
462
|
-
# :nocov:
|
463
456
|
if COMPILED_METHOD_SUPPORT
|
464
|
-
# :nocov:
|
465
457
|
if (layout_template = render_opts[:optimize_layout]) && !opts[:render][:optimized_layout_method_created]
|
466
458
|
instance.send(:retrieve_template, :template=>layout_template, :cache_key=>nil, :template_method_cache_key => :_roda_layout)
|
467
459
|
layout_method = opts[:render][:template_method_cache][:_roda_layout]
|
@@ -610,7 +602,6 @@ class Roda
|
|
610
602
|
end
|
611
603
|
end
|
612
604
|
else
|
613
|
-
# :nocov:
|
614
605
|
def _cached_template_method(_)
|
615
606
|
nil
|
616
607
|
end
|
@@ -630,7 +621,6 @@ class Roda
|
|
630
621
|
def _optimized_view_content(template)
|
631
622
|
nil
|
632
623
|
end
|
633
|
-
# :nocov:
|
634
624
|
end
|
635
625
|
|
636
626
|
|
@@ -43,9 +43,7 @@ class Roda
|
|
43
43
|
module InstanceMethods
|
44
44
|
private
|
45
45
|
|
46
|
-
# :nocov:
|
47
46
|
if Render::COMPILED_METHOD_SUPPORT
|
48
|
-
# :nocov:
|
49
47
|
# Disable use of cached templates, since it assumes a render/view call with no
|
50
48
|
# options will have no locals.
|
51
49
|
def _cached_template_method(template)
|
@@ -4,9 +4,7 @@ require 'rack/mime'
|
|
4
4
|
begin
|
5
5
|
require 'rack/files'
|
6
6
|
rescue LoadError
|
7
|
-
# :nocov:
|
8
7
|
require 'rack/file'
|
9
|
-
# :nocov:
|
10
8
|
end
|
11
9
|
|
12
10
|
|
@@ -225,9 +223,7 @@ class Roda
|
|
225
223
|
ISO88591_ENCODING = Encoding.find('ISO-8859-1')
|
226
224
|
BINARY_ENCODING = Encoding.find('BINARY')
|
227
225
|
|
228
|
-
# :nocov:
|
229
226
|
RACK_FILES = defined?(Rack::Files) ? Rack::Files : Rack::File
|
230
|
-
# :nocov:
|
231
227
|
|
232
228
|
# Depend on the status_303 plugin.
|
233
229
|
def self.load_dependencies(app, _opts = nil)
|
@@ -351,10 +347,8 @@ class Roda
|
|
351
347
|
s, h, b = if Rack.release > '2'
|
352
348
|
file.serving(self, path)
|
353
349
|
else
|
354
|
-
# :nocov:
|
355
350
|
file.path = path
|
356
351
|
file.serving(@env)
|
357
|
-
# :nocov:
|
358
352
|
end
|
359
353
|
|
360
354
|
res.status = opts[:status] || s
|
@@ -45,11 +45,9 @@ class Roda
|
|
45
45
|
when nil, false
|
46
46
|
CLEAR_HEADERS
|
47
47
|
when Array
|
48
|
-
|
49
|
-
if Rack.release >= '2.3'
|
48
|
+
if Rack.release >= '3'
|
50
49
|
keep_headers = keep_headers.map(&:downcase)
|
51
50
|
end
|
52
|
-
# :nocov:
|
53
51
|
lambda{|headers| headers.delete_if{|k,_| !keep_headers.include?(k)}}
|
54
52
|
else
|
55
53
|
raise RodaError, "Invalid :keep_headers option"
|
@@ -5,34 +5,26 @@ require 'time'
|
|
5
5
|
|
6
6
|
class Roda
|
7
7
|
module RodaPlugins
|
8
|
-
# The typecast_params plugin allows for
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# cases it makes sense to explicitly convert the parameter to the
|
8
|
+
# The typecast_params plugin allows for type conversion of submitted parameters.
|
9
|
+
# Submitted parameters should be considered untrusted input, and in standard use
|
10
|
+
# with browsers, parameters are # submitted as strings (or a hash/array containing
|
11
|
+
# strings). In most # cases it makes sense to explicitly convert the parameter to the
|
13
12
|
# desired type. While this can be done via manual conversion:
|
14
13
|
#
|
15
|
-
#
|
16
|
-
#
|
14
|
+
# val = request.params['key'].to_i
|
15
|
+
# val = nil unless val > 0
|
17
16
|
#
|
18
17
|
# the typecast_params plugin adds a friendlier interface:
|
19
18
|
#
|
20
|
-
#
|
19
|
+
# val = typecast_params.pos_int('key')
|
21
20
|
#
|
22
|
-
# As +typecast_params+ is a fairly long method name,
|
23
|
-
# consider aliasing it to something more terse in your
|
24
|
-
# such as +tp+.
|
25
|
-
#
|
26
|
-
# One advantage of using typecast_params is that access or conversion
|
27
|
-
# errors are raised as a specific exception class
|
28
|
-
# (+Roda::RodaPlugins::TypecastParams::Error+). This allows you to handle
|
29
|
-
# this specific exception class globally and return an appropriate 4xx
|
30
|
-
# response to the client. You can use the Error#param_name and Error#reason
|
31
|
-
# methods to get more information about the error.
|
21
|
+
# As +typecast_params+ is a fairly long method name, and may be a method you call
|
22
|
+
# frequently, you may want to consider aliasing it to something more terse in your
|
23
|
+
# application, such as +tp+.
|
32
24
|
#
|
33
25
|
# typecast_params offers support for default values:
|
34
26
|
#
|
35
|
-
#
|
27
|
+
# val = typecast_params.pos_int('key', 1)
|
36
28
|
#
|
37
29
|
# The default value is only used if no value has been submitted for the parameter,
|
38
30
|
# or if the conversion of the value results in +nil+. Handling defaults for parameter
|
@@ -43,35 +35,41 @@ class Roda
|
|
43
35
|
# In many cases, parameters should be required, and if they aren't submitted, that
|
44
36
|
# should be considered an error. typecast_params handles this with ! methods:
|
45
37
|
#
|
46
|
-
#
|
38
|
+
# val = typecast_params.pos_int!('key')
|
47
39
|
#
|
48
40
|
# These ! methods raise an error instead of returning +nil+, and do not allow defaults.
|
49
41
|
#
|
42
|
+
# The errors raised by this plugin use a specific exception class,
|
43
|
+
# +Roda::RodaPlugins::TypecastParams::Error+. This allows you to handle
|
44
|
+
# this specific exception class globally and return an appropriate 4xx
|
45
|
+
# response to the client. You can use the Error#param_name and Error#reason
|
46
|
+
# methods to get more information about the error.
|
47
|
+
#
|
50
48
|
# To make it easy to handle cases where many parameters need the same conversion
|
51
49
|
# done, you can pass an array of keys to a conversion method, and it will return an array
|
52
50
|
# of converted values:
|
53
51
|
#
|
54
|
-
#
|
52
|
+
# val1, val2 = typecast_params.pos_int(['key1', 'key2'])
|
55
53
|
#
|
56
54
|
# This is equivalent to:
|
57
55
|
#
|
58
|
-
#
|
59
|
-
#
|
56
|
+
# val1 = typecast_params.pos_int('key1')
|
57
|
+
# val2 = typecast_params.pos_int('key2')
|
60
58
|
#
|
61
59
|
# The ! methods also support arrays, ensuring that all parameters have a value:
|
62
60
|
#
|
63
|
-
#
|
61
|
+
# val1, val2 = typecast_params.pos_int!(['key1', 'key2'])
|
64
62
|
#
|
65
63
|
# For handling of array parameters, where all entries in the array use the
|
66
64
|
# same conversion, there is an +array+ method which takes the type as the first argument
|
67
65
|
# and the keys to convert as the second argument:
|
68
66
|
#
|
69
|
-
#
|
67
|
+
# vals = typecast_params.array(:pos_int, 'keys')
|
70
68
|
#
|
71
69
|
# If you want to ensure that all entries in the array are converted successfully and that
|
72
70
|
# there is a value for the array itself, you can use +array!+:
|
73
71
|
#
|
74
|
-
#
|
72
|
+
# vals = typecast_params.array!(:pos_int, 'keys')
|
75
73
|
#
|
76
74
|
# This will raise an exception if any of the values in the array for parameter +keys+ cannot
|
77
75
|
# be converted to integer.
|
@@ -79,8 +77,8 @@ class Roda
|
|
79
77
|
# Both +array+ and +array!+ support default values which are used if no value is present
|
80
78
|
# for the parameter:
|
81
79
|
#
|
82
|
-
#
|
83
|
-
#
|
80
|
+
# vals1 = typecast_params.array(:pos_int, 'keys1', [])
|
81
|
+
# vals2 = typecast_params.array!(:pos_int, 'keys2', [])
|
84
82
|
#
|
85
83
|
# You can also pass an array of keys to +array+ or +array!+, if you would like to perform
|
86
84
|
# the same conversion on multiple arrays:
|
@@ -88,7 +86,7 @@ class Roda
|
|
88
86
|
# foo_ids, bar_ids = typecast_params.array!(:pos_int, ['foo_ids', 'bar_ids'])
|
89
87
|
#
|
90
88
|
# The previous examples have shown use of the +pos_int+ method, which uses +to_i+ to convert the
|
91
|
-
# value to an integer, but returns nil if the resulting integer is not positive. Unless you need
|
89
|
+
# value to an integer, but returns +nil+ if the resulting integer is not positive. Unless you need
|
92
90
|
# to handle negative numbers, it is recommended to use +pos_int+ instead of +int+ as +int+ will
|
93
91
|
# convert invalid values to 0 (since that is how <tt>String#to_i</tt> works).
|
94
92
|
#
|
@@ -224,10 +222,10 @@ class Roda
|
|
224
222
|
# # }
|
225
223
|
#
|
226
224
|
# Using the +:symbolize+ option makes it simpler to transition from untrusted external
|
227
|
-
# data (string keys), to
|
228
|
-
# the expected types are used).
|
225
|
+
# data (string keys), to semitrusted data that can be used internally (trusted in the sense that
|
226
|
+
# the expected types are used, not that you trust the values).
|
229
227
|
#
|
230
|
-
# Note that if there are multiple conversion
|
228
|
+
# Note that if there are multiple conversion errors raised inside a +convert!+ or +convert_each!+
|
231
229
|
# block, they are recorded and a single TypecastParams::Error instance is raised after
|
232
230
|
# processing the block. TypecastParams::Error#param_names can be called on the exception to
|
233
231
|
# get an array of all parameter names with conversion issues, and TypecastParams::Error#all_errors
|
@@ -245,14 +243,18 @@ class Roda
|
|
245
243
|
# specific to the Roda application. You can add support for custom types by passing a block
|
246
244
|
# when loading the typecast_params plugin. This block is executed in the context of the
|
247
245
|
# subclass, and calling +handle_type+ in the block can be used to add conversion methods.
|
248
|
-
# +handle_type+ accepts a type name and the block used to convert the type
|
246
|
+
# +handle_type+ accepts a type name, an options hash, and the block used to convert the type.
|
247
|
+
# The only currently supported option is +:max_input_bytesize+, specifying the maximum bytesize of
|
248
|
+
# string input. You can also override the max input bytesize of an existing type using the
|
249
|
+
# +max_input_bytesize+ method.
|
249
250
|
#
|
250
251
|
# plugin :typecast_params do
|
251
|
-
# handle_type(:album) do |value|
|
252
|
+
# handle_type(:album, max_input_bytesize: 100) do |value|
|
252
253
|
# if id = convert_pos_int(val)
|
253
254
|
# Album[id]
|
254
255
|
# end
|
255
256
|
# end
|
257
|
+
# max_input_bytesize(:date, 256)
|
256
258
|
# end
|
257
259
|
#
|
258
260
|
# By default, the typecast_params conversion procs are passed the parameter value directly
|
@@ -260,10 +262,18 @@ class Roda
|
|
260
262
|
# strip leading and trailing whitespace from parameter string values before processing, which
|
261
263
|
# you can do by passing the <tt>strip: :all</tt> option when loading the plugin.
|
262
264
|
#
|
263
|
-
# By default, the
|
264
|
-
#
|
265
|
+
# By default, the typecasting methods for some types check whether the bytesize of input
|
266
|
+
# strings is over the maximum expected values, and raise an error in such cases. The input
|
267
|
+
# bytesize is checked prior to any type conversion. If you would like to skip this check
|
268
|
+
# and allow any bytesize when doing type conversion for param string values, you can do so by
|
269
|
+
# passing the # <tt>:skip_bytesize_checking</tt> option when loading the plugin. By default,
|
270
|
+
# there is an 100 byte limit on integer input, an 1000 byte input on float input, and a 128
|
271
|
+
# byte limit on date/time input.
|
272
|
+
#
|
273
|
+
# By default, the typecasting methods check whether input strings have null bytes, and raise
|
274
|
+
# an error in such cases. This check for null bytes occurs prior to any type conversion.
|
265
275
|
# If you would like to skip this check and allow null bytes in param string values,
|
266
|
-
# you can do by passing the <tt>:allow_null_bytes</tt> option when loading the plugin.
|
276
|
+
# you can do so by passing the <tt>:allow_null_bytes</tt> option when loading the plugin.
|
267
277
|
#
|
268
278
|
# You can use the :date_parse_input_handler option to specify custom handling of date
|
269
279
|
# parsing input. Modern versions of Ruby and the date gem internally raise if the input to
|
@@ -282,6 +292,11 @@ class Roda
|
|
282
292
|
# string.b[0, 128]
|
283
293
|
# }
|
284
294
|
#
|
295
|
+
# The +date_parse_input_handler+ is only called if the value is under the max input
|
296
|
+
# bytesize, so you may need to call +max_input_bytesize+ for the +:date+, +:time+, and
|
297
|
+
# +:datetime+ methods to override the max input bytesize if you want to use this option
|
298
|
+
# for input strings over 128 bytes.
|
299
|
+
#
|
285
300
|
# By design, typecast_params only deals with string keys, it is not possible to use
|
286
301
|
# symbol keys as arguments to the conversion methods and have them converted.
|
287
302
|
module TypecastParams
|
@@ -409,6 +424,14 @@ class Roda
|
|
409
424
|
end
|
410
425
|
end
|
411
426
|
|
427
|
+
module SkipBytesizeChecking
|
428
|
+
private
|
429
|
+
|
430
|
+
# Do not check max input bytesize
|
431
|
+
def check_allowed_bytesize(v, max)
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
412
435
|
# Class handling conversion of submitted parameters to desired types.
|
413
436
|
class Params
|
414
437
|
# Handle conversions for the given type using the given block.
|
@@ -422,23 +445,29 @@ class Roda
|
|
422
445
|
# This method is used to define all type conversions, even the built
|
423
446
|
# in ones. It can be called in subclasses to setup subclass-specific
|
424
447
|
# types.
|
425
|
-
def self.handle_type(type, &block)
|
448
|
+
def self.handle_type(type, opts=OPTS, &block)
|
426
449
|
convert_meth = :"convert_#{type}"
|
427
450
|
define_method(convert_meth, &block)
|
428
451
|
|
452
|
+
max_input_bytesize = opts[:max_input_bytesize]
|
453
|
+
max_input_bytesize_meth = :"_max_input_bytesize_for_#{type}"
|
454
|
+
define_method(max_input_bytesize_meth){max_input_bytesize}
|
455
|
+
|
429
456
|
convert_array_meth = :"_convert_array_#{type}"
|
430
457
|
define_method(convert_array_meth) do |v|
|
431
458
|
raise Error, "expected array but received #{v.inspect}" unless v.is_a?(Array)
|
432
459
|
v.map! do |val|
|
460
|
+
check_allowed_bytesize(val, send(max_input_bytesize_meth))
|
433
461
|
check_null_byte(val)
|
434
462
|
send(convert_meth, val)
|
435
463
|
end
|
436
464
|
end
|
437
465
|
|
438
|
-
private convert_meth, convert_array_meth
|
466
|
+
private convert_meth, convert_array_meth, max_input_bytesize_meth
|
467
|
+
alias_method max_input_bytesize_meth, max_input_bytesize_meth
|
439
468
|
|
440
469
|
define_method(type) do |key, default=nil|
|
441
|
-
process_arg(convert_meth, key, default) if require_hash!
|
470
|
+
process_arg(convert_meth, key, default, send(max_input_bytesize_meth)) if require_hash!
|
442
471
|
end
|
443
472
|
|
444
473
|
define_method(:"#{type}!") do |key|
|
@@ -446,6 +475,15 @@ class Roda
|
|
446
475
|
end
|
447
476
|
end
|
448
477
|
|
478
|
+
# Override the maximum input bytesize for the given type. This is mostly useful
|
479
|
+
# for overriding the sizes for the default input types.
|
480
|
+
def self.max_input_bytesize(type, bytesize)
|
481
|
+
max_input_bytesize_meth = :"_max_input_bytesize_for_#{type}"
|
482
|
+
define_method(max_input_bytesize_meth){bytesize}
|
483
|
+
private max_input_bytesize_meth
|
484
|
+
alias_method max_input_bytesize_meth, max_input_bytesize_meth
|
485
|
+
end
|
486
|
+
|
449
487
|
# Create a new instance with the given object and nesting level.
|
450
488
|
# +obj+ should be an array or hash, and +nesting+ should be an
|
451
489
|
# array. Designed for internal use, should not be called by
|
@@ -485,17 +523,17 @@ class Roda
|
|
485
523
|
end
|
486
524
|
end
|
487
525
|
|
488
|
-
handle_type(:int) do |v|
|
526
|
+
handle_type(:int, :max_input_bytesize=>100) do |v|
|
489
527
|
string_or_numeric!(v) && v.to_i
|
490
528
|
end
|
491
529
|
|
492
|
-
handle_type(:pos_int) do |v|
|
530
|
+
handle_type(:pos_int, :max_input_bytesize=>100) do |v|
|
493
531
|
if (v = convert_int(v)) && v > 0
|
494
532
|
v
|
495
533
|
end
|
496
534
|
end
|
497
535
|
|
498
|
-
handle_type(:Integer) do |v|
|
536
|
+
handle_type(:Integer, :max_input_bytesize=>100) do |v|
|
499
537
|
if string_or_numeric!(v)
|
500
538
|
case v
|
501
539
|
when String
|
@@ -510,11 +548,11 @@ class Roda
|
|
510
548
|
end
|
511
549
|
end
|
512
550
|
|
513
|
-
handle_type(:float) do |v|
|
551
|
+
handle_type(:float, :max_input_bytesize=>1000) do |v|
|
514
552
|
string_or_numeric!(v) && v.to_f
|
515
553
|
end
|
516
554
|
|
517
|
-
handle_type(:Float) do |v|
|
555
|
+
handle_type(:Float, :max_input_bytesize=>1000) do |v|
|
518
556
|
string_or_numeric!(v) && ::Kernel::Float(v)
|
519
557
|
end
|
520
558
|
|
@@ -523,15 +561,15 @@ class Roda
|
|
523
561
|
v
|
524
562
|
end
|
525
563
|
|
526
|
-
handle_type(:date) do |v|
|
564
|
+
handle_type(:date, :max_input_bytesize=>128) do |v|
|
527
565
|
parse!(::Date, v)
|
528
566
|
end
|
529
567
|
|
530
|
-
handle_type(:time) do |v|
|
568
|
+
handle_type(:time, :max_input_bytesize=>128) do |v|
|
531
569
|
parse!(::Time, v)
|
532
570
|
end
|
533
571
|
|
534
|
-
handle_type(:datetime) do |v|
|
572
|
+
handle_type(:datetime, :max_input_bytesize=>128) do |v|
|
535
573
|
parse!(::DateTime, v)
|
536
574
|
end
|
537
575
|
|
@@ -712,7 +750,7 @@ class Roda
|
|
712
750
|
def array(type, key, default=nil)
|
713
751
|
meth = :"_convert_array_#{type}"
|
714
752
|
raise ProgrammerError, "no typecast_params type registered for #{type.inspect}" unless respond_to?(meth, true)
|
715
|
-
process_arg(meth, key, default) if require_hash!
|
753
|
+
process_arg(meth, key, default, send(:"_max_input_bytesize_for_#{type}")) if require_hash!
|
716
754
|
end
|
717
755
|
|
718
756
|
# Call +array+ with the +type+, +key+, and +default+, but if the return value is nil or any value in
|
@@ -945,10 +983,10 @@ class Roda
|
|
945
983
|
|
946
984
|
# If +key+ is not an array, convert the value at the given +key+ using the +meth+ method and +default+
|
947
985
|
# value. If +key+ is an array, return an array with the conversion done for each respective member of +key+.
|
948
|
-
def process_arg(meth, key, default)
|
986
|
+
def process_arg(meth, key, default, max_input_bytesize=nil)
|
949
987
|
case key
|
950
988
|
when String
|
951
|
-
v = process(meth, key, default)
|
989
|
+
v = process(meth, key, default, max_input_bytesize)
|
952
990
|
|
953
991
|
if @capture
|
954
992
|
key = key.to_sym if symbolize?
|
@@ -961,13 +999,20 @@ class Roda
|
|
961
999
|
when Array
|
962
1000
|
key.map do |k|
|
963
1001
|
raise ProgrammerError, "non-String element in array argument passed to typecast_params: #{k.inspect}" unless k.is_a?(String)
|
964
|
-
process_arg(meth, k, default)
|
1002
|
+
process_arg(meth, k, default, max_input_bytesize)
|
965
1003
|
end
|
966
1004
|
else
|
967
1005
|
raise ProgrammerError, "Unsupported argument for typecast_params conversion method: #{key.inspect}"
|
968
1006
|
end
|
969
1007
|
end
|
970
1008
|
|
1009
|
+
# Raise an Error if the value is a string with bytesize over max (if max is given)
|
1010
|
+
def check_allowed_bytesize(v, max)
|
1011
|
+
if max && v.is_a?(String) && v.bytesize > max
|
1012
|
+
handle_error(nil, :too_long, "string parameter is too long for type", true)
|
1013
|
+
end
|
1014
|
+
end
|
1015
|
+
|
971
1016
|
# Raise an Error if the value is a string containing a null byte.
|
972
1017
|
def check_null_byte(v)
|
973
1018
|
if v.is_a?(String) && v.index("\0")
|
@@ -977,10 +1022,11 @@ class Roda
|
|
977
1022
|
|
978
1023
|
# Get the value of +key+ for the object, and convert it to the expected type using +meth+.
|
979
1024
|
# If the value either before or after conversion is nil, return the +default+ value.
|
980
|
-
def process(meth, key, default)
|
1025
|
+
def process(meth, key, default, max_input_bytesize=nil)
|
981
1026
|
v = param_value(key)
|
982
1027
|
|
983
1028
|
unless v.nil?
|
1029
|
+
check_allowed_bytesize(v, max_input_bytesize)
|
984
1030
|
check_null_byte(v)
|
985
1031
|
v = send(meth, v)
|
986
1032
|
end
|
@@ -1049,6 +1095,9 @@ class Roda
|
|
1049
1095
|
if opts[:allow_null_bytes]
|
1050
1096
|
app::TypecastParams.send(:include, AllowNullByte)
|
1051
1097
|
end
|
1098
|
+
if opts[:skip_bytesize_checking]
|
1099
|
+
app::TypecastParams.send(:include, SkipBytesizeChecking)
|
1100
|
+
end
|
1052
1101
|
if opts[:date_parse_input_handler]
|
1053
1102
|
app::TypecastParams.class_eval do
|
1054
1103
|
include DateParseInputHandler
|
@@ -126,9 +126,7 @@ class Roda
|
|
126
126
|
|
127
127
|
private
|
128
128
|
|
129
|
-
# :nocov:
|
130
129
|
if Render::COMPILED_METHOD_SUPPORT
|
131
|
-
# :nocov:
|
132
130
|
# Return nil if using custom view or layout options.
|
133
131
|
# If using a view subdir, prefix the template key with the subdir.
|
134
132
|
def _cached_template_method_key(template)
|
data/lib/roda/request.rb
CHANGED
@@ -1,18 +1,16 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
|
-
# :nocov:
|
4
3
|
begin
|
5
4
|
require "rack/version"
|
6
5
|
rescue LoadError
|
7
6
|
require "rack"
|
8
7
|
else
|
9
|
-
if Rack.release >= '
|
8
|
+
if Rack.release >= '3'
|
10
9
|
require "rack/request"
|
11
10
|
else
|
12
11
|
require "rack"
|
13
12
|
end
|
14
13
|
end
|
15
|
-
# :nocov:
|
16
14
|
|
17
15
|
require_relative "cache"
|
18
16
|
|
@@ -129,8 +127,7 @@ class Roda
|
|
129
127
|
"#<#{self.class.inspect} #{@env["REQUEST_METHOD"]} #{path}>"
|
130
128
|
end
|
131
129
|
|
132
|
-
|
133
|
-
if Rack.release >= '2.3'
|
130
|
+
if Rack.release >= '3'
|
134
131
|
def http_version
|
135
132
|
# Prefer SERVER_PROTOCOL as it is required in Rack 3.
|
136
133
|
# Still fall back to HTTP_VERSION if SERVER_PROTOCOL
|
@@ -139,7 +136,6 @@ class Roda
|
|
139
136
|
@env['SERVER_PROTOCOL'] || @env['HTTP_VERSION']
|
140
137
|
end
|
141
138
|
else
|
142
|
-
# :nocov:
|
143
139
|
# What HTTP version the request was submitted with.
|
144
140
|
def http_version
|
145
141
|
# Prefer HTTP_VERSION as it is backwards compatible
|
@@ -444,10 +440,10 @@ class Roda
|
|
444
440
|
hash.all?{|k,v| send("match_#{k}", v)}
|
445
441
|
end
|
446
442
|
|
447
|
-
# Match integer segment, and yield resulting value as an
|
443
|
+
# Match integer segment of up to 100 decimal characters, and yield resulting value as an
|
448
444
|
# integer.
|
449
445
|
def _match_class_Integer
|
450
|
-
consume(/\A\/(\d
|
446
|
+
consume(/\A\/(\d{1,100})(?=\/|\z)/){|i| [i.to_i]}
|
451
447
|
end
|
452
448
|
|
453
449
|
# Match only if all of the arguments in the given array match.
|
data/lib/roda/response.rb
CHANGED
@@ -42,7 +42,6 @@ class Roda
|
|
42
42
|
# code for non-empty responses and a 404 code for empty responses.
|
43
43
|
attr_accessor :status
|
44
44
|
|
45
|
-
# :nocov:
|
46
45
|
if defined?(Rack::Headers) && Rack::Headers.is_a?(Class)
|
47
46
|
# Set the default headers when creating a response.
|
48
47
|
def initialize
|
@@ -51,7 +50,6 @@ class Roda
|
|
51
50
|
@length = 0
|
52
51
|
end
|
53
52
|
else
|
54
|
-
# :nocov:
|
55
53
|
# Set the default headers when creating a response.
|
56
54
|
def initialize
|
57
55
|
@headers = {}
|
@@ -173,7 +171,6 @@ class Roda
|
|
173
171
|
|
174
172
|
private
|
175
173
|
|
176
|
-
# :nocov:
|
177
174
|
if Rack.release < '2.0.2'
|
178
175
|
# Don't use a content length for empty 205 responses on
|
179
176
|
# rack 1, as it violates Rack::Lint in that version.
|
@@ -181,7 +178,6 @@ class Roda
|
|
181
178
|
headers.delete("Content-Type")
|
182
179
|
headers.delete("Content-Length")
|
183
180
|
end
|
184
|
-
# :nocov:
|
185
181
|
else
|
186
182
|
# Set the content length for empty 205 responses to 0
|
187
183
|
def empty_205_headers(headers)
|
data/lib/roda/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roda
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.61.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -164,7 +164,7 @@ dependencies:
|
|
164
164
|
- - ">="
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
|
-
description:
|
167
|
+
description:
|
168
168
|
email:
|
169
169
|
- code@jeremyevans.net
|
170
170
|
executables: []
|
@@ -232,6 +232,8 @@ extra_rdoc_files:
|
|
232
232
|
- doc/release_notes/3.58.0.txt
|
233
233
|
- doc/release_notes/3.59.0.txt
|
234
234
|
- doc/release_notes/3.6.0.txt
|
235
|
+
- doc/release_notes/3.60.0.txt
|
236
|
+
- doc/release_notes/3.61.0.txt
|
235
237
|
- doc/release_notes/3.7.0.txt
|
236
238
|
- doc/release_notes/3.8.0.txt
|
237
239
|
- doc/release_notes/3.9.0.txt
|
@@ -298,6 +300,8 @@ files:
|
|
298
300
|
- doc/release_notes/3.58.0.txt
|
299
301
|
- doc/release_notes/3.59.0.txt
|
300
302
|
- doc/release_notes/3.6.0.txt
|
303
|
+
- doc/release_notes/3.60.0.txt
|
304
|
+
- doc/release_notes/3.61.0.txt
|
301
305
|
- doc/release_notes/3.7.0.txt
|
302
306
|
- doc/release_notes/3.8.0.txt
|
303
307
|
- doc/release_notes/3.9.0.txt
|
@@ -359,6 +363,7 @@ files:
|
|
359
363
|
- lib/roda/plugins/inject_erb.rb
|
360
364
|
- lib/roda/plugins/json.rb
|
361
365
|
- lib/roda/plugins/json_parser.rb
|
366
|
+
- lib/roda/plugins/link_to.rb
|
362
367
|
- lib/roda/plugins/mail_processor.rb
|
363
368
|
- lib/roda/plugins/mailer.rb
|
364
369
|
- lib/roda/plugins/match_affix.rb
|
@@ -433,7 +438,7 @@ metadata:
|
|
433
438
|
documentation_uri: https://roda.jeremyevans.net/documentation.html
|
434
439
|
mailing_list_uri: https://github.com/jeremyevans/roda/discussions
|
435
440
|
source_code_uri: https://github.com/jeremyevans/roda
|
436
|
-
post_install_message:
|
441
|
+
post_install_message:
|
437
442
|
rdoc_options: []
|
438
443
|
require_paths:
|
439
444
|
- lib
|
@@ -449,7 +454,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
449
454
|
version: '0'
|
450
455
|
requirements: []
|
451
456
|
rubygems_version: 3.3.7
|
452
|
-
signing_key:
|
457
|
+
signing_key:
|
453
458
|
specification_version: 4
|
454
459
|
summary: Routing tree web toolkit
|
455
460
|
test_files: []
|