roda 3.11.0 → 3.12.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 +4 -0
- data/doc/release_notes/3.12.0.txt +19 -0
- data/lib/roda/plugins/_after_hook.rb +1 -1
- data/lib/roda/plugins/_before_hook.rb +1 -1
- data/lib/roda/plugins/class_level_routing.rb +1 -1
- data/lib/roda/plugins/common_logger.rb +70 -0
- data/lib/roda/plugins/flash.rb +1 -1
- data/lib/roda/plugins/head.rb +1 -1
- data/lib/roda/plugins/heartbeat.rb +1 -1
- data/lib/roda/plugins/hooks.rb +2 -2
- data/lib/roda/plugins/sessions.rb +1 -1
- data/lib/roda/plugins/static_routing.rb +1 -1
- data/lib/roda/plugins/status_handler.rb +1 -1
- data/lib/roda/version.rb +1 -1
- data/spec/plugin/common_logger_spec.rb +59 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0839d9d46fb688ab858d224dff6293be6572d9fc2938ea0696cb34bc6cb14949'
|
|
4
|
+
data.tar.gz: c3cbc4adc620b1f4776d8258e44751f7206837ba12a6a8e4917e5bf6d5a7efec
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7e595d7c11c1486131b3e46b596c6d38a65dac41bb72e686fdbc260f629ce4a639543501e30754412d6252942204d8fa906579bb54a6ff224233dfb333610bfd
|
|
7
|
+
data.tar.gz: 97f598575e2a13907021cb9024cfa4c6c7c6e1ce68c69639794f89db068a7ee2c27b35bace18b568ae841ae51b6ebf6404c611f3f3f1692b48b95bf1207073a4
|
data/CHANGELOG
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
= New Features
|
|
2
|
+
|
|
3
|
+
* A common_logger plugin has been added for common log support. This
|
|
4
|
+
offers about 30% better performance than Rack::CommonLogger, with
|
|
5
|
+
the following differences:
|
|
6
|
+
|
|
7
|
+
* When timing requests, doesn't consider middleware or proxy the
|
|
8
|
+
body, so timing information is just the time that Roda takes
|
|
9
|
+
to process the request.
|
|
10
|
+
* Only looks for "Content-Length" as a header, not different
|
|
11
|
+
capitalizations (Roda only uses "Content-Length" internally).
|
|
12
|
+
* Logs to $stderr instead of rack.errors in request environment
|
|
13
|
+
if a logger object is not explicitly passed.
|
|
14
|
+
|
|
15
|
+
= Other Improvements
|
|
16
|
+
|
|
17
|
+
* Internal before/after hook methods now use more descriptive names
|
|
18
|
+
for easier debugging, with a naming format designed to not
|
|
19
|
+
conflict with hook methods in external plugins.
|
|
@@ -13,7 +13,7 @@ class Roda
|
|
|
13
13
|
# have added a _roda_after_* method.
|
|
14
14
|
def include(*)
|
|
15
15
|
res = super
|
|
16
|
-
meths = private_instance_methods.grep(/\A_roda_after_\d\d
|
|
16
|
+
meths = private_instance_methods.grep(/\A_roda_after_\d\d/).sort.map{|s| "#{s}(res)"}.join(';')
|
|
17
17
|
class_eval("def _roda_after(res); #{meths} end", __FILE__, __LINE__)
|
|
18
18
|
private :_roda_after
|
|
19
19
|
res
|
|
@@ -31,7 +31,7 @@ class Roda
|
|
|
31
31
|
# Build a _roda_before method that calls each _roda_before_* method
|
|
32
32
|
# in order.
|
|
33
33
|
def def_roda_before
|
|
34
|
-
meths = private_instance_methods.grep(/\A_roda_before_\d\d
|
|
34
|
+
meths = private_instance_methods.grep(/\A_roda_before_\d\d/).sort.join(';')
|
|
35
35
|
class_eval("def _roda_before; #{meths} end", __FILE__, __LINE__)
|
|
36
36
|
private :_roda_before
|
|
37
37
|
end
|
|
@@ -89,7 +89,7 @@ class Roda
|
|
|
89
89
|
|
|
90
90
|
# If the normal routing tree doesn't handle an action, try each class level route
|
|
91
91
|
# to see if it matches.
|
|
92
|
-
def
|
|
92
|
+
def _roda_after_10__class_level_routing(result)
|
|
93
93
|
if result && result[0] == 404 && (v = result[2]).is_a?(Array) && v.empty?
|
|
94
94
|
# Reset the response so it doesn't inherit the status or any headers from
|
|
95
95
|
# the original response.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The common_logger plugin adds common logger support to Roda
|
|
7
|
+
# applications, similar to Rack::CommonLogger, with the following
|
|
8
|
+
# differences:
|
|
9
|
+
#
|
|
10
|
+
# * Better performance
|
|
11
|
+
# * Doesn't include middleware timing
|
|
12
|
+
# * Doesn't proxy the body
|
|
13
|
+
# * Doesn't support different capitalization of the Content-Length response header
|
|
14
|
+
# * Logs to $stderr instead of env['rack.errors'] if explicit logger not passed
|
|
15
|
+
#
|
|
16
|
+
# Example:
|
|
17
|
+
#
|
|
18
|
+
# plugin :common_logger
|
|
19
|
+
# plugin :common_logger, $stdout
|
|
20
|
+
# plugin :common_logger, Logger.new('filename')
|
|
21
|
+
module CommonLogger
|
|
22
|
+
def self.load_dependencies(app, _=nil)
|
|
23
|
+
app.plugin :_after_hook
|
|
24
|
+
app.plugin :_before_hook
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.configure(app, logger=nil)
|
|
28
|
+
app.opts[:common_logger] = logger || app.opts[:common_logger] || $stderr
|
|
29
|
+
app.opts[:common_logger_meth] = app.opts[:common_logger].method(logger.respond_to?(:write) ? :write : :<<)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if RUBY_VERSION >= '2.1'
|
|
33
|
+
# A timer object for calculating elapsed time.
|
|
34
|
+
def self.start_timer
|
|
35
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
36
|
+
end
|
|
37
|
+
else
|
|
38
|
+
# :nocov:
|
|
39
|
+
def self.start_timer # :nodoc:
|
|
40
|
+
Time.now
|
|
41
|
+
end
|
|
42
|
+
# :nocov:
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
module InstanceMethods
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
# Log request/response information in common log format to logger.
|
|
49
|
+
def _roda_after_90__common_logger(result)
|
|
50
|
+
elapsed_time = if timer = @_request_timer
|
|
51
|
+
'%0.4f' % (CommonLogger.start_timer - timer)
|
|
52
|
+
else
|
|
53
|
+
'-'
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
env = @_request.env
|
|
57
|
+
|
|
58
|
+
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["PATH_INFO"]}#{"?#{env["QUERY_STRING"]}" if ((qs = env["QUERY_STRING"]) && !qs.empty?)} #{env["HTTP_VERSION"]}\" #{result[0]} #{((length = result[1]['Content-Length']) && (length unless length == '0')) || '-'} #{elapsed_time}\n")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Create timer instance used for timing
|
|
62
|
+
def _roda_before_05__common_logger
|
|
63
|
+
@_request_timer = CommonLogger.start_timer
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
register_plugin(:common_logger, CommonLogger)
|
|
69
|
+
end
|
|
70
|
+
end
|
data/lib/roda/plugins/flash.rb
CHANGED
data/lib/roda/plugins/head.rb
CHANGED
|
@@ -29,7 +29,7 @@ class Roda
|
|
|
29
29
|
private
|
|
30
30
|
|
|
31
31
|
# If the request is for a heartbeat path, return the heartbeat response.
|
|
32
|
-
def
|
|
32
|
+
def _roda_before_20__heartbeat
|
|
33
33
|
if env['PATH_INFO'] == opts[:heartbeat_path]
|
|
34
34
|
response = HEARTBEAT_RESPONSE.dup
|
|
35
35
|
response[1] = Hash[response[1]]
|
data/lib/roda/plugins/hooks.rb
CHANGED
|
@@ -79,14 +79,14 @@ class Roda
|
|
|
79
79
|
private
|
|
80
80
|
|
|
81
81
|
# Run after hooks.
|
|
82
|
-
def
|
|
82
|
+
def _roda_after_80__hooks(res)
|
|
83
83
|
if b = opts[:after_hook]
|
|
84
84
|
instance_exec(res, &b)
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
# Run before hooks.
|
|
89
|
-
def
|
|
89
|
+
def _roda_before_10__hooks
|
|
90
90
|
if b = opts[:before_hook]
|
|
91
91
|
instance_exec(&b)
|
|
92
92
|
end
|
|
@@ -208,7 +208,7 @@ class Roda
|
|
|
208
208
|
# If session information has been set in the request environment,
|
|
209
209
|
# update the rack response headers to set the session cookie in
|
|
210
210
|
# the response.
|
|
211
|
-
def
|
|
211
|
+
def _roda_after_50__sessions(res)
|
|
212
212
|
if res && (session = env['rack.session'])
|
|
213
213
|
@_request.persist_session(res[1], session)
|
|
214
214
|
end
|
|
@@ -109,7 +109,7 @@ class Roda
|
|
|
109
109
|
|
|
110
110
|
# If there is a static routing method for the given path, call it
|
|
111
111
|
# instead having the routing tree handle the request.
|
|
112
|
-
def
|
|
112
|
+
def _roda_before_30__static_routing
|
|
113
113
|
r = @_request
|
|
114
114
|
if route = self.class.static_route_for(r.request_method, r.path_info)
|
|
115
115
|
r.static_route(&route)
|
|
@@ -48,7 +48,7 @@ class Roda
|
|
|
48
48
|
private
|
|
49
49
|
|
|
50
50
|
# If routing returns a response we have a handler for, call that handler.
|
|
51
|
-
def
|
|
51
|
+
def _roda_after_20__status_handler(result)
|
|
52
52
|
if result && (block = opts[:status_handler][result[0]]) && (v = result[2]).is_a?(Array) && v.empty?
|
|
53
53
|
@_response.headers.clear
|
|
54
54
|
result.replace(_call(&block))
|
data/lib/roda/version.rb
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require_relative "../spec_helper"
|
|
2
|
+
|
|
3
|
+
require 'logger'
|
|
4
|
+
|
|
5
|
+
describe "common_logger plugin" do
|
|
6
|
+
def cl_app(&block)
|
|
7
|
+
app(:common_logger, &block)
|
|
8
|
+
@logger = StringIO.new
|
|
9
|
+
@app.plugin :common_logger, @logger
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'logs requests to given logger/stream' do
|
|
13
|
+
cl_app(&:path_info)
|
|
14
|
+
|
|
15
|
+
body.must_equal '/'
|
|
16
|
+
@logger.rewind
|
|
17
|
+
@logger.read.must_match /\A- - - \[\d\d\/[A-Z][a-z]{2}\/\d\d\d\d:\d\d:\d\d:\d\d [-+]\d\d\d\d\] "GET \/ " 200 1 0.\d\d\d\d\n\z/
|
|
18
|
+
|
|
19
|
+
@logger.rewind
|
|
20
|
+
@logger.truncate(0)
|
|
21
|
+
body('', 'HTTP_X_FORWARDED_FOR'=>'1.1.1.1', 'REMOTE_USER'=>'je', 'REQUEST_METHOD'=>'POST', 'QUERY_STRING'=>'', "HTTP_VERSION"=>'HTTP/1.1').must_equal ''
|
|
22
|
+
@logger.rewind
|
|
23
|
+
@logger.read.must_match /\A1\.1\.1\.1 - je \[\d\d\/[A-Z][a-z]{2}\/\d\d\d\d:\d\d:\d\d:\d\d [-+]\d\d\d\d\] "POST HTTP\/1.1" 200 - 0.\d\d\d\d\n\z/
|
|
24
|
+
|
|
25
|
+
@logger.rewind
|
|
26
|
+
@logger.truncate(0)
|
|
27
|
+
body('/b', 'REMOTE_ADDR'=>'1.1.1.2', 'QUERY_STRING'=>'foo=bar', "HTTP_VERSION"=>'HTTP/1.0').must_equal '/b'
|
|
28
|
+
@logger.rewind
|
|
29
|
+
@logger.read.must_match /\A1\.1\.1\.2 - - \[\d\d\/[A-Z][a-z]{2}\/\d\d\d\d:\d\d:\d\d:\d\d [-+]\d\d\d\d\] "GET \/b\?foo=bar HTTP\/1.0" 200 2 0.\d\d\d\d\n\z/
|
|
30
|
+
|
|
31
|
+
@app.plugin :common_logger, Logger.new(@logger)
|
|
32
|
+
@logger.rewind
|
|
33
|
+
@logger.truncate(0)
|
|
34
|
+
body.must_equal '/'
|
|
35
|
+
@logger.rewind
|
|
36
|
+
@logger.read.must_match /\A- - - \[\d\d\/[A-Z][a-z]{2}\/\d\d\d\d:\d\d:\d\d:\d\d [-+]\d\d\d\d\] "GET \/ " 200 1 0.\d\d\d\d\n\z/
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'skips timer information if not available' do
|
|
40
|
+
cl_app do |r|
|
|
41
|
+
@_request_timer = nil
|
|
42
|
+
r.path_info
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
body.must_equal '/'
|
|
46
|
+
@logger.rewind
|
|
47
|
+
@logger.read.must_match /\A- - - \[\d\d\/[A-Z][a-z]{2}\/\d\d\d\d:\d\d:\d\d:\d\d [-+]\d\d\d\d\] "GET \/ " 200 1 -\n\z/
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'skips length information if not available' do
|
|
51
|
+
cl_app do |r|
|
|
52
|
+
r.halt [500, {}, []]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
body.must_equal ''
|
|
56
|
+
@logger.rewind
|
|
57
|
+
@logger.read.must_match /\A- - - \[\d\d\/[A-Z][a-z]{2}\/\d\d\d\d:\d\d:\d\d:\d\d [-+]\d\d\d\d\] "GET \/ " 500 - 0.\d\d\d\d\n\z/
|
|
58
|
+
end
|
|
59
|
+
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.12.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: 2018-
|
|
11
|
+
date: 2018-09-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|
|
@@ -207,6 +207,7 @@ extra_rdoc_files:
|
|
|
207
207
|
- doc/release_notes/3.9.0.txt
|
|
208
208
|
- doc/release_notes/3.10.0.txt
|
|
209
209
|
- doc/release_notes/3.11.0.txt
|
|
210
|
+
- doc/release_notes/3.12.0.txt
|
|
210
211
|
files:
|
|
211
212
|
- CHANGELOG
|
|
212
213
|
- MIT-LICENSE
|
|
@@ -252,6 +253,7 @@ files:
|
|
|
252
253
|
- doc/release_notes/3.1.0.txt
|
|
253
254
|
- doc/release_notes/3.10.0.txt
|
|
254
255
|
- doc/release_notes/3.11.0.txt
|
|
256
|
+
- doc/release_notes/3.12.0.txt
|
|
255
257
|
- doc/release_notes/3.2.0.txt
|
|
256
258
|
- doc/release_notes/3.3.0.txt
|
|
257
259
|
- doc/release_notes/3.4.0.txt
|
|
@@ -273,6 +275,7 @@ files:
|
|
|
273
275
|
- lib/roda/plugins/chunked.rb
|
|
274
276
|
- lib/roda/plugins/class_level_routing.rb
|
|
275
277
|
- lib/roda/plugins/class_matchers.rb
|
|
278
|
+
- lib/roda/plugins/common_logger.rb
|
|
276
279
|
- lib/roda/plugins/content_for.rb
|
|
277
280
|
- lib/roda/plugins/content_security_policy.rb
|
|
278
281
|
- lib/roda/plugins/cookies.rb
|
|
@@ -373,6 +376,7 @@ files:
|
|
|
373
376
|
- spec/plugin/chunked_spec.rb
|
|
374
377
|
- spec/plugin/class_level_routing_spec.rb
|
|
375
378
|
- spec/plugin/class_matchers_spec.rb
|
|
379
|
+
- spec/plugin/common_logger_spec.rb
|
|
376
380
|
- spec/plugin/content_for_spec.rb
|
|
377
381
|
- spec/plugin/content_security_policy_spec.rb
|
|
378
382
|
- spec/plugin/cookies_spec.rb
|