roda 3.1.0 → 3.2.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 +6 -0
- data/doc/release_notes/3.2.0.txt +22 -0
- data/lib/roda/plugins/assets.rb +7 -1
- data/lib/roda/plugins/public.rb +6 -2
- data/lib/roda/plugins/sinatra_helpers.rb +1 -1
- data/lib/roda/plugins/timestamp_public.rb +75 -0
- data/lib/roda/version.rb +1 -1
- data/spec/plugin/timestamp_public_spec.rb +85 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4935b8951819226ca81b82723628a6c555e505e
|
4
|
+
data.tar.gz: c3fd3714c47c7b5e014ed34a2f817a249b257fa6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7bf5572895450e439a6559a79815603a98fd5dd1b2a1b11a1b13218dd15a35cbdbc67db60021752878c22fc1dceadc8f4926c79f90d65705ca78187a68fb8c55
|
7
|
+
data.tar.gz: 4a6e9c478b28b58da51dedad966cd77b72ff5bca90a21d4adcba47c4560252549af8d9f75df2123fc30f46c600b7da06e7b6f5d8bb692b36d5f7052a0a364148
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
= 3.2.0 (2017-11-16)
|
2
|
+
|
3
|
+
* Use microseconds in assets plugin :timestamp_paths timestamps (jeremyevans)
|
4
|
+
|
5
|
+
* Add timestamp_public plugin for serving static files with paths that change based on modify timestamp (jeremyevans)
|
6
|
+
|
1
7
|
= 3.1.0 (2017-10-13)
|
2
8
|
|
3
9
|
* Make set_layout_locals and set_view_locals in branch_locals plugin work when the other is not called (jeremyevans)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A timestamp_public plugin has been added for serving static files
|
4
|
+
with paths that change based on the modification timestamp of the
|
5
|
+
file. By using a new path, cached versions of the file will not
|
6
|
+
be used, fixing staleness issues. Example:
|
7
|
+
|
8
|
+
plugin :timestamp_public
|
9
|
+
|
10
|
+
route do |r|
|
11
|
+
# serves requests for /static/\d+/.*
|
12
|
+
r.timestamp_public
|
13
|
+
|
14
|
+
# /static/1234567890/path/to/file
|
15
|
+
timestamp_path("path/to/file")
|
16
|
+
end
|
17
|
+
|
18
|
+
= Other Improvements
|
19
|
+
|
20
|
+
* When using the assets plugin :timestamp_paths option, the
|
21
|
+
timestamps now include microseconds, to make cache poisoning more
|
22
|
+
difficult.
|
data/lib/roda/plugins/assets.rb
CHANGED
@@ -620,7 +620,13 @@ class Roda
|
|
620
620
|
dirs.each{|f| asset_dir = asset_dir[f]}
|
621
621
|
prefix = "#{dirs.join('/')}/" if o[:group_subdirs]
|
622
622
|
end
|
623
|
-
Array(asset_dir).map
|
623
|
+
Array(asset_dir).map do |f|
|
624
|
+
if o[:timestamp_paths]
|
625
|
+
mtime = asset_last_modified(File.join(o[:"#{stype}_path"], *[prefix, f].compact))
|
626
|
+
mtime = "#{sprintf("%i%06i", mtime.to_i, mtime.usec)}/"
|
627
|
+
end
|
628
|
+
"#{url_prefix}/#{o[:"#{stype}_prefix"]}#{mtime}#{prefix}#{f}#{o[:"#{stype}_suffix"]}"
|
629
|
+
end
|
624
630
|
end
|
625
631
|
end
|
626
632
|
|
data/lib/roda/plugins/public.rb
CHANGED
@@ -45,8 +45,12 @@ class Roda
|
|
45
45
|
# :headers :: A hash of headers to use for statically served files
|
46
46
|
# :root :: Use this option for the root of the public directory (default: "public")
|
47
47
|
def self.configure(app, opts={})
|
48
|
-
|
49
|
-
|
48
|
+
if opts[:root]
|
49
|
+
app.opts[:public_root] = app.expand_path(opts[:root])
|
50
|
+
elsif !app.opts[:public_root]
|
51
|
+
app.opts[:public_root] = app.expand_path("public")
|
52
|
+
end
|
53
|
+
app.opts[:public_server] = ::Rack::File.new(app.opts[:public_root], opts[:headers]||{}, opts[:default_mime] || 'text/plain')
|
50
54
|
app.opts[:public_gzip] = opts[:gzip]
|
51
55
|
end
|
52
56
|
|
@@ -53,7 +53,7 @@ class Roda
|
|
53
53
|
# and halts the request. It takes an optional body:
|
54
54
|
#
|
55
55
|
# error # 500 response, empty boby
|
56
|
-
# error 501 # 501
|
56
|
+
# error 501 # 501 response, empty body
|
57
57
|
# error 'b' # 500 response, 'b' body
|
58
58
|
# error 501, 'b' # 501 response, 'b' body
|
59
59
|
#
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The timestamp_public plugin adds a +timestamp_path+ method for constructing
|
7
|
+
# timestamp paths, and a +r.timestamp_public+ routing method to serve static files
|
8
|
+
# from a directory (using the public plugin). This plugin is useful when you want
|
9
|
+
# to modify the path to static files when the modify timestamp on the file changes,
|
10
|
+
# ensuring that requests for the static file will not be cached.
|
11
|
+
#
|
12
|
+
# Note that while this plugin will not serve files outside of the public directory,
|
13
|
+
# for performance reasons it does not check the path of the file is inside the public
|
14
|
+
# directory when getting the modify timestamp. If the +timestamp_path+ method is
|
15
|
+
# called with untrusted input, it is possible for an attacker to get the modify
|
16
|
+
# timestamp for any file on the file system.
|
17
|
+
#
|
18
|
+
# Examples:
|
19
|
+
#
|
20
|
+
# # Use public folder as location of files, and static as the path prefix
|
21
|
+
# plugin :timestamp_public
|
22
|
+
#
|
23
|
+
# # Use /path/to/app/static as location of files, and public as the path prefix
|
24
|
+
# opts[:root] = '/path/to/app'
|
25
|
+
# plugin :public, root: 'static', prefix: 'public'
|
26
|
+
#
|
27
|
+
# # Assuming public is the location of files, and static is the path prefix
|
28
|
+
# r.route do
|
29
|
+
# # Make GET /static/1238099123/images/foo.png look for public/images/foo.png
|
30
|
+
# r.timestamp_public
|
31
|
+
#
|
32
|
+
# r.get "example" do
|
33
|
+
# # "/static/1238099123/images/foo.png"
|
34
|
+
# timestamp_path("images/foo.png")
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
module TimestampPublic
|
38
|
+
# Use options given to setup timestamped file serving. The following option is
|
39
|
+
# recognized by the plugin:
|
40
|
+
#
|
41
|
+
# :prefix :: The prefix for paths, before the timestamp segment
|
42
|
+
#
|
43
|
+
# The options given are also passed to the public plugin.
|
44
|
+
def self.configure(app, opts={})
|
45
|
+
app.plugin :public, opts
|
46
|
+
app.opts[:timestamp_public_prefix] = (opts[:prefix] || app.opts[:timestamp_public_prefix] || "static").dup.freeze
|
47
|
+
end
|
48
|
+
|
49
|
+
module InstanceMethods
|
50
|
+
# Return a path to the static file that could be served by r.timestamp_public.
|
51
|
+
# This does not check the file is inside the directory for performance reasons,
|
52
|
+
# so this should not be called with untrusted input.
|
53
|
+
def timestamp_path(file)
|
54
|
+
mtime = File.mtime(File.join(opts[:public_root], file))
|
55
|
+
"/#{opts[:timestamp_public_prefix]}/#{sprintf("%i%06i", mtime.to_i, mtime.usec)}/#{file}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module RequestMethods
|
60
|
+
# Serve files from the public directory if the file exists,
|
61
|
+
# it includes the timestamp_public prefix segment followed by
|
62
|
+
# a integer segment for the timestamp, and this is a GET request.
|
63
|
+
def timestamp_public
|
64
|
+
if is_get?
|
65
|
+
on roda_class.opts[:timestamp_public_prefix], Integer do |_|
|
66
|
+
public
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
register_plugin(:timestamp_public, TimestampPublic)
|
74
|
+
end
|
75
|
+
end
|
data/lib/roda/version.rb
CHANGED
@@ -0,0 +1,85 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
|
3
|
+
describe "timestamp_public plugin" do
|
4
|
+
it "adds r.timestamp_public for serving static files from timestamp_public folder" do
|
5
|
+
app(:bare) do
|
6
|
+
plugin :timestamp_public, :root=>'spec/views'
|
7
|
+
|
8
|
+
route do |r|
|
9
|
+
r.timestamp_public
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
status("/about/_test.erb\0").must_equal 404
|
14
|
+
status("/about/_test.erb").must_equal 404
|
15
|
+
status("/static/a/about/_test.erb").must_equal 404
|
16
|
+
status("/static/1/about/_test.erb\0").must_equal 404
|
17
|
+
body("/static/1/about/_test.erb").must_equal File.read('spec/views/about/_test.erb')
|
18
|
+
end
|
19
|
+
|
20
|
+
it "adds r.timestamp_public for serving static files from timestamp_public folder" do
|
21
|
+
app(:bare) do
|
22
|
+
plugin :timestamp_public, :root=>'spec/views', :prefix=>'foo'
|
23
|
+
|
24
|
+
route do |r|
|
25
|
+
r.timestamp_public
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
body("/foo/1/about/_test.erb").must_equal File.read('spec/views/about/_test.erb')
|
30
|
+
end
|
31
|
+
|
32
|
+
it "adds r.timestamp_public for serving static files from timestamp_public folder" do
|
33
|
+
app(:bare) do
|
34
|
+
plugin :timestamp_public, :root=>'spec/plugin'
|
35
|
+
|
36
|
+
route do |r|
|
37
|
+
r.timestamp_public
|
38
|
+
timestamp_path('../views/about/_test.erb')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
mtime = File.mtime('spec/views/about/_test.erb')
|
43
|
+
body.must_equal "/static/#{sprintf("%i%06i", mtime.to_i, mtime.usec)}/../views/about/_test.erb"
|
44
|
+
status("/static/1/../views/about/_test.erb").must_equal 404
|
45
|
+
end
|
46
|
+
|
47
|
+
it "respects the application's :root option" do
|
48
|
+
app(:bare) do
|
49
|
+
opts[:root] = File.expand_path('../../', __FILE__)
|
50
|
+
plugin :timestamp_public, :root=>'views'
|
51
|
+
|
52
|
+
route do |r|
|
53
|
+
r.timestamp_public
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
body('/static/1/about/_test.erb').must_equal File.read('spec/views/about/_test.erb')
|
58
|
+
end
|
59
|
+
|
60
|
+
it "handles serving gzip files in gzip mode if client supports gzip" do
|
61
|
+
app(:bare) do
|
62
|
+
plugin :timestamp_public, :root=>'spec/views', :gzip=>true
|
63
|
+
|
64
|
+
route do |r|
|
65
|
+
r.timestamp_public
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
body('/static/1/about/_test.erb').must_equal File.read('spec/views/about/_test.erb')
|
70
|
+
header('Content-Encoding', '/about/_test.erb').must_be_nil
|
71
|
+
|
72
|
+
body('/static/1/about.erb').must_equal File.read('spec/views/about.erb')
|
73
|
+
header('Content-Encoding', '/about.erb').must_be_nil
|
74
|
+
|
75
|
+
body('/static/1/about/_test.erb', 'HTTP_ACCEPT_ENCODING'=>'deflate, gzip').must_equal File.binread('spec/views/about/_test.erb.gz')
|
76
|
+
h = req('/static/1/about/_test.erb', 'HTTP_ACCEPT_ENCODING'=>'deflate, gzip')[1]
|
77
|
+
h['Content-Encoding'].must_equal 'gzip'
|
78
|
+
h['Content-Type'].must_equal 'text/plain'
|
79
|
+
|
80
|
+
body('/static/1/about/_test.css', 'HTTP_ACCEPT_ENCODING'=>'deflate, gzip').must_equal File.binread('spec/views/about/_test.css.gz')
|
81
|
+
h = req('/static/1/about/_test.css', 'HTTP_ACCEPT_ENCODING'=>'deflate, gzip')[1]
|
82
|
+
h['Content-Encoding'].must_equal 'gzip'
|
83
|
+
h['Content-Type'].must_equal 'text/css'
|
84
|
+
end
|
85
|
+
end
|
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.2.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-11-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -197,6 +197,7 @@ extra_rdoc_files:
|
|
197
197
|
- doc/release_notes/2.29.0.txt
|
198
198
|
- doc/release_notes/3.0.0.txt
|
199
199
|
- doc/release_notes/3.1.0.txt
|
200
|
+
- doc/release_notes/3.2.0.txt
|
200
201
|
files:
|
201
202
|
- CHANGELOG
|
202
203
|
- MIT-LICENSE
|
@@ -240,6 +241,7 @@ files:
|
|
240
241
|
- doc/release_notes/2.9.0.txt
|
241
242
|
- doc/release_notes/3.0.0.txt
|
242
243
|
- doc/release_notes/3.1.0.txt
|
244
|
+
- doc/release_notes/3.2.0.txt
|
243
245
|
- lib/roda.rb
|
244
246
|
- lib/roda/plugins/_symbol_regexp_matchers.rb
|
245
247
|
- lib/roda/plugins/all_verbs.rb
|
@@ -318,6 +320,7 @@ files:
|
|
318
320
|
- lib/roda/plugins/symbol_matchers.rb
|
319
321
|
- lib/roda/plugins/symbol_status.rb
|
320
322
|
- lib/roda/plugins/symbol_views.rb
|
323
|
+
- lib/roda/plugins/timestamp_public.rb
|
321
324
|
- lib/roda/plugins/type_routing.rb
|
322
325
|
- lib/roda/plugins/unescape_path.rb
|
323
326
|
- lib/roda/plugins/view_options.rb
|
@@ -409,6 +412,7 @@ files:
|
|
409
412
|
- spec/plugin/symbol_matchers_spec.rb
|
410
413
|
- spec/plugin/symbol_status_spec.rb
|
411
414
|
- spec/plugin/symbol_views_spec.rb
|
415
|
+
- spec/plugin/timestamp_public_spec.rb
|
412
416
|
- spec/plugin/type_routing_spec.rb
|
413
417
|
- spec/plugin/unescape_path_spec.rb
|
414
418
|
- spec/plugin/view_options_spec.rb
|