async-http-cache 0.1.5 → 0.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/.github/workflows/development.yml +0 -1
- data/Gemfile +4 -0
- data/async-http-cache.gemspec +2 -3
- data/lib/async/http/cache/body.rb +23 -12
- data/lib/async/http/cache/general.rb +12 -3
- data/lib/async/http/cache/response.rb +11 -1
- data/lib/async/http/cache/store/memory.rb +9 -0
- data/lib/async/http/cache/version.rb +1 -1
- metadata +5 -20
- data/Rakefile +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0819bedaf18e394d19ae5ac3e53fa5eb418f2166252b4a578c6087a3a5b4704
|
4
|
+
data.tar.gz: b9d593ee6e8ecef570603c486b04fd52aaaec9c227abe73118cfa0463a54c58d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd1bf4dc1595e38f251094969895398b4b335380bb654cd7449197932f657f0aaa3d0f849d8f58846b1ee23ff317f5a6c14359c458e5c25c34630f521af4a620
|
7
|
+
data.tar.gz: dbdc2267bb3a61ce7e376bb4f76c37c81913b41a48b98eb220856b1b2352aac3e00a63191125404318c0880a8e83d7ef10a49eb8bdfc85ae87f2c2e047f864ed
|
data/Gemfile
CHANGED
data/async-http-cache.gemspec
CHANGED
@@ -21,13 +21,12 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.add_dependency "async-http"
|
25
|
-
spec.add_dependency "protocol-http", "~> 0.14"
|
24
|
+
spec.add_dependency "async-http", "~> 0.51"
|
26
25
|
|
27
26
|
spec.add_development_dependency "async-rspec", "~> 1.10"
|
28
27
|
|
29
28
|
spec.add_development_dependency "covered"
|
30
29
|
spec.add_development_dependency "bundler"
|
31
30
|
spec.add_development_dependency "rspec"
|
32
|
-
spec.add_development_dependency "
|
31
|
+
spec.add_development_dependency "bake-bundler"
|
33
32
|
end
|
@@ -22,37 +22,48 @@
|
|
22
22
|
|
23
23
|
require 'protocol/http/body/rewindable'
|
24
24
|
require 'protocol/http/body/streamable'
|
25
|
+
require 'protocol/http/body/digestable'
|
25
26
|
|
26
27
|
module Async
|
27
28
|
module HTTP
|
28
29
|
module Cache
|
29
30
|
module Body
|
30
|
-
|
31
|
-
|
31
|
+
TRAILERS = 'trailers'
|
32
|
+
ETAG = 'etag'
|
33
|
+
|
34
|
+
def self.wrap(response, &block)
|
35
|
+
if body = response.body
|
32
36
|
if body.empty?
|
33
37
|
# A body that is empty? at the outset, is immutable. This generally only applies to HEAD requests.
|
34
|
-
yield
|
38
|
+
yield response, body
|
35
39
|
else
|
36
|
-
#
|
37
|
-
rewindable = ::Protocol::HTTP::Body::Rewindable.
|
40
|
+
# Insert a rewindable body so that we can cache the response body:
|
41
|
+
rewindable = ::Protocol::HTTP::Body::Rewindable.wrap(response)
|
38
42
|
|
39
|
-
|
40
|
-
|
43
|
+
unless response.headers.include?(ETAG)
|
44
|
+
# Compute a digest and add it to the response headers:
|
45
|
+
::Protocol::HTTP::Body::Digestable.wrap(response) do |wrapper|
|
46
|
+
response.headers.add(ETAG, wrapper.etag)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Ensure the etag is listed as a trailer:
|
50
|
+
response.headers.add(TRAILERS, ETAG)
|
51
|
+
end
|
41
52
|
|
42
|
-
# Wrap the
|
43
|
-
::Protocol::HTTP::Body::Streamable.wrap(
|
53
|
+
# Wrap the response with the callback:
|
54
|
+
::Protocol::HTTP::Body::Streamable.wrap(response) do |error|
|
44
55
|
if error
|
45
56
|
Async.logger.error(self) {error}
|
46
57
|
else
|
47
|
-
yield
|
58
|
+
yield response, rewindable.buffered
|
48
59
|
end
|
49
60
|
end
|
50
61
|
end
|
51
62
|
else
|
52
|
-
yield
|
63
|
+
yield response, nil
|
53
64
|
end
|
54
65
|
|
55
|
-
return
|
66
|
+
return response
|
56
67
|
end
|
57
68
|
end
|
58
69
|
end
|
@@ -31,6 +31,7 @@ module Async
|
|
31
31
|
module Cache
|
32
32
|
class General < ::Protocol::HTTP::Middleware
|
33
33
|
CACHE_CONTROL = 'cache-control'
|
34
|
+
|
34
35
|
CONTENT_TYPE = 'content-type'
|
35
36
|
AUTHORIZATION = 'authorization'
|
36
37
|
COOKIE = 'cookie'
|
@@ -91,9 +92,17 @@ module Async
|
|
91
92
|
return response
|
92
93
|
end
|
93
94
|
|
94
|
-
|
95
|
+
if request.head? and body = response.body
|
96
|
+
unless body.empty?
|
97
|
+
Async.logger.warn(self) {"HEAD request resulted in non-empty body!"}
|
98
|
+
|
99
|
+
return response
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
return Body.wrap(response) do |response, body|
|
95
104
|
Async.logger.debug(self) {"Updating cache for #{key}..."}
|
96
|
-
@store.insert(key, request, Response.new(
|
105
|
+
@store.insert(key, request, Response.new(response, body))
|
97
106
|
end
|
98
107
|
end
|
99
108
|
|
@@ -107,7 +116,7 @@ module Async
|
|
107
116
|
Async.logger.debug(self) {"Cache hit for #{key}..."}
|
108
117
|
@count += 1
|
109
118
|
|
110
|
-
#
|
119
|
+
# Return the cached response:
|
111
120
|
return response
|
112
121
|
end
|
113
122
|
end
|
@@ -29,6 +29,9 @@ module Async
|
|
29
29
|
class Response < ::Protocol::HTTP::Response
|
30
30
|
CACHE_CONTROL = 'cache-control'
|
31
31
|
SET_COOKIE = 'set-cookie'
|
32
|
+
ETAG = 'etag'
|
33
|
+
|
34
|
+
X_CACHE = 'x-cache'
|
32
35
|
|
33
36
|
def initialize(response, body)
|
34
37
|
@generated_at = Async::Clock.now
|
@@ -36,16 +39,23 @@ module Async
|
|
36
39
|
super(
|
37
40
|
response.version,
|
38
41
|
response.status,
|
39
|
-
response.headers.
|
42
|
+
response.headers.flatten,
|
40
43
|
body,
|
41
44
|
response.protocol
|
42
45
|
)
|
43
46
|
|
44
47
|
@max_age = @headers[CACHE_CONTROL]&.max_age
|
48
|
+
@etag = nil
|
49
|
+
|
50
|
+
@headers.set(X_CACHE, 'hit')
|
45
51
|
end
|
46
52
|
|
47
53
|
attr :generated_at
|
48
54
|
|
55
|
+
def etag
|
56
|
+
@etag ||= @headers[ETAG]
|
57
|
+
end
|
58
|
+
|
49
59
|
def cachable?
|
50
60
|
if cache_control = @headers[CACHE_CONTROL]
|
51
61
|
if cache_control.private? || !cache_control.public?
|
@@ -64,6 +64,9 @@ module Async
|
|
64
64
|
|
65
65
|
attr :index
|
66
66
|
|
67
|
+
IF_NONE_MATCH = 'if-none-match'
|
68
|
+
NOT_MODIFIED = ::Protocol::HTTP::Response[304]
|
69
|
+
|
67
70
|
def lookup(key, request)
|
68
71
|
if response = @index[key]
|
69
72
|
if response.expired?
|
@@ -74,6 +77,12 @@ module Async
|
|
74
77
|
return nil
|
75
78
|
end
|
76
79
|
|
80
|
+
if etags = request.headers[IF_NONE_MATCH]
|
81
|
+
if etags.include?(response.etag)
|
82
|
+
return NOT_MODIFIED
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
77
86
|
@hit += 1
|
78
87
|
|
79
88
|
return response.dup
|
metadata
CHANGED
@@ -1,43 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-http-cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async-http
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: protocol-http
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
30
16
|
requirements:
|
31
17
|
- - "~>"
|
32
18
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0.
|
19
|
+
version: '0.51'
|
34
20
|
type: :runtime
|
35
21
|
prerelease: false
|
36
22
|
version_requirements: !ruby/object:Gem::Requirement
|
37
23
|
requirements:
|
38
24
|
- - "~>"
|
39
25
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0.
|
26
|
+
version: '0.51'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: async-rspec
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,7 +81,7 @@ dependencies:
|
|
95
81
|
- !ruby/object:Gem::Version
|
96
82
|
version: '0'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
84
|
+
name: bake-bundler
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
100
86
|
requirements:
|
101
87
|
- - ">="
|
@@ -120,7 +106,6 @@ files:
|
|
120
106
|
- ".rspec"
|
121
107
|
- Gemfile
|
122
108
|
- README.md
|
123
|
-
- Rakefile
|
124
109
|
- async-http-cache.gemspec
|
125
110
|
- lib/async/http/cache.rb
|
126
111
|
- lib/async/http/cache/body.rb
|