roda 3.55.0 → 3.56.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/CHANGELOG +16 -0
- data/doc/release_notes/3.56.0.txt +33 -0
- data/lib/roda/plugins/chunked.rb +1 -1
- data/lib/roda/plugins/common_logger.rb +1 -1
- data/lib/roda/plugins/cookies.rb +2 -0
- data/lib/roda/plugins/json_parser.rb +6 -2
- data/lib/roda/plugins/multi_public.rb +8 -0
- data/lib/roda/plugins/not_allowed.rb +13 -0
- data/lib/roda/plugins/public.rb +8 -0
- data/lib/roda/plugins/route_csrf.rb +1 -0
- data/lib/roda/plugins/run_append_slash.rb +1 -1
- data/lib/roda/plugins/run_require_slash.rb +46 -0
- data/lib/roda/plugins/sessions.rb +1 -0
- data/lib/roda/plugins/sinatra_helpers.rb +10 -0
- data/lib/roda/plugins/static.rb +2 -0
- data/lib/roda/plugins/status_303.rb +6 -3
- data/lib/roda/plugins/status_handler.rb +35 -9
- data/lib/roda/plugins/symbol_status.rb +2 -0
- data/lib/roda/plugins/unescape_path.rb +2 -0
- data/lib/roda/request.rb +35 -1
- data/lib/roda/response.rb +5 -0
- data/lib/roda/version.rb +1 -1
- metadata +22 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25ca2a1c88af9f7305cdcdb21e3b5983f879386f07c296d7ea0e8f863fddfeac
|
4
|
+
data.tar.gz: 24d9dbfeaa438c859b2b3fcecd2170d55e9d4335b1b57ca06c140b900d4a8283
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c1b58f0a4ac491533eebb08e83c5801d095d94dbf4270d5834fb3511c82fd305244c0c02e23ba51dba1479e81b361faf556ad85698ea77ebd8a130f471b9527
|
7
|
+
data.tar.gz: b18e88e98b3c42a83f0e66891e48b03b9b641ecaf5963e5e5fd71d086c92176cefd5642464c790ed5edde30459c4a1d78b62864b1f14cd38f3bea1c9b6cefa30
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
= 3.56.0 (2022-05-13)
|
2
|
+
|
3
|
+
* Make status_303 plugin use 303 responses for HTTP/2 and higher versions (jeremyevans)
|
4
|
+
|
5
|
+
* Add RodaRequest#http_version for determining the HTTP version in use (jeremyevans)
|
6
|
+
|
7
|
+
* Do not set a body for 405 responses when using the verb methods in the not_allowed plugin (jeremyevans) (#267)
|
8
|
+
|
9
|
+
* Support status_handler method :keep_headers option in status_handler plugin (jeremyevans) (#267)
|
10
|
+
|
11
|
+
* Make not_allowed plugin have r.root return 405 responses for non-GET requests (jeremyevans) (#266)
|
12
|
+
|
13
|
+
* In Rack 3, only require the parts of rack used by Roda, instead of requiring rack itself and relying on autoload (jeremyevans)
|
14
|
+
|
15
|
+
* Add run_require_slash plugin, for skipping application dispatch for remaining paths that would violate Rack SPEC (jeremyevans)
|
16
|
+
|
1
17
|
= 3.55.0 (2022-04-12)
|
2
18
|
|
3
19
|
* Allow passing blocks to the view method in the render plugin (jeremyevans) (#262)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* RodaRequest#http_version has been added for determining the HTTP
|
4
|
+
version the request was submitted with. This will be a string
|
5
|
+
such as "HTTP/1.0", "HTTP/1.1", "HTTP/2", etc. This will use the
|
6
|
+
SERVER_PROTOCOL and HTTP_VERSION entries from the environment to
|
7
|
+
determine which HTTP version is in use.
|
8
|
+
|
9
|
+
* The status_handler method in the status_handler plugin now supports
|
10
|
+
a :keep_headers option. The value for this option should be an
|
11
|
+
array of header names to keep. All other headers are removed. The
|
12
|
+
default behavior without the option is still to remove all headers.
|
13
|
+
|
14
|
+
* A run_require_slash plugin has been added, which will skip
|
15
|
+
dispatching to another rack application if the remaining path is not
|
16
|
+
empty and does not start with a slash.
|
17
|
+
|
18
|
+
= Other Improvements
|
19
|
+
|
20
|
+
* The status_303 plugin will use 303 as the default redirect status
|
21
|
+
for non-GET requests for HTTP/2 and higher HTTP versions. Previously,
|
22
|
+
it only used 303 for HTTP/1.1.
|
23
|
+
|
24
|
+
* The not_allowed plugin now overrides the r.root method to return
|
25
|
+
405 responses to non-GET requests to the root.
|
26
|
+
|
27
|
+
* The not_allowed plugin no longer sets the body when returning 405
|
28
|
+
responses using methods such as r.get and r.post. Previously, the
|
29
|
+
body was unintentionally set to the same value as the Allow header.
|
30
|
+
|
31
|
+
* When using the Rack master branch (what will become Rack 3), Roda
|
32
|
+
only requires the parts of rack that it uses, instead of requiring
|
33
|
+
rack and relying on autoload to load the parts of rack in use.
|
data/lib/roda/plugins/chunked.rb
CHANGED
@@ -226,7 +226,7 @@ class Roda
|
|
226
226
|
# an overview. If a block is given, it is passed to #delay.
|
227
227
|
def chunked(template, opts=OPTS, &block)
|
228
228
|
unless defined?(@_chunked)
|
229
|
-
@_chunked = !self.opts[:force_chunked_encoding] ||
|
229
|
+
@_chunked = !self.opts[:force_chunked_encoding] || @_request.http_version == "HTTP/1.1"
|
230
230
|
end
|
231
231
|
|
232
232
|
if block
|
@@ -53,7 +53,7 @@ class Roda
|
|
53
53
|
|
54
54
|
env = @_request.env
|
55
55
|
|
56
|
-
opts[:common_logger_meth].call("#{env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-"} - #{env["REMOTE_USER"] || "-"} [#{Time.now.strftime("%d/%b/%Y:%H:%M:%S %z")}] \"#{env["REQUEST_METHOD"]} #{env["SCRIPT_NAME"]}#{env["PATH_INFO"]}#{"?#{env["QUERY_STRING"]}" if ((qs = env["QUERY_STRING"]) && !qs.empty?)} #{
|
56
|
+
opts[:common_logger_meth].call("#{env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-"} - #{env["REMOTE_USER"] || "-"} [#{Time.now.strftime("%d/%b/%Y:%H:%M:%S %z")}] \"#{env["REQUEST_METHOD"]} #{env["SCRIPT_NAME"]}#{env["PATH_INFO"]}#{"?#{env["QUERY_STRING"]}" if ((qs = env["QUERY_STRING"]) && !qs.empty?)} #{@_request.http_version}\" #{result[0]} #{((length = result[1]['Content-Length']) && (length unless length == '0')) || '-'} #{elapsed_time}\n")
|
57
57
|
end
|
58
58
|
|
59
59
|
# Create timer instance used for timing
|
data/lib/roda/plugins/cookies.rb
CHANGED
@@ -4,12 +4,16 @@ require 'json'
|
|
4
4
|
|
5
5
|
class Roda
|
6
6
|
module RodaPlugins
|
7
|
-
# The json_parser plugin parses request bodies in
|
7
|
+
# The json_parser plugin parses request bodies in JSON format
|
8
8
|
# if the request's content type specifies json. This is mostly
|
9
9
|
# designed for use with JSON API sites.
|
10
10
|
#
|
11
11
|
# This only parses the request body as JSON if the Content-Type
|
12
12
|
# header for the request includes "json".
|
13
|
+
#
|
14
|
+
# The parsed JSON body will be available in +r.POST+, just as a
|
15
|
+
# parsed HTML form body would be. It will also be available in
|
16
|
+
# +r.params+ (which merges +r.GET+ with +r.POST+).
|
13
17
|
module JsonParser
|
14
18
|
DEFAULT_ERROR_HANDLER = proc{|r| r.halt [400, {}, []]}
|
15
19
|
|
@@ -25,7 +29,7 @@ class Roda
|
|
25
29
|
# object as the second argument, so the parser needs
|
26
30
|
# to respond to +call(str, request)+.
|
27
31
|
# :wrap :: Whether to wrap uploaded JSON data in a hash with a "_json"
|
28
|
-
# key. Without this, calls to r.params will fail if a non-Hash
|
32
|
+
# key. Without this, calls to +r.params+ will fail if a non-Hash
|
29
33
|
# (such as an array) is uploaded in JSON format. A value of
|
30
34
|
# :always will wrap all values, and a value of :unless_hash will
|
31
35
|
# only wrap values that are not already hashes.
|
@@ -17,6 +17,9 @@ class Roda
|
|
17
17
|
# will return a 200 response for <tt>GET /</tt> and a 405
|
18
18
|
# response for <tt>POST /</tt>.
|
19
19
|
#
|
20
|
+
# This plugin changes the +r.root+ method to return a 405 status
|
21
|
+
# for non-GET requests to +/+.
|
22
|
+
#
|
20
23
|
# This plugin also changes the +r.is+ method so that if you use
|
21
24
|
# a verb method inside +r.is+, it returns a 405 status if none
|
22
25
|
# of the verb methods match. So this code:
|
@@ -100,6 +103,15 @@ class Roda
|
|
100
103
|
end
|
101
104
|
end
|
102
105
|
|
106
|
+
# Treat +r.root+ similar to <tt>r.get ''</tt>, using a 405
|
107
|
+
# response for non-GET requests.
|
108
|
+
def root
|
109
|
+
super
|
110
|
+
if @remaining_path == "/" && !is_get?
|
111
|
+
always{method_not_allowed("GET")}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
103
115
|
# Setup methods for all verbs. If inside an is block and not given
|
104
116
|
# arguments, record the verb used. If given an argument, add an is
|
105
117
|
# check with the arguments.
|
@@ -129,6 +141,7 @@ class Roda
|
|
129
141
|
res = response
|
130
142
|
res.status = 405
|
131
143
|
res['Allow'] = verbs
|
144
|
+
nil
|
132
145
|
end
|
133
146
|
end
|
134
147
|
end
|
data/lib/roda/plugins/public.rb
CHANGED
@@ -34,7 +34,7 @@ class Roda
|
|
34
34
|
# path internally, or a redirect is issued when configured with
|
35
35
|
# <tt>use_redirects: true</tt>.
|
36
36
|
def run(*)
|
37
|
-
if remaining_path.empty?
|
37
|
+
if @remaining_path.empty?
|
38
38
|
if scope.opts[:run_append_slash_redirect]
|
39
39
|
redirect("#{path}/")
|
40
40
|
else
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The run_require_slash plugin makes +r.run+ a no-op if the remaining
|
7
|
+
# path is not empty and does not start with +/+. The Rack SPEC requires that
|
8
|
+
# +PATH_INFO+ start with a slash if not empty, so this plugin prevents
|
9
|
+
# dispatching to the application with an environment that would violate the
|
10
|
+
# Rack SPEC.
|
11
|
+
#
|
12
|
+
# You are unlikely to want to use this plugin unless are consuming partial
|
13
|
+
# segments of the request path, or using the match_affix plugin to change
|
14
|
+
# how routing is done:
|
15
|
+
#
|
16
|
+
# plugin :match_affix, "", /(\/|\z)/
|
17
|
+
# route do |r|
|
18
|
+
# r.on "/a" do
|
19
|
+
# r.on "b" do
|
20
|
+
# r.run App
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# # with run_require_slash:
|
26
|
+
# # GET /a/b/e => App not dispatched to
|
27
|
+
# # GET /a/b => App gets "" as PATH_INFO
|
28
|
+
#
|
29
|
+
# # with run_require_slash:
|
30
|
+
# # GET /a/b/e => App gets "e" as PATH_INFO, violating rack SPEC
|
31
|
+
# # GET /a/b => App gets "" as PATH_INFO
|
32
|
+
module RunRequireSlash
|
33
|
+
module RequestMethods
|
34
|
+
# Calls the given rack app only if the remaining patch is empty or
|
35
|
+
# starts with a slash.
|
36
|
+
def run(*)
|
37
|
+
if @remaining_path.empty? || @remaining_path.start_with?('/')
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
register_plugin(:run_require_slash, RunRequireSlash)
|
45
|
+
end
|
46
|
+
end
|
data/lib/roda/plugins/static.rb
CHANGED
@@ -17,10 +17,13 @@ class Roda
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def default_redirect_status
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
return super if is_get?
|
21
|
+
|
22
|
+
case http_version
|
23
|
+
when 'HTTP/1.0', 'HTTP/0.9', nil
|
23
24
|
super
|
25
|
+
else
|
26
|
+
303
|
24
27
|
end
|
25
28
|
end
|
26
29
|
end
|
@@ -15,24 +15,53 @@ class Roda
|
|
15
15
|
# status_handler(403) do
|
16
16
|
# "You are forbidden from seeing that!"
|
17
17
|
# end
|
18
|
+
#
|
18
19
|
# status_handler(404) do
|
19
20
|
# "Where did it go?"
|
20
21
|
# end
|
21
22
|
#
|
23
|
+
# status_handler(405, keep_headers: ['Accept']) do
|
24
|
+
# "Use a different method!"
|
25
|
+
# end
|
26
|
+
#
|
22
27
|
# Before a block is called, any existing headers on the response will be
|
23
|
-
# cleared
|
24
|
-
#
|
28
|
+
# cleared, unless the +:keep_headers+ option is used. If the +:keep_headers+
|
29
|
+
# option is used, the value should be an array, and only the headers listed
|
30
|
+
# in the array will be kept.
|
25
31
|
module StatusHandler
|
32
|
+
CLEAR_HEADERS = :clear.to_proc
|
33
|
+
private_constant :CLEAR_HEADERS
|
34
|
+
|
26
35
|
def self.configure(app)
|
27
36
|
app.opts[:status_handler] ||= {}
|
28
37
|
end
|
29
38
|
|
30
39
|
module ClassMethods
|
31
40
|
# Install the given block as a status handler for the given HTTP response code.
|
32
|
-
def status_handler(code, &block)
|
41
|
+
def status_handler(code, opts=OPTS, &block)
|
33
42
|
# For backwards compatibility, pass request argument if block accepts argument
|
34
43
|
arity = block.arity == 0 ? 0 : 1
|
35
|
-
|
44
|
+
handle_headers = case keep_headers = opts[:keep_headers]
|
45
|
+
when nil, false
|
46
|
+
CLEAR_HEADERS
|
47
|
+
when Array
|
48
|
+
# :nocov:
|
49
|
+
if Rack.release >= '2.3'
|
50
|
+
keep_headers = keep_headers.map(&:downcase)
|
51
|
+
end
|
52
|
+
# :nocov:
|
53
|
+
lambda{|headers| headers.delete_if{|k,_| !keep_headers.include?(k)}}
|
54
|
+
else
|
55
|
+
raise RodaError, "Invalid :keep_headers option"
|
56
|
+
end
|
57
|
+
|
58
|
+
meth = define_roda_method(:"_roda_status_handler__#{code}", arity, &block)
|
59
|
+
self.opts[:status_handler][code] = define_roda_method(:"_roda_status_handler_#{code}", 1) do |result|
|
60
|
+
res = @_response
|
61
|
+
res.status = result[0]
|
62
|
+
handle_headers.call(res.headers)
|
63
|
+
result.replace(_roda_handle_route{arity == 1 ? send(meth, @_request) : send(meth)})
|
64
|
+
end
|
36
65
|
end
|
37
66
|
|
38
67
|
# Freeze the hash of status handlers so that there can be no thread safety issues at runtime.
|
@@ -47,11 +76,8 @@ class Roda
|
|
47
76
|
|
48
77
|
# If routing returns a response we have a handler for, call that handler.
|
49
78
|
def _roda_after_20__status_handler(result)
|
50
|
-
if result && (meth
|
51
|
-
|
52
|
-
res.headers.clear
|
53
|
-
res.status = result[0]
|
54
|
-
result.replace(_roda_handle_route{arity == 1 ? send(meth, @_request) : send(meth)})
|
79
|
+
if result && (meth = opts[:status_handler][result[0]]) && (v = result[2]).is_a?(Array) && v.empty?
|
80
|
+
send(meth, result)
|
55
81
|
end
|
56
82
|
end
|
57
83
|
end
|
data/lib/roda/request.rb
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
|
-
|
3
|
+
# :nocov:
|
4
|
+
begin
|
5
|
+
require "rack/version"
|
6
|
+
rescue LoadError
|
7
|
+
require "rack"
|
8
|
+
else
|
9
|
+
if Rack.release >= '2.3'
|
10
|
+
require "rack/request"
|
11
|
+
else
|
12
|
+
require "rack"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
# :nocov:
|
16
|
+
|
4
17
|
require_relative "cache"
|
5
18
|
|
6
19
|
class Roda
|
@@ -116,6 +129,27 @@ class Roda
|
|
116
129
|
"#<#{self.class.inspect} #{@env["REQUEST_METHOD"]} #{path}>"
|
117
130
|
end
|
118
131
|
|
132
|
+
# :nocov:
|
133
|
+
if Rack.release >= '2.3'
|
134
|
+
def http_version
|
135
|
+
# Prefer SERVER_PROTOCOL as it is required in Rack 3.
|
136
|
+
# Still fall back to HTTP_VERSION if SERVER_PROTOCOL
|
137
|
+
# is not set, in case the server in use is not Rack 3
|
138
|
+
# compliant.
|
139
|
+
@env['SERVER_PROTOCOL'] || @env['HTTP_VERSION']
|
140
|
+
end
|
141
|
+
else
|
142
|
+
# :nocov:
|
143
|
+
# What HTTP version the request was submitted with.
|
144
|
+
def http_version
|
145
|
+
# Prefer HTTP_VERSION as it is backwards compatible
|
146
|
+
# with previous Roda versions. Fallback to
|
147
|
+
# SERVER_PROTOCOL for servers that do not set
|
148
|
+
# HTTP_VERSION.
|
149
|
+
@env['HTTP_VERSION'] || @env['SERVER_PROTOCOL']
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
119
153
|
# Does a terminal match on the current path, matching only if the arguments
|
120
154
|
# have fully matched the path. If it matches, the match block is
|
121
155
|
# executed, and when the match block returns, the rack response is
|
data/lib/roda/response.rb
CHANGED
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.56.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 5.7.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest-hooks
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: minitest-global_expectations
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -213,6 +227,7 @@ extra_rdoc_files:
|
|
213
227
|
- doc/release_notes/3.53.0.txt
|
214
228
|
- doc/release_notes/3.54.0.txt
|
215
229
|
- doc/release_notes/3.55.0.txt
|
230
|
+
- doc/release_notes/3.56.0.txt
|
216
231
|
- doc/release_notes/3.6.0.txt
|
217
232
|
- doc/release_notes/3.7.0.txt
|
218
233
|
- doc/release_notes/3.8.0.txt
|
@@ -275,6 +290,7 @@ files:
|
|
275
290
|
- doc/release_notes/3.53.0.txt
|
276
291
|
- doc/release_notes/3.54.0.txt
|
277
292
|
- doc/release_notes/3.55.0.txt
|
293
|
+
- doc/release_notes/3.56.0.txt
|
278
294
|
- doc/release_notes/3.6.0.txt
|
279
295
|
- doc/release_notes/3.7.0.txt
|
280
296
|
- doc/release_notes/3.8.0.txt
|
@@ -374,6 +390,7 @@ files:
|
|
374
390
|
- lib/roda/plugins/route_csrf.rb
|
375
391
|
- lib/roda/plugins/run_append_slash.rb
|
376
392
|
- lib/roda/plugins/run_handler.rb
|
393
|
+
- lib/roda/plugins/run_require_slash.rb
|
377
394
|
- lib/roda/plugins/sessions.rb
|
378
395
|
- lib/roda/plugins/shared_vars.rb
|
379
396
|
- lib/roda/plugins/sinatra_helpers.rb
|
@@ -396,13 +413,13 @@ files:
|
|
396
413
|
- lib/roda/response.rb
|
397
414
|
- lib/roda/session_middleware.rb
|
398
415
|
- lib/roda/version.rb
|
399
|
-
homepage:
|
416
|
+
homepage: https://roda.jeremyevans.net
|
400
417
|
licenses:
|
401
418
|
- MIT
|
402
419
|
metadata:
|
403
420
|
bug_tracker_uri: https://github.com/jeremyevans/roda/issues
|
404
|
-
changelog_uri:
|
405
|
-
documentation_uri:
|
421
|
+
changelog_uri: https://roda.jeremyevans.net/rdoc/files/CHANGELOG.html
|
422
|
+
documentation_uri: https://roda.jeremyevans.net/documentation.html
|
406
423
|
mailing_list_uri: https://github.com/jeremyevans/roda/discussions
|
407
424
|
source_code_uri: https://github.com/jeremyevans/roda
|
408
425
|
post_install_message:
|