roda 3.60.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 +6 -0
- data/README.rdoc +40 -15
- data/doc/release_notes/3.61.0.txt +24 -0
- data/lib/roda/plugins/_optimized_matching.rb +2 -2
- data/lib/roda/plugins/common_logger.rb +1 -1
- data/lib/roda/plugins/typecast_params.rb +102 -53
- data/lib/roda/request.rb +2 -2
- data/lib/roda/version.rb +1 -1
- metadata +8 -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,9 @@
|
|
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
|
+
|
1
7
|
= 3.60.0 (2022-09-13)
|
2
8
|
|
3
9
|
* Add link_to plugin with link_to method for creating HTML links (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,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
|
@@ -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
|
#
|
@@ -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
|
data/lib/roda/request.rb
CHANGED
@@ -440,10 +440,10 @@ class Roda
|
|
440
440
|
hash.all?{|k,v| send("match_#{k}", v)}
|
441
441
|
end
|
442
442
|
|
443
|
-
# 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
|
444
444
|
# integer.
|
445
445
|
def _match_class_Integer
|
446
|
-
consume(/\A\/(\d
|
446
|
+
consume(/\A\/(\d{1,100})(?=\/|\z)/){|i| [i.to_i]}
|
447
447
|
end
|
448
448
|
|
449
449
|
# Match only if all of the arguments in the given array match.
|
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: []
|
@@ -233,6 +233,7 @@ extra_rdoc_files:
|
|
233
233
|
- doc/release_notes/3.59.0.txt
|
234
234
|
- doc/release_notes/3.6.0.txt
|
235
235
|
- doc/release_notes/3.60.0.txt
|
236
|
+
- doc/release_notes/3.61.0.txt
|
236
237
|
- doc/release_notes/3.7.0.txt
|
237
238
|
- doc/release_notes/3.8.0.txt
|
238
239
|
- doc/release_notes/3.9.0.txt
|
@@ -300,6 +301,7 @@ files:
|
|
300
301
|
- doc/release_notes/3.59.0.txt
|
301
302
|
- doc/release_notes/3.6.0.txt
|
302
303
|
- doc/release_notes/3.60.0.txt
|
304
|
+
- doc/release_notes/3.61.0.txt
|
303
305
|
- doc/release_notes/3.7.0.txt
|
304
306
|
- doc/release_notes/3.8.0.txt
|
305
307
|
- doc/release_notes/3.9.0.txt
|
@@ -436,7 +438,7 @@ metadata:
|
|
436
438
|
documentation_uri: https://roda.jeremyevans.net/documentation.html
|
437
439
|
mailing_list_uri: https://github.com/jeremyevans/roda/discussions
|
438
440
|
source_code_uri: https://github.com/jeremyevans/roda
|
439
|
-
post_install_message:
|
441
|
+
post_install_message:
|
440
442
|
rdoc_options: []
|
441
443
|
require_paths:
|
442
444
|
- lib
|
@@ -452,7 +454,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
452
454
|
version: '0'
|
453
455
|
requirements: []
|
454
456
|
rubygems_version: 3.3.7
|
455
|
-
signing_key:
|
457
|
+
signing_key:
|
456
458
|
specification_version: 4
|
457
459
|
summary: Routing tree web toolkit
|
458
460
|
test_files: []
|