roda 3.53.0 → 3.56.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +42 -588
- data/doc/release_notes/3.54.0.txt +48 -0
- data/doc/release_notes/3.55.0.txt +12 -0
- data/doc/release_notes/3.56.0.txt +33 -0
- data/lib/roda/plugins/additional_view_directories.rb +1 -3
- data/lib/roda/plugins/assets.rb +6 -3
- data/lib/roda/plugins/chunked.rb +48 -22
- data/lib/roda/plugins/common_logger.rb +1 -1
- data/lib/roda/plugins/cookies.rb +2 -0
- data/lib/roda/plugins/drop_body.rb +5 -4
- data/lib/roda/plugins/heartbeat.rb +6 -1
- data/lib/roda/plugins/json_parser.rb +24 -5
- data/lib/roda/plugins/middleware.rb +17 -2
- data/lib/roda/plugins/multi_public.rb +13 -1
- data/lib/roda/plugins/not_allowed.rb +13 -0
- data/lib/roda/plugins/public.rb +22 -7
- data/lib/roda/plugins/render.rb +5 -3
- data/lib/roda/plugins/route_csrf.rb +4 -1
- data/lib/roda/plugins/run_append_slash.rb +1 -1
- data/lib/roda/plugins/run_handler.rb +7 -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 +15 -1
- 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 +39 -7
- data/lib/roda/version.rb +1 -1
- metadata +28 -7
@@ -35,7 +35,13 @@ class Roda
|
|
35
35
|
def run(app, opts=OPTS)
|
36
36
|
res = catch(:halt){super(app)}
|
37
37
|
yield res if defined?(yield)
|
38
|
-
|
38
|
+
if opts[:not_found] == :pass && res[0] == 404
|
39
|
+
body = res[2]
|
40
|
+
body.close if body.respond_to?(:close)
|
41
|
+
nil
|
42
|
+
else
|
43
|
+
throw(:halt, res)
|
44
|
+
end
|
39
45
|
end
|
40
46
|
end
|
41
47
|
end
|
@@ -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
|
@@ -1,5 +1,15 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
|
+
require 'rack/mime'
|
4
|
+
begin
|
5
|
+
require 'rack/files'
|
6
|
+
rescue LoadError
|
7
|
+
# :nocov:
|
8
|
+
require 'rack/file'
|
9
|
+
# :nocov:
|
10
|
+
end
|
11
|
+
|
12
|
+
|
3
13
|
#
|
4
14
|
class Roda
|
5
15
|
module RodaPlugins
|
@@ -215,6 +225,10 @@ class Roda
|
|
215
225
|
ISO88591_ENCODING = Encoding.find('ISO-8859-1')
|
216
226
|
BINARY_ENCODING = Encoding.find('BINARY')
|
217
227
|
|
228
|
+
# :nocov:
|
229
|
+
RACK_FILES = defined?(Rack::Files) ? Rack::Files : Rack::File
|
230
|
+
# :nocov:
|
231
|
+
|
218
232
|
# Depend on the status_303 plugin.
|
219
233
|
def self.load_dependencies(app, _opts = nil)
|
220
234
|
app.plugin :status_303
|
@@ -333,7 +347,7 @@ class Roda
|
|
333
347
|
last_modified(lm)
|
334
348
|
end
|
335
349
|
|
336
|
-
file =
|
350
|
+
file = RACK_FILES.new nil
|
337
351
|
s, h, b = if Rack.release > '2'
|
338
352
|
file.serving(self, path)
|
339
353
|
else
|
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
@@ -1,5 +1,10 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
|
+
begin
|
4
|
+
require 'rack/headers'
|
5
|
+
rescue LoadError
|
6
|
+
end
|
7
|
+
|
3
8
|
class Roda
|
4
9
|
# Base class used for Roda responses. The instance methods for this
|
5
10
|
# class are added by Roda::RodaPlugins::Base::ResponseMethods, the class
|
@@ -37,11 +42,22 @@ class Roda
|
|
37
42
|
# code for non-empty responses and a 404 code for empty responses.
|
38
43
|
attr_accessor :status
|
39
44
|
|
40
|
-
#
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
+
# :nocov:
|
46
|
+
if defined?(Rack::Headers) && Rack::Headers.is_a?(Class)
|
47
|
+
# Set the default headers when creating a response.
|
48
|
+
def initialize
|
49
|
+
@headers = Rack::Headers.new
|
50
|
+
@body = []
|
51
|
+
@length = 0
|
52
|
+
end
|
53
|
+
else
|
54
|
+
# :nocov:
|
55
|
+
# Set the default headers when creating a response.
|
56
|
+
def initialize
|
57
|
+
@headers = {}
|
58
|
+
@body = []
|
59
|
+
@length = 0
|
60
|
+
end
|
45
61
|
end
|
46
62
|
|
47
63
|
# Return the response header with the given key. Example:
|
@@ -96,8 +112,7 @@ class Roda
|
|
96
112
|
if (s == 304 || s == 204 || (s >= 100 && s <= 199))
|
97
113
|
h.delete("Content-Type")
|
98
114
|
elsif s == 205
|
99
|
-
h
|
100
|
-
h["Content-Length"] = '0'
|
115
|
+
empty_205_headers(h)
|
101
116
|
else
|
102
117
|
h["Content-Length"] ||= '0'
|
103
118
|
end
|
@@ -158,6 +173,23 @@ class Roda
|
|
158
173
|
|
159
174
|
private
|
160
175
|
|
176
|
+
# :nocov:
|
177
|
+
if Rack.release < '2.0.2'
|
178
|
+
# Don't use a content length for empty 205 responses on
|
179
|
+
# rack 1, as it violates Rack::Lint in that version.
|
180
|
+
def empty_205_headers(headers)
|
181
|
+
headers.delete("Content-Type")
|
182
|
+
headers.delete("Content-Length")
|
183
|
+
end
|
184
|
+
# :nocov:
|
185
|
+
else
|
186
|
+
# Set the content length for empty 205 responses to 0
|
187
|
+
def empty_205_headers(headers)
|
188
|
+
headers.delete("Content-Type")
|
189
|
+
headers["Content-Length"] = '0'
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
161
193
|
# For each default header, if a header has not already been set for the
|
162
194
|
# response, set the header in the response.
|
163
195
|
def set_default_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.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
|
@@ -109,7 +123,7 @@ dependencies:
|
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '0'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
126
|
+
name: sassc
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
114
128
|
requirements:
|
115
129
|
- - ">="
|
@@ -211,6 +225,9 @@ extra_rdoc_files:
|
|
211
225
|
- doc/release_notes/3.51.0.txt
|
212
226
|
- doc/release_notes/3.52.0.txt
|
213
227
|
- doc/release_notes/3.53.0.txt
|
228
|
+
- doc/release_notes/3.54.0.txt
|
229
|
+
- doc/release_notes/3.55.0.txt
|
230
|
+
- doc/release_notes/3.56.0.txt
|
214
231
|
- doc/release_notes/3.6.0.txt
|
215
232
|
- doc/release_notes/3.7.0.txt
|
216
233
|
- doc/release_notes/3.8.0.txt
|
@@ -271,6 +288,9 @@ files:
|
|
271
288
|
- doc/release_notes/3.51.0.txt
|
272
289
|
- doc/release_notes/3.52.0.txt
|
273
290
|
- doc/release_notes/3.53.0.txt
|
291
|
+
- doc/release_notes/3.54.0.txt
|
292
|
+
- doc/release_notes/3.55.0.txt
|
293
|
+
- doc/release_notes/3.56.0.txt
|
274
294
|
- doc/release_notes/3.6.0.txt
|
275
295
|
- doc/release_notes/3.7.0.txt
|
276
296
|
- doc/release_notes/3.8.0.txt
|
@@ -370,6 +390,7 @@ files:
|
|
370
390
|
- lib/roda/plugins/route_csrf.rb
|
371
391
|
- lib/roda/plugins/run_append_slash.rb
|
372
392
|
- lib/roda/plugins/run_handler.rb
|
393
|
+
- lib/roda/plugins/run_require_slash.rb
|
373
394
|
- lib/roda/plugins/sessions.rb
|
374
395
|
- lib/roda/plugins/shared_vars.rb
|
375
396
|
- lib/roda/plugins/sinatra_helpers.rb
|
@@ -392,13 +413,13 @@ files:
|
|
392
413
|
- lib/roda/response.rb
|
393
414
|
- lib/roda/session_middleware.rb
|
394
415
|
- lib/roda/version.rb
|
395
|
-
homepage:
|
416
|
+
homepage: https://roda.jeremyevans.net
|
396
417
|
licenses:
|
397
418
|
- MIT
|
398
419
|
metadata:
|
399
420
|
bug_tracker_uri: https://github.com/jeremyevans/roda/issues
|
400
|
-
changelog_uri:
|
401
|
-
documentation_uri:
|
421
|
+
changelog_uri: https://roda.jeremyevans.net/rdoc/files/CHANGELOG.html
|
422
|
+
documentation_uri: https://roda.jeremyevans.net/documentation.html
|
402
423
|
mailing_list_uri: https://github.com/jeremyevans/roda/discussions
|
403
424
|
source_code_uri: https://github.com/jeremyevans/roda
|
404
425
|
post_install_message:
|
@@ -416,7 +437,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
416
437
|
- !ruby/object:Gem::Version
|
417
438
|
version: '0'
|
418
439
|
requirements: []
|
419
|
-
rubygems_version: 3.3.
|
440
|
+
rubygems_version: 3.3.7
|
420
441
|
signing_key:
|
421
442
|
specification_version: 4
|
422
443
|
summary: Routing tree web toolkit
|