roda 2.23.0 → 2.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +20 -0
- data/README.rdoc +1 -0
- data/doc/release_notes/2.24.0.txt +65 -0
- data/lib/roda.rb +12 -4
- data/lib/roda/plugins/assets.rb +2 -2
- data/lib/roda/plugins/cookies.rb +14 -2
- data/lib/roda/plugins/disallow_file_uploads.rb +38 -0
- data/lib/roda/plugins/h.rb +29 -15
- data/lib/roda/plugins/middleware.rb +43 -5
- data/lib/roda/plugins/precompile_templates.rb +1 -1
- data/lib/roda/plugins/public.rb +1 -1
- data/lib/roda/plugins/render.rb +7 -4
- data/lib/roda/plugins/static.rb +1 -1
- data/lib/roda/plugins/static_routing.rb +10 -6
- data/lib/roda/plugins/strip_path_prefix.rb +33 -0
- data/lib/roda/version.rb +1 -1
- data/spec/integration_spec.rb +21 -0
- data/spec/plugin/cookies_spec.rb +26 -0
- data/spec/plugin/disallow_file_uploads_spec.rb +25 -0
- data/spec/plugin/h_spec.rb +1 -1
- data/spec/plugin/middleware_spec.rb +37 -0
- data/spec/plugin/render_spec.rb +14 -1
- data/spec/plugin/static_routing_spec.rb +20 -0
- data/spec/plugin/strip_path_prefix_spec.rb +24 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b17a05c593a91658be1194fb29c9564dcd6e3fe2
|
4
|
+
data.tar.gz: 153d3095509dd43d37e9297c963aea4e39ef2cbe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3871a3650c8490435fd94d13148a5ba90c636779cb1235c94c0bb61d76ef35efa8cf5c504e29271a3e34bcc818c179ed8a709e1576ccbeb53fb8c4825da2272
|
7
|
+
data.tar.gz: 0ab43b3207200bfc783a00d714b058d04220a1ab1dd333670b8c2d590530cab87564e9323f4023a6c8e48f63a50fd3cf82f842429ae395bdf8f192905fb035bd
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
= 2.24.0 (2017-03-15)
|
2
|
+
|
3
|
+
* Have h plugin use cgi/escape if available for faster escaping (jeremyevans)
|
4
|
+
|
5
|
+
* Add disallow_file_uploads plugin for raising an exception if a multipart file upload is attempted (jeremyevans)
|
6
|
+
|
7
|
+
* Add strip_path_prefix plugin for stripping prefixes off of internal absolute paths, making them relative paths (jeremyevans)
|
8
|
+
|
9
|
+
* Add Roda.expand_path method to DRY up path expansion (jeremyevans)
|
10
|
+
|
11
|
+
* Support :freeze_middleware option, which freezes all middleware instances when building the rack app (jeremyevans)
|
12
|
+
|
13
|
+
* Allow middleware plugin to accept a block that will be used to configure the application when used as middleware (jeremyevans)
|
14
|
+
|
15
|
+
* Support an options hash when loading the cookies plugin, that will be used as the defaults for setting and deleting cookies (mwpastore, jeremyevans) (#112)
|
16
|
+
|
17
|
+
* Make the static_routing plugin work with the hooks plugin if the hooks plugin is loaded first (jeremyevans) (#110)
|
18
|
+
|
19
|
+
* Do not modify the render plugin's cache if loading the plugin multiple times (jeremyevans)
|
20
|
+
|
1
21
|
= 2.23.0 (2017-02-24)
|
2
22
|
|
3
23
|
* Add :inherit_cache render plugin option, to create a copy of the cache for subclasses, instead of using an empty cache (jeremyevans)
|
data/README.rdoc
CHANGED
@@ -635,6 +635,7 @@ The following options are respected by the default library or multiple plugins:
|
|
635
635
|
|
636
636
|
:add_script_name :: Prepend the SCRIPT_NAME for the request to paths. This is
|
637
637
|
useful if you mount the app as a path under another app.
|
638
|
+
:freeze_middleware :: Whether to freeze all middleware when building the rack app.
|
638
639
|
:root :: Set the root path for the app. This defaults to the current working
|
639
640
|
directory of the process.
|
640
641
|
:unsupported_block_result :: If set to :raise, raises an error if a match or
|
@@ -0,0 +1,65 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* The middleware plugin now accepts a block that can be used to
|
4
|
+
implement configurable middleware. This allows you to load the
|
5
|
+
Roda application as middleware in another application, and provide
|
6
|
+
options/block that are passed to the block you passed when loading
|
7
|
+
the middleware plugin. Example:
|
8
|
+
|
9
|
+
class Mid < Roda
|
10
|
+
plugin :middleware do |middleware, *args, &block|
|
11
|
+
middleware.opts[:middleware_args] = args
|
12
|
+
block.call(middleware)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class App < Roda
|
17
|
+
use Mid, :foo, :bar do |middleware|
|
18
|
+
middleware.opts[:middleware_args] << :baz
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Note that when passing a block when loading the middleware plugin,
|
23
|
+
using the middleware in another rack application will actually
|
24
|
+
load a subclass of the middleware (Mid in the example above).
|
25
|
+
This allows you to use the Roda middleware multiple times in the
|
26
|
+
same process with different configurations.
|
27
|
+
|
28
|
+
* The cookies plugin now accepts options that are used as the default
|
29
|
+
options when setting and deleting cookies:
|
30
|
+
|
31
|
+
plugin :cookies, :path => '/foo', :domain => 'example.com'
|
32
|
+
|
33
|
+
* A strip_path_prefix plugin has been added, which can be used to
|
34
|
+
strip prefixes from internal paths. Internally Sequel stores
|
35
|
+
most paths as absolute paths, but there are cases where this
|
36
|
+
doesn't work well, such as symlink changes and chroot. This
|
37
|
+
plugin supports those scenarios.
|
38
|
+
|
39
|
+
* A disallow_file_uploads plugin has been added, which raises
|
40
|
+
an exception if the user attempts a multipart file upload.
|
41
|
+
More exactly, it makes the application raise an exception if
|
42
|
+
attempting to parse a request body when the user has submitted
|
43
|
+
a multipart file upload. This is useful if you don't need to
|
44
|
+
support file uploads in your application, or cases where no
|
45
|
+
paths are writable by the application (due to chroot or system call
|
46
|
+
filtering).
|
47
|
+
|
48
|
+
* The :freeze_middleware option has been added, which freezes all
|
49
|
+
middleware instances when building the rack application. This
|
50
|
+
can help find thread safety issues in middleware.
|
51
|
+
|
52
|
+
= Other Improvements
|
53
|
+
|
54
|
+
* The h plugin is now about 6x faster on ruby 2.3+ due to the use
|
55
|
+
of cgi/escape.
|
56
|
+
|
57
|
+
* The static_routing plugin now works with the hooks plugin if the
|
58
|
+
hooks plugin is loaded first.
|
59
|
+
|
60
|
+
* The render plugin's render cache is no longer cleared when loading
|
61
|
+
the plugin multiple times.
|
62
|
+
|
63
|
+
= Backwards Compatibility
|
64
|
+
|
65
|
+
* The h plugin now escapes ' as ' instead of '.
|
data/lib/roda.rb
CHANGED
@@ -123,6 +123,11 @@ class Roda
|
|
123
123
|
build_rack_app
|
124
124
|
end
|
125
125
|
|
126
|
+
# Expand the given path, using the root argument as the base directory.
|
127
|
+
def expand_path(path, root=opts[:root])
|
128
|
+
::File.expand_path(path, root)
|
129
|
+
end
|
130
|
+
|
126
131
|
# Freeze the internal state of the class, to avoid thread safety issues at runtime.
|
127
132
|
# It's optional to call this method, as nothing should be modifying the
|
128
133
|
# internal state at runtime anyway, but this makes sure an exception will
|
@@ -220,10 +225,13 @@ class Roda
|
|
220
225
|
# Build the rack app to use
|
221
226
|
def build_rack_app
|
222
227
|
if block = @route_block
|
223
|
-
|
224
|
-
@middleware.
|
225
|
-
|
226
|
-
|
228
|
+
app = lambda{|env| new(env).call(&block)}
|
229
|
+
@middleware.reverse_each do |args, bl|
|
230
|
+
mid, *args = args
|
231
|
+
app = mid.new(app, *args, &bl)
|
232
|
+
app.freeze if opts[:freeze_middleware]
|
233
|
+
end
|
234
|
+
@app = app
|
227
235
|
end
|
228
236
|
end
|
229
237
|
end
|
data/lib/roda/plugins/assets.rb
CHANGED
@@ -354,8 +354,8 @@ class Roda
|
|
354
354
|
app.opts[:assets][:orig_opts] = opts
|
355
355
|
end
|
356
356
|
opts = app.opts[:assets]
|
357
|
-
opts[:path] =
|
358
|
-
opts[:public] =
|
357
|
+
opts[:path] = app.expand_path(opts[:path]||"assets").freeze
|
358
|
+
opts[:public] = app.expand_path(opts[:public]||"public").freeze
|
359
359
|
|
360
360
|
# Combine multiple values into a path, ignoring trailing slashes
|
361
361
|
j = lambda do |*v|
|
data/lib/roda/plugins/cookies.rb
CHANGED
@@ -9,7 +9,18 @@ class Roda
|
|
9
9
|
#
|
10
10
|
# response.set_cookie('foo', 'bar')
|
11
11
|
# response.delete_cookie('foo')
|
12
|
+
#
|
13
|
+
# Pass a hash of cookie options when loading the plugin to set some
|
14
|
+
# defaults for all cookies upon setting and deleting. This is particularly
|
15
|
+
# useful for configuring the +domain+ and +path+ of all cookies.
|
16
|
+
#
|
17
|
+
# plugin :cookies, :domain=>'example.com', :path=>'/api'
|
12
18
|
module Cookies
|
19
|
+
# Allow setting default cookie options when loading the cookies plugin.
|
20
|
+
def self.configure(app, opts={})
|
21
|
+
app.opts[:cookies_opts] = (app.opts[:cookies_opts]||{}).merge(opts).freeze
|
22
|
+
end
|
23
|
+
|
13
24
|
module ResponseMethods
|
14
25
|
# Modify the headers to include a Set-Cookie value that
|
15
26
|
# deletes the cookie. A value hash can be provided to
|
@@ -19,7 +30,7 @@ class Roda
|
|
19
30
|
# response.delete_cookie('foo')
|
20
31
|
# response.delete_cookie('foo', :domain=>'example.org')
|
21
32
|
def delete_cookie(key, value = {})
|
22
|
-
::Rack::Utils.delete_cookie_header!(@headers, key, value)
|
33
|
+
::Rack::Utils.delete_cookie_header!(@headers, key, roda_class.opts[:cookies_opts].merge(value))
|
23
34
|
end
|
24
35
|
|
25
36
|
# Set the cookie with the given key in the headers.
|
@@ -27,7 +38,8 @@ class Roda
|
|
27
38
|
# response.set_cookie('foo', 'bar')
|
28
39
|
# response.set_cookie('foo', :value=>'bar', :domain=>'example.org')
|
29
40
|
def set_cookie(key, value)
|
30
|
-
|
41
|
+
value = { :value=>value } unless value.respond_to?(:keys)
|
42
|
+
::Rack::Utils.set_cookie_header!(@headers, key, roda_class.opts[:cookies_opts].merge(value))
|
31
43
|
end
|
32
44
|
end
|
33
45
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
raise LoadError, "disallow_file_uploads plugin not supported on Rack <1.6" if Rack.release < '1.6'
|
4
|
+
|
5
|
+
#
|
6
|
+
class Roda
|
7
|
+
module RodaPlugins
|
8
|
+
# The disallow_file_uploads plugin raises a Roda::RodaPlugins::DisallowFileUploads::Error
|
9
|
+
# if there is an attempt to upload a file. This plugin is useful for applications where
|
10
|
+
# multipart file uploads are not expected and you want to remove the ability for rack
|
11
|
+
# to create temporary files. Example:
|
12
|
+
#
|
13
|
+
# plugin :disallow_file_uploads
|
14
|
+
#
|
15
|
+
# This plugin is only supported on Rack 1.6+. This plugin does not technically
|
16
|
+
# block users from uploading files, it only blocks the parsing of request bodies containing
|
17
|
+
# multipart file uploads. So if you do not call +r.POST+ (or something that calls it such as
|
18
|
+
# +r.params+), then Roda will not attempt to parse the request body, and an exception will not
|
19
|
+
# be raised.
|
20
|
+
module DisallowFileUploads
|
21
|
+
# Exception class used when a multipart file upload is attempted.
|
22
|
+
class Error < RodaError; end
|
23
|
+
|
24
|
+
NO_TEMPFILE = lambda{|_,_| raise Error, "Support for uploading files has been disabled"}
|
25
|
+
|
26
|
+
module RequestMethods
|
27
|
+
# HTML escape the input and return the escaped version.
|
28
|
+
def initialize(_, env)
|
29
|
+
env['rack.multipart.tempfile_factory'] = NO_TEMPFILE
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
register_plugin(:disallow_file_uploads, DisallowFileUploads)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
data/lib/roda/plugins/h.rb
CHANGED
@@ -14,23 +14,37 @@ class Roda
|
|
14
14
|
# h('<foo>')
|
15
15
|
# end
|
16
16
|
module H
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
17
|
+
begin
|
18
|
+
require 'cgi/escape'
|
19
|
+
unless CGI.respond_to?(:escapeHTML) # work around for JRuby 9.1
|
20
|
+
CGI = Object.new
|
21
|
+
CGI.extend(::CGI::Util)
|
22
|
+
end
|
23
|
+
|
24
|
+
module InstanceMethods
|
25
|
+
# HTML escape the input and return the escaped version.
|
26
|
+
def h(string)
|
27
|
+
CGI.escapeHTML(string.to_s)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
rescue LoadError
|
31
|
+
# A Hash of entities and their escaped equivalents,
|
32
|
+
# to be escaped by h().
|
33
|
+
ESCAPE_HTML = {
|
34
|
+
"&" => "&".freeze,
|
35
|
+
"<" => "<".freeze,
|
36
|
+
">" => ">".freeze,
|
37
|
+
"'" => "'".freeze,
|
38
|
+
'"' => """.freeze,
|
39
|
+
}.freeze
|
26
40
|
|
27
|
-
|
28
|
-
|
41
|
+
# A Regexp of HTML entities to match for escaping.
|
42
|
+
ESCAPE_HTML_PATTERN = Regexp.union(*ESCAPE_HTML.keys)
|
29
43
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
44
|
+
module InstanceMethods
|
45
|
+
def h(string)
|
46
|
+
string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
|
47
|
+
end
|
34
48
|
end
|
35
49
|
end
|
36
50
|
end
|
@@ -35,22 +35,60 @@ class Roda
|
|
35
35
|
#
|
36
36
|
# It is possible to use the Roda app as a regular app even when using
|
37
37
|
# the middleware plugin.
|
38
|
+
#
|
39
|
+
# You can support configurable middleware by passing a block when loading
|
40
|
+
# the plugin:
|
41
|
+
#
|
42
|
+
# class Mid < Roda
|
43
|
+
# plugin :middleware do |middleware, *args, &block|
|
44
|
+
# middleware.opts[:middleware_args] = args
|
45
|
+
# block.call(middleware)
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# route do |r|
|
49
|
+
# r.is "mid" do
|
50
|
+
# opts[:middleware_args].join(' ')
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# class App < Roda
|
56
|
+
# use Mid, :foo, :bar do |middleware|
|
57
|
+
# middleware.opts[:middleware_args] << :baz
|
58
|
+
# end
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# # Request to App for /mid returns
|
62
|
+
# # "foo bar baz"
|
63
|
+
#
|
64
|
+
# Note that when supporting configurable middleware via a block, the middleware
|
65
|
+
# used is a subclass of the class loading the plugin, instead of the class itself.
|
66
|
+
# This is done so the same class can be used as middleware with multiple separate
|
67
|
+
# configurations.
|
38
68
|
module Middleware
|
39
69
|
# Configure the middleware plugin. Options:
|
40
70
|
# :env_var :: Set the environment variable to use to indicate to the roda
|
41
71
|
# application that the current request is a middleware request.
|
42
72
|
# You should only need to override this if you are using multiple
|
43
73
|
# roda middleware in the same application.
|
44
|
-
def self.configure(app, opts={})
|
74
|
+
def self.configure(app, opts={}, &block)
|
45
75
|
app.opts[:middleware_env_var] = opts[:env_var] if opts.has_key?(:env_var)
|
46
76
|
app.opts[:middleware_env_var] ||= 'roda.forward_next'
|
77
|
+
app.opts[:middleware_configure] = block if block
|
47
78
|
end
|
48
79
|
|
49
80
|
# Forward instances are what is actually used as middleware.
|
50
81
|
class Forwarder
|
51
82
|
# Store the current middleware and the next middleware to call.
|
52
|
-
def initialize(mid, app)
|
53
|
-
@mid = mid
|
83
|
+
def initialize(mid, app, *args, &block)
|
84
|
+
@mid = if configure = mid.opts[:middleware_configure]
|
85
|
+
mid = Class.new(mid)
|
86
|
+
configure.call(mid, *args, &block)
|
87
|
+
mid
|
88
|
+
else
|
89
|
+
raise RodaError, "cannot provide middleware args or block unless loading middleware plugin with a block" if block || !args.empty?
|
90
|
+
mid
|
91
|
+
end
|
54
92
|
@app = app
|
55
93
|
end
|
56
94
|
|
@@ -76,11 +114,11 @@ class Roda
|
|
76
114
|
|
77
115
|
module ClassMethods
|
78
116
|
# Create a Forwarder instead of a new instance if a non-Hash is given.
|
79
|
-
def new(app)
|
117
|
+
def new(app, *args, &block)
|
80
118
|
if app.is_a?(Hash)
|
81
119
|
super
|
82
120
|
else
|
83
|
-
Forwarder.new(self, app)
|
121
|
+
Forwarder.new(self, app, *args, &block)
|
84
122
|
end
|
85
123
|
end
|
86
124
|
|
data/lib/roda/plugins/public.rb
CHANGED
@@ -32,7 +32,7 @@ class Roda
|
|
32
32
|
# :headers :: A hash of headers to use for statically served files
|
33
33
|
# :root :: Use this option for the root of the public directory (default: "public")
|
34
34
|
def self.configure(app, opts={})
|
35
|
-
root =
|
35
|
+
root = app.expand_path(opts[:root]||"public")
|
36
36
|
app.opts[:public_server] = ::Rack::File.new(root, opts[:headers]||{}, opts[:default_mime] || 'text/plain')
|
37
37
|
app.opts[:public_gzip] = opts[:gzip]
|
38
38
|
end
|
data/lib/roda/plugins/render.rb
CHANGED
@@ -157,6 +157,7 @@ class Roda
|
|
157
157
|
# Setup default rendering options. See Render for details.
|
158
158
|
def self.configure(app, opts=OPTS)
|
159
159
|
if app.opts[:render]
|
160
|
+
orig_cache = app.opts[:render][:cache]
|
160
161
|
opts = app.opts[:render][:orig_opts].merge(opts)
|
161
162
|
end
|
162
163
|
app.opts[:render] = opts.dup
|
@@ -164,12 +165,14 @@ class Roda
|
|
164
165
|
|
165
166
|
opts = app.opts[:render]
|
166
167
|
opts[:engine] = (opts[:engine] || opts[:ext] || "erb").dup.freeze
|
167
|
-
opts[:views] =
|
168
|
+
opts[:views] = app.expand_path(opts[:views]||"views").freeze
|
168
169
|
opts[:allowed_paths] ||= [opts[:views]].freeze
|
169
|
-
opts[:allowed_paths] = opts[:allowed_paths].map{|f|
|
170
|
+
opts[:allowed_paths] = opts[:allowed_paths].map{|f| app.expand_path(f, nil)}.uniq.freeze
|
170
171
|
|
171
172
|
if opts.fetch(:cache, true)
|
172
|
-
if
|
173
|
+
if orig_cache
|
174
|
+
opts[:cache] = orig_cache
|
175
|
+
elsif cache_class = opts[:cache_class]
|
173
176
|
opts[:cache] = cache_class.new
|
174
177
|
else
|
175
178
|
opts[:cache] = app.thread_safe_cache
|
@@ -396,7 +399,7 @@ class Roda
|
|
396
399
|
def template_path(opts)
|
397
400
|
path = "#{opts[:views]}/#{template_name(opts)}.#{opts[:engine]}"
|
398
401
|
if opts.fetch(:check_paths){render_opts[:check_paths]}
|
399
|
-
full_path =
|
402
|
+
full_path = self.class.expand_path(path)
|
400
403
|
unless render_opts[:allowed_paths].any?{|f| full_path.start_with?(f)}
|
401
404
|
raise RodaError, "attempt to render path not in allowed_paths: #{path} (allowed: #{render_opts[:allowed_paths].join(', ')})"
|
402
405
|
end
|
data/lib/roda/plugins/static.rb
CHANGED
@@ -30,7 +30,7 @@ class Roda
|
|
30
30
|
def self.configure(app, paths, opts={})
|
31
31
|
opts = opts.dup
|
32
32
|
opts[:urls] = paths
|
33
|
-
opts[:root] =
|
33
|
+
opts[:root] = app.expand_path(opts[:root]||"public")
|
34
34
|
app.use ::Rack::Static, opts
|
35
35
|
end
|
36
36
|
end
|
@@ -48,6 +48,9 @@ class Roda
|
|
48
48
|
# As shown above, you can use Roda's routing tree methods inside the
|
49
49
|
# static_route block to have shared behavior for different request methods,
|
50
50
|
# while still having handling the request methods differently.
|
51
|
+
#
|
52
|
+
# Note that if you want to use the static_routing plugin and the hooks
|
53
|
+
# plugin at the same time, you should load the hooks plugin first.
|
51
54
|
module StaticRouting
|
52
55
|
def self.configure(app)
|
53
56
|
app.opts[:static_routes] = {}
|
@@ -104,12 +107,13 @@ class Roda
|
|
104
107
|
module InstanceMethods
|
105
108
|
# If there is a static routing method for the given path, call it
|
106
109
|
# instead having the routing tree handle the request.
|
107
|
-
def call
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
110
|
+
def call(&block)
|
111
|
+
super do |r|
|
112
|
+
if route = self.class.static_route_for(r.request_method, r.path_info)
|
113
|
+
r.static_route(&route)
|
114
|
+
else
|
115
|
+
instance_exec(r, &block)
|
116
|
+
end
|
113
117
|
end
|
114
118
|
end
|
115
119
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The strip_path_prefix plugin makes Roda strip a given prefix off internal absolute paths,
|
7
|
+
# turning them to relative paths. Roda by default stores internal paths as absolute paths.
|
8
|
+
# The main reason to use this plugin is when the internal absolute path could change at
|
9
|
+
# runtime, either due to a symlink change or chroot call, or you really want to use
|
10
|
+
# relative links instead of absolute links.
|
11
|
+
#
|
12
|
+
# Examples:
|
13
|
+
#
|
14
|
+
# plugin :strip_path_prefix # Defaults to Dir.pwd
|
15
|
+
# plugin :strip_path_prefix, File.dirname(Dir.pwd)
|
16
|
+
module StripPathPrefix
|
17
|
+
# Set the regexp to use when stripping prefixes from internal paths.
|
18
|
+
def self.configure(app, prefix=Dir.pwd)
|
19
|
+
prefix += '/' unless prefix=~ /\/\z/
|
20
|
+
app.opts[:strip_path_prefix] = /\A#{Regexp.escape(prefix)}/
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
# Strip the path prefix from the gien path if it starts with the prefix.
|
25
|
+
def expand_path(path, root=opts[:root])
|
26
|
+
super.sub(opts[:strip_path_prefix], '')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
register_plugin(:strip_path_prefix, StripPathPrefix)
|
32
|
+
end
|
33
|
+
end
|
data/lib/roda/version.rb
CHANGED
data/spec/integration_spec.rb
CHANGED
@@ -54,6 +54,27 @@ describe "integration" do
|
|
54
54
|
body('/hello').must_equal 'D '
|
55
55
|
end
|
56
56
|
|
57
|
+
it "should freeze middleware if opts[:freeze_middleware] is true" do
|
58
|
+
c = Class.new do
|
59
|
+
def initialize(app) @app = app end
|
60
|
+
def call(env) @a = 1; @app.call(env) end
|
61
|
+
end
|
62
|
+
|
63
|
+
app do
|
64
|
+
"D"
|
65
|
+
end
|
66
|
+
|
67
|
+
body.must_equal 'D'
|
68
|
+
|
69
|
+
app.use c
|
70
|
+
body.must_equal 'D'
|
71
|
+
|
72
|
+
app.clear_middleware!
|
73
|
+
app.opts[:freeze_middleware] = true
|
74
|
+
app.use c
|
75
|
+
proc{body}.must_raise RuntimeError, TypeError
|
76
|
+
end
|
77
|
+
|
57
78
|
it "should support adding middleware using use after route block setup" do
|
58
79
|
c = @c
|
59
80
|
app(:bare) do
|
data/spec/plugin/cookies_spec.rb
CHANGED
@@ -22,4 +22,30 @@ describe "cookies plugin" do
|
|
22
22
|
header('Set-Cookie').must_match(/foo=; (max-age=0; )?expires=Thu, 01[ -]Jan[ -]1970 00:00:00 (-0000|GMT)/)
|
23
23
|
body.must_equal 'Hello'
|
24
24
|
end
|
25
|
+
|
26
|
+
it "should pass default cookie options when setting" do
|
27
|
+
app.plugin :cookies, :path => '/foo'
|
28
|
+
app.route { response.set_cookie("foo", "bar") }
|
29
|
+
header('Set-Cookie').must_equal "foo=bar; path=/foo"
|
30
|
+
|
31
|
+
app.route { response.set_cookie("foo", :value=>"bar", :path=>'/baz') }
|
32
|
+
header('Set-Cookie').must_equal "foo=bar; path=/baz"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should pass default cookie options when deleting" do
|
36
|
+
app.plugin :cookies, :domain => 'example.com'
|
37
|
+
app.route { response.delete_cookie("foo") }
|
38
|
+
header('Set-Cookie').must_match(/foo=; domain=example.com; (max-age=0; )?expires=Thu, 01[ -]Jan[ -]1970 00:00:00 (-0000|GMT)/)
|
39
|
+
|
40
|
+
app.route { response.delete_cookie("foo", :domain=>'bar.com') }
|
41
|
+
header('Set-Cookie').must_match(/foo=; domain=bar.com; (max-age=0; )?expires=Thu, 01[ -]Jan[ -]1970 00:00:00 (-0000|GMT)/)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should not override existing default cookie options" do
|
45
|
+
app.plugin :cookies, :path => '/foo'
|
46
|
+
app.plugin :cookies
|
47
|
+
app.route { response.set_cookie("foo", "bar") }
|
48
|
+
|
49
|
+
header('Set-Cookie').must_equal "foo=bar; path=/foo"
|
50
|
+
end
|
25
51
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
|
2
|
+
|
3
|
+
if Rack.release < '1.6'
|
4
|
+
warn "Rack #{Rack.release} used, skipping disallow_file_uploads plugin test"
|
5
|
+
else
|
6
|
+
describe "disallow_file_uploads plugin" do
|
7
|
+
it "disallows the uploading of files" do
|
8
|
+
app do |r|
|
9
|
+
r['foo'][:tempfile].read
|
10
|
+
end
|
11
|
+
|
12
|
+
request_body = StringIO.new("------WebKitFormBoundarymwHIM9XjTTVHn3YP\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"bar.txt\"\r\nContent-Type: text/plain\r\n\r\nfoo\n\r\n------WebKitFormBoundarymwHIM9XjTTVHn3YP--\r\n")
|
13
|
+
|
14
|
+
h = {
|
15
|
+
'rack.input'=>request_body,
|
16
|
+
'CONTENT_TYPE'=>'multipart/form-data; boundary=----WebKitFormBoundarymwHIM9XjTTVHn3YP',
|
17
|
+
'CONTENT_LENGTH'=>'184',
|
18
|
+
'REQUEST_METHOD'=>'POST'
|
19
|
+
}
|
20
|
+
body(h.dup).must_equal "foo\n"
|
21
|
+
app.plugin :disallow_file_uploads
|
22
|
+
proc{body(h.dup)}.must_raise Roda::RodaPlugins::DisallowFileUploads::Error
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/spec/plugin/h_spec.rb
CHANGED
@@ -57,6 +57,43 @@ describe "middleware plugin" do
|
|
57
57
|
body.must_equal 'a'
|
58
58
|
end
|
59
59
|
|
60
|
+
it "should raise error if attempting to use options for Roda application that does not support configurable middleware" do
|
61
|
+
a1 = app(:bare){plugin :middleware}
|
62
|
+
proc{app(:bare){use a1, :foo; route{}; build_rack_app}}.must_raise Roda::RodaError
|
63
|
+
proc{app(:bare){use(a1){}; route{}; build_rack_app}}.must_raise Roda::RodaError
|
64
|
+
end
|
65
|
+
|
66
|
+
it "supports configuring middleware via a block" do
|
67
|
+
a1 = app(:bare) do
|
68
|
+
plugin :middleware do |mid, *args, &block|
|
69
|
+
mid.opts[:a] = args.concat(block.call(:quux)).join(' ')
|
70
|
+
end
|
71
|
+
opts[:a] = 'a1'
|
72
|
+
|
73
|
+
route do |r|
|
74
|
+
r.is 'a' do opts[:a] end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
body('/a').must_equal 'a1'
|
79
|
+
|
80
|
+
app(:bare) do
|
81
|
+
use a1, :foo, :bar do |baz|
|
82
|
+
[baz, :a1]
|
83
|
+
end
|
84
|
+
|
85
|
+
route do
|
86
|
+
'b1'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
body.must_equal 'b1'
|
91
|
+
body('/a').must_equal 'foo bar quux a1'
|
92
|
+
|
93
|
+
@app = a1
|
94
|
+
body('/a').must_equal 'a1'
|
95
|
+
end
|
96
|
+
|
60
97
|
it "is compatible with the multi_route plugin" do
|
61
98
|
app(:bare) do
|
62
99
|
plugin :multi_route
|
data/spec/plugin/render_spec.rb
CHANGED
@@ -499,7 +499,7 @@ describe "render plugin" do
|
|
499
499
|
sc.render_opts[:cache][:foo].must_be_nil
|
500
500
|
end
|
501
501
|
|
502
|
-
it "should use
|
502
|
+
it "should use a copy of superclass's cache when inheriting if :inherit_cache option is used" do
|
503
503
|
c = Class.new(Roda)
|
504
504
|
c.plugin :render, :inherit_cache=>true
|
505
505
|
c.render_opts[:cache][:foo] = 1
|
@@ -510,6 +510,19 @@ describe "render plugin" do
|
|
510
510
|
sc.render_opts[:cache][:foo].must_equal 1
|
511
511
|
end
|
512
512
|
|
513
|
+
it "should not modifying existing cache if loading the plugin a separate time" do
|
514
|
+
c = Class.new(Roda)
|
515
|
+
c.plugin :render
|
516
|
+
cache = c.render_opts[:cache]
|
517
|
+
c.plugin :render
|
518
|
+
c.render_opts[:cache].must_be_same_as cache
|
519
|
+
|
520
|
+
c.plugin :render, :cache=>false
|
521
|
+
c.render_opts[:cache].must_equal false
|
522
|
+
c.plugin :render
|
523
|
+
c.render_opts[:cache].must_equal false
|
524
|
+
end
|
525
|
+
|
513
526
|
it "render plugin call should not override existing options" do
|
514
527
|
c = Class.new(Roda)
|
515
528
|
c.plugin :render, :layout=>:foo
|
@@ -46,6 +46,26 @@ describe "static_routing plugin" do
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
+
it "works with hooks plugin if loaded after" do
|
50
|
+
a = []
|
51
|
+
app(:bare) do
|
52
|
+
plugin :hooks
|
53
|
+
plugin :static_routing
|
54
|
+
|
55
|
+
before{a << 1}
|
56
|
+
after{a << 2}
|
57
|
+
|
58
|
+
static_route "/foo" do |r|
|
59
|
+
a << 3
|
60
|
+
"bar"
|
61
|
+
end
|
62
|
+
|
63
|
+
route{}
|
64
|
+
end
|
65
|
+
body('/foo').must_equal 'bar'
|
66
|
+
a.must_equal [1,3,2]
|
67
|
+
end
|
68
|
+
|
49
69
|
it "does not allow placeholders in static routes" do
|
50
70
|
app(:bare) do
|
51
71
|
plugin :static_routing
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
|
2
|
+
|
3
|
+
describe "strip_path_prefix plugin" do
|
4
|
+
it "strips path prefix when expanding paths" do
|
5
|
+
app(:bare){}
|
6
|
+
abs_dir = app.expand_path('spec')
|
7
|
+
|
8
|
+
app.plugin :strip_path_prefix
|
9
|
+
app.expand_path('spec').must_equal 'spec'
|
10
|
+
File.expand_path(app.expand_path('spec'), Dir.pwd).must_equal abs_dir
|
11
|
+
|
12
|
+
app.expand_path('/foo').must_equal '/foo'
|
13
|
+
app.expand_path('bar', '/foo').must_equal '/foo/bar'
|
14
|
+
|
15
|
+
app.opts[:root] = '/foo'
|
16
|
+
app.expand_path('bar').must_equal '/foo/bar'
|
17
|
+
app.plugin :strip_path_prefix, '/foo'
|
18
|
+
app.expand_path('bar').must_equal 'bar'
|
19
|
+
|
20
|
+
app.opts[:root] = '/foo/bar'
|
21
|
+
app.expand_path('baz').must_equal 'bar/baz'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
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: 2.
|
4
|
+
version: 2.24.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: 2017-
|
11
|
+
date: 2017-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -203,6 +203,7 @@ extra_rdoc_files:
|
|
203
203
|
- doc/release_notes/2.21.0.txt
|
204
204
|
- doc/release_notes/2.22.0.txt
|
205
205
|
- doc/release_notes/2.23.0.txt
|
206
|
+
- doc/release_notes/2.24.0.txt
|
206
207
|
files:
|
207
208
|
- CHANGELOG
|
208
209
|
- MIT-LICENSE
|
@@ -230,6 +231,7 @@ files:
|
|
230
231
|
- doc/release_notes/2.21.0.txt
|
231
232
|
- doc/release_notes/2.22.0.txt
|
232
233
|
- doc/release_notes/2.23.0.txt
|
234
|
+
- doc/release_notes/2.24.0.txt
|
233
235
|
- doc/release_notes/2.3.0.txt
|
234
236
|
- doc/release_notes/2.4.0.txt
|
235
237
|
- doc/release_notes/2.5.0.txt
|
@@ -255,6 +257,7 @@ files:
|
|
255
257
|
- lib/roda/plugins/delay_build.rb
|
256
258
|
- lib/roda/plugins/delegate.rb
|
257
259
|
- lib/roda/plugins/delete_empty_headers.rb
|
260
|
+
- lib/roda/plugins/disallow_file_uploads.rb
|
258
261
|
- lib/roda/plugins/drop_body.rb
|
259
262
|
- lib/roda/plugins/empty_root.rb
|
260
263
|
- lib/roda/plugins/environments.rb
|
@@ -307,6 +310,7 @@ files:
|
|
307
310
|
- lib/roda/plugins/static_routing.rb
|
308
311
|
- lib/roda/plugins/status_handler.rb
|
309
312
|
- lib/roda/plugins/streaming.rb
|
313
|
+
- lib/roda/plugins/strip_path_prefix.rb
|
310
314
|
- lib/roda/plugins/symbol_matchers.rb
|
311
315
|
- lib/roda/plugins/symbol_status.rb
|
312
316
|
- lib/roda/plugins/symbol_views.rb
|
@@ -343,6 +347,7 @@ files:
|
|
343
347
|
- spec/plugin/delay_build_spec.rb
|
344
348
|
- spec/plugin/delegate_spec.rb
|
345
349
|
- spec/plugin/delete_empty_headers_spec.rb
|
350
|
+
- spec/plugin/disallow_file_uploads_spec.rb
|
346
351
|
- spec/plugin/drop_body_spec.rb
|
347
352
|
- spec/plugin/empty_root_spec.rb
|
348
353
|
- spec/plugin/environments_spec.rb
|
@@ -394,6 +399,7 @@ files:
|
|
394
399
|
- spec/plugin/static_spec.rb
|
395
400
|
- spec/plugin/status_handler_spec.rb
|
396
401
|
- spec/plugin/streaming_spec.rb
|
402
|
+
- spec/plugin/strip_path_prefix_spec.rb
|
397
403
|
- spec/plugin/symbol_matchers_spec.rb
|
398
404
|
- spec/plugin/symbol_status_spec.rb
|
399
405
|
- spec/plugin/symbol_views_spec.rb
|