rack-contrib 2.2.0 → 2.3.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.
Potentially problematic release.
This version of rack-contrib might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +0 -1
- data/lib/rack/contrib.rb +2 -1
- data/lib/rack/contrib/access.rb +6 -4
- data/lib/rack/contrib/backstage.rb +3 -1
- data/lib/rack/contrib/bounce_favicon.rb +2 -0
- data/lib/rack/contrib/callbacks.rb +2 -0
- data/lib/rack/contrib/common_cookies.rb +16 -11
- data/lib/rack/contrib/config.rb +3 -15
- data/lib/rack/contrib/cookies.rb +2 -0
- data/lib/rack/contrib/csshttprequest.rb +9 -5
- data/lib/rack/contrib/deflect.rb +34 -32
- data/lib/rack/contrib/enforce_valid_encoding.rb +2 -0
- data/lib/rack/contrib/evil.rb +2 -0
- data/lib/rack/contrib/expectation_cascade.rb +3 -1
- data/lib/rack/contrib/garbagecollector.rb +2 -0
- data/lib/rack/contrib/host_meta.rb +2 -0
- data/lib/rack/contrib/json_body_parser.rb +9 -7
- data/lib/rack/contrib/jsonp.rb +7 -5
- data/lib/rack/contrib/lazy_conditional_get.rb +9 -0
- data/lib/rack/contrib/lighttpd_script_name_fix.rb +2 -0
- data/lib/rack/contrib/locale.rb +3 -0
- data/lib/rack/contrib/mailexceptions.rb +3 -1
- data/lib/rack/contrib/nested_params.rb +3 -1
- data/lib/rack/contrib/not_found.rb +2 -0
- data/lib/rack/contrib/post_body_content_type_parser.rb +2 -0
- data/lib/rack/contrib/printout.rb +2 -0
- data/lib/rack/contrib/proctitle.rb +2 -0
- data/lib/rack/contrib/profiler.rb +2 -0
- data/lib/rack/contrib/relative_redirect.rb +10 -5
- data/lib/rack/contrib/response_cache.rb +12 -11
- data/lib/rack/contrib/response_headers.rb +2 -0
- data/lib/rack/contrib/route_exceptions.rb +2 -0
- data/lib/rack/contrib/runtime.rb +3 -30
- data/lib/rack/contrib/signals.rb +6 -0
- data/lib/rack/contrib/simple_endpoint.rb +3 -1
- data/lib/rack/contrib/static_cache.rb +10 -3
- data/lib/rack/contrib/time_zone.rb +2 -0
- data/lib/rack/contrib/try_static.rb +2 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf14e9cb70d9701bc1f3fe5ce036a0667f4ba6c9411e0e6ded73ef958228ec45
|
4
|
+
data.tar.gz: d0c2abe31908dd0d49dec3635cca17c720c94d098a04e9485adf917c469e0ee5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f352f5eac5008e79d645460cd9b17dcc7231fe55edb63a0540c6c0991c06ba5f989cd70c23453e854a8189bcd02ad1be96366bb4d24efdaccefc5fe823a9eed5
|
7
|
+
data.tar.gz: 379d6d0190a63d1df9c615e2fdd53bfebcac0cf506407e1e8a11c734ffc955f066a2aa56e79db21458b62efbb6603e1749f1bdddaed1c35fb84a69cd494dba8f
|
data/README.md
CHANGED
@@ -8,7 +8,6 @@ interface:
|
|
8
8
|
* `Rack::BounceFavicon` - Returns a 404 for requests to `/favicon.ico`
|
9
9
|
* `Rack::CSSHTTPRequest` - Adds CSSHTTPRequest support by encoding responses as CSS for cross-site AJAX-style data loading
|
10
10
|
* `Rack::Callbacks` - Implements DSL for pure before/after filter like Middlewares.
|
11
|
-
* `Rack::Config` - Shared configuration for cooperative middleware.
|
12
11
|
* `Rack::Cookies` - Adds simple cookie jar hash to env
|
13
12
|
* `Rack::Deflect` - Helps protect against DoS attacks.
|
14
13
|
* `Rack::Evil` - Lets the rack application return a response to the client from any place.
|
data/lib/rack/contrib.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack'
|
2
4
|
|
3
5
|
module Rack
|
@@ -33,7 +35,6 @@ module Rack
|
|
33
35
|
autoload :ProcTitle, "rack/contrib/proctitle"
|
34
36
|
autoload :Profiler, "rack/contrib/profiler"
|
35
37
|
autoload :ResponseHeaders, "rack/contrib/response_headers"
|
36
|
-
autoload :Runtime, "rack/contrib/runtime"
|
37
38
|
autoload :Signals, "rack/contrib/signals"
|
38
39
|
autoload :SimpleEndpoint, "rack/contrib/simple_endpoint"
|
39
40
|
autoload :TimeZone, "rack/contrib/time_zone"
|
data/lib/rack/contrib/access.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "ipaddr"
|
2
4
|
|
3
5
|
module Rack
|
@@ -48,9 +50,9 @@ module Rack
|
|
48
50
|
end
|
49
51
|
|
50
52
|
def call(env)
|
51
|
-
|
53
|
+
request = Request.new(env)
|
52
54
|
ipmasks = ipmasks_for_path(env)
|
53
|
-
return forbidden! unless ip_authorized?(ipmasks)
|
55
|
+
return forbidden! unless ip_authorized?(request, ipmasks)
|
54
56
|
status, headers, body = @app.call(env)
|
55
57
|
[status, headers, body]
|
56
58
|
end
|
@@ -73,11 +75,11 @@ module Rack
|
|
73
75
|
[403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, []]
|
74
76
|
end
|
75
77
|
|
76
|
-
def ip_authorized?(ipmasks)
|
78
|
+
def ip_authorized?(request, ipmasks)
|
77
79
|
return true if ipmasks.nil?
|
78
80
|
|
79
81
|
ipmasks.any? do |ip_mask|
|
80
|
-
ip_mask.include?(IPAddr.new(
|
82
|
+
ip_mask.include?(IPAddr.new(request.ip))
|
81
83
|
end
|
82
84
|
end
|
83
85
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
class Backstage
|
3
5
|
File = ::File
|
@@ -10,7 +12,7 @@ module Rack
|
|
10
12
|
def call(env)
|
11
13
|
if File.exists?(@file)
|
12
14
|
content = File.read(@file)
|
13
|
-
length =
|
15
|
+
length = content.bytesize.to_s
|
14
16
|
[503, {'Content-Type' => 'text/html', 'Content-Length' => length}, [content]]
|
15
17
|
else
|
16
18
|
@app.call(env)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
# Rack middleware to use common cookies across domain and subdomains.
|
3
5
|
class CommonCookies
|
@@ -10,21 +12,24 @@ module Rack
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def call(env)
|
13
|
-
@app.call(env)
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
status, headers, body = @app.call(env)
|
16
|
+
headers = Utils::HeaderHash.new(headers)
|
17
|
+
|
18
|
+
host = env['HTTP_HOST'].sub PORT, ''
|
19
|
+
share_cookie(headers, host)
|
20
|
+
|
21
|
+
[status, headers, body]
|
17
22
|
end
|
18
23
|
|
19
24
|
private
|
20
25
|
|
21
|
-
def domain
|
22
|
-
|
26
|
+
def domain(host)
|
27
|
+
host =~ DOMAIN_REGEXP
|
23
28
|
".#{$1}.#{$2}"
|
24
29
|
end
|
25
30
|
|
26
|
-
def share_cookie(headers)
|
27
|
-
headers['Set-Cookie'] &&= common_cookie(headers) if
|
31
|
+
def share_cookie(headers, host)
|
32
|
+
headers['Set-Cookie'] &&= common_cookie(headers, host) if host !~ LOCALHOST_OR_IP_REGEXP
|
28
33
|
end
|
29
34
|
|
30
35
|
def cookie(headers)
|
@@ -32,8 +37,8 @@ module Rack
|
|
32
37
|
cookies.is_a?(Array) ? cookies.join("\n") : cookies
|
33
38
|
end
|
34
39
|
|
35
|
-
def common_cookie(headers)
|
36
|
-
cookie(headers).gsub(/; domain=[^;]*/, '').gsub(/$/, "; domain=#{domain}")
|
40
|
+
def common_cookie(headers, host)
|
41
|
+
cookie(headers).gsub(/; domain=[^;]*/, '').gsub(/$/, "; domain=#{domain(host)}")
|
37
42
|
end
|
38
43
|
end
|
39
|
-
end
|
44
|
+
end
|
data/lib/rack/contrib/config.rb
CHANGED
@@ -1,16 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
class Config
|
6
|
-
def initialize(app, &block)
|
7
|
-
@app = app
|
8
|
-
@block = block
|
9
|
-
end
|
10
|
-
|
11
|
-
def call(env)
|
12
|
-
@block.call(env)
|
13
|
-
@app.call(env)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
3
|
+
require 'rack'
|
4
|
+
require 'rack/config'
|
data/lib/rack/contrib/cookies.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'csshttprequest'
|
2
4
|
|
3
5
|
module Rack
|
@@ -13,9 +15,12 @@ module Rack
|
|
13
15
|
# the CSSHTTPRequest encoder
|
14
16
|
def call(env)
|
15
17
|
status, headers, response = @app.call(env)
|
18
|
+
headers = Utils::HeaderHash.new(headers)
|
19
|
+
|
16
20
|
if chr_request?(env)
|
17
|
-
|
18
|
-
modify_headers!(headers,
|
21
|
+
encoded_response = encode(response)
|
22
|
+
modify_headers!(headers, encoded_response)
|
23
|
+
response = [encoded_response]
|
19
24
|
end
|
20
25
|
[status, headers, response]
|
21
26
|
end
|
@@ -25,9 +30,8 @@ module Rack
|
|
25
30
|
!(/\.chr$/.match(env['PATH_INFO'])).nil? || Rack::Request.new(env).params['_format'] == 'chr'
|
26
31
|
end
|
27
32
|
|
28
|
-
def encode(
|
29
|
-
|
30
|
-
return ::CSSHTTPRequest.encode(assembled_body)
|
33
|
+
def encode(body)
|
34
|
+
::CSSHTTPRequest.encode(body.to_enum.to_a.join)
|
31
35
|
end
|
32
36
|
|
33
37
|
def modify_headers!(headers, encoded_response)
|
data/lib/rack/contrib/deflect.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'thread'
|
2
4
|
|
3
5
|
# TODO: optional stats
|
@@ -67,10 +69,10 @@ module Rack
|
|
67
69
|
end
|
68
70
|
|
69
71
|
def deflect? env
|
70
|
-
|
71
|
-
return false if options[:whitelist].include?
|
72
|
-
return true if options[:blacklist].include?
|
73
|
-
sync { watch }
|
72
|
+
remote_addr = env['REMOTE_ADDR']
|
73
|
+
return false if options[:whitelist].include? remote_addr
|
74
|
+
return true if options[:blacklist].include? remote_addr
|
75
|
+
sync { watch(remote_addr) }
|
74
76
|
end
|
75
77
|
|
76
78
|
def log message
|
@@ -82,55 +84,55 @@ module Rack
|
|
82
84
|
@mutex.synchronize(&block)
|
83
85
|
end
|
84
86
|
|
85
|
-
def map
|
86
|
-
@remote_addr_map[
|
87
|
+
def map(remote_addr)
|
88
|
+
@remote_addr_map[remote_addr] ||= {
|
87
89
|
:expires => Time.now + options[:interval],
|
88
90
|
:requests => 0
|
89
91
|
}
|
90
92
|
end
|
91
93
|
|
92
|
-
def watch
|
93
|
-
increment_requests
|
94
|
-
clear! if watch_expired? and not blocked?
|
95
|
-
clear! if blocked? and block_expired?
|
96
|
-
block! if watching? and exceeded_request_threshold?
|
97
|
-
blocked?
|
94
|
+
def watch(remote_addr)
|
95
|
+
increment_requests(remote_addr)
|
96
|
+
clear!(remote_addr) if watch_expired?(remote_addr) and not blocked?(remote_addr)
|
97
|
+
clear!(remote_addr) if blocked?(remote_addr) and block_expired?(remote_addr)
|
98
|
+
block!(remote_addr) if watching?(remote_addr) and exceeded_request_threshold?(remote_addr)
|
99
|
+
blocked?(remote_addr)
|
98
100
|
end
|
99
101
|
|
100
|
-
def block!
|
101
|
-
return if blocked?
|
102
|
-
log "blocked #{
|
103
|
-
map[:block_expires] = Time.now + options[:block_duration]
|
102
|
+
def block!(remote_addr)
|
103
|
+
return if blocked?(remote_addr)
|
104
|
+
log "blocked #{remote_addr}"
|
105
|
+
map(remote_addr)[:block_expires] = Time.now + options[:block_duration]
|
104
106
|
end
|
105
107
|
|
106
|
-
def blocked?
|
107
|
-
map.has_key? :block_expires
|
108
|
+
def blocked?(remote_addr)
|
109
|
+
map(remote_addr).has_key? :block_expires
|
108
110
|
end
|
109
111
|
|
110
|
-
def block_expired?
|
111
|
-
map[:block_expires] < Time.now rescue false
|
112
|
+
def block_expired?(remote_addr)
|
113
|
+
map(remote_addr)[:block_expires] < Time.now rescue false
|
112
114
|
end
|
113
115
|
|
114
|
-
def watching?
|
115
|
-
@remote_addr_map.has_key?
|
116
|
+
def watching?(remote_addr)
|
117
|
+
@remote_addr_map.has_key? remote_addr
|
116
118
|
end
|
117
119
|
|
118
|
-
def clear!
|
119
|
-
return unless watching?
|
120
|
-
log "released #{
|
121
|
-
@remote_addr_map.delete
|
120
|
+
def clear!(remote_addr)
|
121
|
+
return unless watching?(remote_addr)
|
122
|
+
log "released #{remote_addr}" if blocked?(remote_addr)
|
123
|
+
@remote_addr_map.delete remote_addr
|
122
124
|
end
|
123
125
|
|
124
|
-
def increment_requests
|
125
|
-
map[:requests] += 1
|
126
|
+
def increment_requests(remote_addr)
|
127
|
+
map(remote_addr)[:requests] += 1
|
126
128
|
end
|
127
129
|
|
128
|
-
def exceeded_request_threshold?
|
129
|
-
map[:requests] > options[:request_threshold]
|
130
|
+
def exceeded_request_threshold?(remote_addr)
|
131
|
+
map(remote_addr)[:requests] > options[:request_threshold]
|
130
132
|
end
|
131
133
|
|
132
|
-
def watch_expired?
|
133
|
-
map[:expires] <= Time.now
|
134
|
+
def watch_expired?(remote_addr)
|
135
|
+
map(remote_addr)[:expires] <= Time.now
|
134
136
|
end
|
135
137
|
|
136
138
|
end
|
data/lib/rack/contrib/evil.rb
CHANGED
@@ -55,16 +55,18 @@ module Rack
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def call(env)
|
58
|
-
|
59
|
-
|
58
|
+
begin
|
59
|
+
if @verbs.include?(env[Rack::REQUEST_METHOD]) &&
|
60
|
+
@matcher.call(@media, env['CONTENT_TYPE'])
|
60
61
|
|
61
|
-
|
62
|
+
update_form_hash_with_json_body(env)
|
63
|
+
end
|
64
|
+
rescue JSON::ParserError
|
65
|
+
body = { error: 'Failed to parse body as JSON' }.to_json
|
66
|
+
header = { 'Content-Type' => 'application/json' }
|
67
|
+
return Rack::Response.new(body, 400, header).finish
|
62
68
|
end
|
63
69
|
@app.call(env)
|
64
|
-
rescue JSON::ParserError
|
65
|
-
body = { error: 'Failed to parse body as JSON' }.to_json
|
66
|
-
header = { 'Content-Type' => 'application/json' }
|
67
|
-
Rack::Response.new(body, 400, header).finish
|
68
70
|
end
|
69
71
|
|
70
72
|
private
|
data/lib/rack/contrib/jsonp.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
|
3
5
|
# A Rack middleware for providing JSON-P support.
|
@@ -53,7 +55,7 @@ module Rack
|
|
53
55
|
|
54
56
|
# Set new Content-Length, if it was set before we mutated the response body
|
55
57
|
if headers['Content-Length']
|
56
|
-
length = response.
|
58
|
+
length = response.map(&:bytesize).reduce(0, :+)
|
57
59
|
headers['Content-Length'] = length.to_s
|
58
60
|
end
|
59
61
|
end
|
@@ -87,8 +89,8 @@ module Rack
|
|
87
89
|
# method of combining all of the data into a single string makes sense
|
88
90
|
# since JSON is returned as a full string.
|
89
91
|
#
|
90
|
-
def pad(callback, response
|
91
|
-
response.
|
92
|
+
def pad(callback, response)
|
93
|
+
body = response.to_enum.map do |s|
|
92
94
|
# U+2028 and U+2029 are allowed inside strings in JSON (as all literal
|
93
95
|
# Unicode characters) but JavaScript defines them as newline
|
94
96
|
# seperators. Because no literal newlines are allowed in a string, this
|
@@ -96,8 +98,8 @@ module Rack
|
|
96
98
|
# replacing them with the escaped version. This should be safe because
|
97
99
|
# according to the JSON spec, these characters are *only* valid inside
|
98
100
|
# a string and should therefore not be present any other places.
|
99
|
-
|
100
|
-
end
|
101
|
+
s.gsub(U2028, '\u2028').gsub(U2029, '\u2029')
|
102
|
+
end.join
|
101
103
|
|
102
104
|
# https://github.com/rack/rack-contrib/issues/46
|
103
105
|
response.close if response.respond_to?(:close)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
|
3
5
|
##
|
@@ -43,6 +45,10 @@ module Rack
|
|
43
45
|
# know for sure that it does not modify the cached content, you can set the
|
44
46
|
# `Rack-Lazy-Conditional-Get` on response to `skip`. This will not update the
|
45
47
|
# global modification date.
|
48
|
+
#
|
49
|
+
# NOTE: This will not work properly in a multi-threaded environment with
|
50
|
+
# default cache object. A provided cache object should ensure thread-safety
|
51
|
+
# of the `get`/`set`/`[]`/`[]=` methods.
|
46
52
|
|
47
53
|
class LazyConditionalGet
|
48
54
|
|
@@ -70,7 +76,10 @@ module Rack
|
|
70
76
|
if reading? env and fresh? env
|
71
77
|
return [304, {'Last-Modified' => env['HTTP_IF_MODIFIED_SINCE']}, []]
|
72
78
|
end
|
79
|
+
|
73
80
|
status, headers, body = @app.call env
|
81
|
+
headers = Utils::HeaderHash.new(headers)
|
82
|
+
|
74
83
|
update_cache unless (reading?(env) or skipping?(headers))
|
75
84
|
headers['Last-Modified'] = cached_value if stampable? headers
|
76
85
|
[status, headers, body]
|
data/lib/rack/contrib/locale.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'i18n'
|
2
4
|
|
3
5
|
module Rack
|
@@ -14,6 +16,7 @@ module Rack
|
|
14
16
|
|
15
17
|
env['rack.locale'] = I18n.locale = locale.to_s
|
16
18
|
status, headers, body = @app.call(env)
|
19
|
+
headers = Utils::HeaderHash.new(headers)
|
17
20
|
|
18
21
|
unless headers['Content-Language']
|
19
22
|
headers['Content-Language'] = locale.to_s
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'net/smtp'
|
2
4
|
require 'mail'
|
3
5
|
require 'erb'
|
@@ -104,7 +106,7 @@ module Rack
|
|
104
106
|
|
105
107
|
def extract_body(env)
|
106
108
|
if io = env['rack.input']
|
107
|
-
io.rewind
|
109
|
+
io.rewind
|
108
110
|
io.read
|
109
111
|
end
|
110
112
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack/utils'
|
2
4
|
|
3
5
|
module Rack
|
@@ -24,7 +26,7 @@ module Rack
|
|
24
26
|
post_body = env[POST_BODY]
|
25
27
|
env[FORM_INPUT] = post_body
|
26
28
|
env[FORM_HASH] = Rack::Utils.parse_nested_query(post_body.read)
|
27
|
-
post_body.rewind
|
29
|
+
post_body.rewind
|
28
30
|
end
|
29
31
|
@app.call(env)
|
30
32
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack'
|
2
4
|
|
3
5
|
# Rack::RelativeRedirect is a simple middleware that converts relative paths in
|
@@ -30,15 +32,18 @@ class Rack::RelativeRedirect
|
|
30
32
|
# and use that to make the Location header an absolute url. If the Location
|
31
33
|
# does not start with a slash, make location relative to the path requested.
|
32
34
|
def call(env)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
status, headers, body = @app.call(env)
|
36
|
+
headers = Rack::Utils::HeaderHash.new(headers)
|
37
|
+
|
38
|
+
if [301,302,303, 307,308].include?(status) and loc = headers['Location'] and !%r{\Ahttps?://}o.match(loc)
|
39
|
+
absolute = @absolute_proc.call(env, [status, headers, body])
|
40
|
+
headers['Location'] = if %r{\A/}.match(loc)
|
37
41
|
"#{absolute}#{loc}"
|
38
42
|
else
|
39
43
|
"#{absolute}#{File.dirname(Rack::Utils.unescape(env['PATH_INFO']))}/#{loc}"
|
40
44
|
end
|
41
45
|
end
|
42
|
-
|
46
|
+
|
47
|
+
[status, headers, body]
|
43
48
|
end
|
44
49
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fileutils'
|
2
4
|
require 'rack'
|
3
5
|
|
@@ -19,12 +21,8 @@ class Rack::ResponseCache
|
|
19
21
|
DEFAULT_PATH_PROC = proc do |env, res|
|
20
22
|
path = Rack::Utils.unescape(env['PATH_INFO'])
|
21
23
|
headers = res[1]
|
22
|
-
|
23
|
-
|
24
|
-
content_type = headers.fetch('Content-Type') do |titlecase_key|
|
25
|
-
_, val = headers.find { |key, _| key.casecmp(titlecase_key) == 0 }
|
26
|
-
val
|
27
|
-
end
|
24
|
+
content_type = headers['Content-Type']
|
25
|
+
|
28
26
|
if !path.include?('..') and match = /text\/((?:x|ht)ml|css)/o.match(content_type)
|
29
27
|
type = match[1]
|
30
28
|
path = "#{path}.#{type}" unless /\.#{type}\z/.match(path)
|
@@ -54,16 +52,19 @@ class Rack::ResponseCache
|
|
54
52
|
# If the cache is a string, create any necessary middle directories, and cache the file in the appropriate
|
55
53
|
# subdirectory of cache. Otherwise, cache the body of the response as the value with the path as the key.
|
56
54
|
def call(env)
|
57
|
-
|
58
|
-
|
55
|
+
status, headers, body = @app.call(env)
|
56
|
+
headers = Rack::Utils::HeaderHash.new(headers)
|
57
|
+
|
58
|
+
if env['REQUEST_METHOD'] == 'GET' and env['QUERY_STRING'] == '' and status == 200 and path = @path_proc.call(env, [status, headers, body])
|
59
59
|
if @cache.is_a?(String)
|
60
60
|
path = File.join(@cache, path) if @cache
|
61
61
|
FileUtils.mkdir_p(File.dirname(path))
|
62
|
-
File.open(path, 'wb'){|f|
|
62
|
+
File.open(path, 'wb'){|f| body.each{|c| f.write(c)}}
|
63
63
|
else
|
64
|
-
@cache[path] =
|
64
|
+
@cache[path] = body
|
65
65
|
end
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
|
+
[status, headers, body]
|
68
69
|
end
|
69
70
|
end
|
data/lib/rack/contrib/runtime.rb
CHANGED
@@ -1,31 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
|
-
|
3
|
-
|
4
|
-
# time of the request, in seconds
|
5
|
-
#
|
6
|
-
# You can put it right before the application to see the processing
|
7
|
-
# time, or before all the other middlewares to include time for them,
|
8
|
-
# too.
|
9
|
-
class Runtime
|
10
|
-
def initialize(app, name = nil)
|
11
|
-
@app = app
|
12
|
-
@header_name = "X-Runtime"
|
13
|
-
@header_name << "-#{name}" if name
|
14
|
-
end
|
15
|
-
|
16
|
-
def call(env)
|
17
|
-
start_time = Time.now
|
18
|
-
status, headers, body = @app.call(env)
|
19
|
-
request_time = Time.now - start_time
|
20
|
-
|
21
|
-
if !headers.has_key?(@header_name)
|
22
|
-
headers[@header_name] = "%0.6f" % request_time
|
23
|
-
end
|
24
|
-
|
25
|
-
[status, headers, body]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
|
3
|
+
require 'rack'
|
4
|
+
require 'rack/runtime'
|
data/lib/rack/contrib/signals.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
# Installs signal handlers that are safely processed after a request
|
3
5
|
#
|
@@ -24,6 +26,10 @@ module Rack
|
|
24
26
|
@body.each(&block)
|
25
27
|
@callback.call
|
26
28
|
end
|
29
|
+
|
30
|
+
def close
|
31
|
+
@body.close if @body.respond_to?(:close)
|
32
|
+
end
|
27
33
|
end
|
28
34
|
|
29
35
|
def initialize(app, &block)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'time'
|
2
4
|
|
3
5
|
module Rack
|
@@ -57,10 +59,12 @@ module Rack
|
|
57
59
|
@no_cache = {}
|
58
60
|
@urls.collect! do |url|
|
59
61
|
if url =~ /\*$/
|
60
|
-
url.sub
|
61
|
-
@no_cache[
|
62
|
+
url_prefix = url.sub(/\*$/, '')
|
63
|
+
@no_cache[url_prefix] = 1
|
64
|
+
url_prefix
|
65
|
+
else
|
66
|
+
url
|
62
67
|
end
|
63
|
-
url
|
64
68
|
end
|
65
69
|
root = options[:root] || Dir.pwd
|
66
70
|
@file_server = Rack::File.new(root)
|
@@ -81,7 +85,10 @@ module Rack
|
|
81
85
|
if @versioning_enabled
|
82
86
|
path.sub!(@version_regex, '\1')
|
83
87
|
end
|
88
|
+
|
84
89
|
status, headers, body = @file_server.call(env)
|
90
|
+
headers = Utils::HeaderHash.new(headers)
|
91
|
+
|
85
92
|
if @no_cache[url].nil?
|
86
93
|
headers['Cache-Control'] ="max-age=#{@duration_in_seconds}, public"
|
87
94
|
headers['Expires'] = duration_in_words
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-contrib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- rack-devel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|