faraday-http-cache 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -6
- data/lib/faraday-http-cache.rb +1 -1
- data/lib/faraday/http_cache.rb +7 -5
- data/lib/faraday/http_cache/cache_control.rb +2 -2
- data/lib/faraday/http_cache/request.rb +1 -2
- data/lib/faraday/http_cache/response.rb +1 -1
- data/spec/http_cache_spec.rb +17 -16
- data/spec/instrumentation_spec.rb +2 -2
- data/spec/request_spec.rb +0 -1
- data/spec/storage_spec.rb +5 -4
- data/spec/support/test_app.rb +1 -2
- data/spec/support/test_server.rb +5 -4
- data/spec/validation_spec.rb +4 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed664b05e7052722cfb0f9d0ba7336b6de8ea5b7
|
4
|
+
data.tar.gz: fece9174d01e39d9e63c92f0ae6ba28c676a3504
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: db36959ac2578e4f9559aece670ab1a8fcc58d33d87bceb24dd9ea6871260d0af88ad570907198e01a4d733e146e884d5fca62ffec2223b61d1b2bd6aba8d399
|
7
|
+
data.tar.gz: de95b997afd0c83d6e1b344e5e00f9bd0e2a6ce57c7d81bbde0bc5a8ac6f4efbe804087c2565c89ec879145c5e06e00ced67d491e77cfe2515c9900817063676
|
data/README.md
CHANGED
@@ -84,7 +84,7 @@ client.get('http://site/api/users')
|
|
84
84
|
In addition to logging you can instrument the middleware by passing in an `:instrumenter` option
|
85
85
|
such as ActiveSupport::Notifications (compatible objects are also allowed).
|
86
86
|
|
87
|
-
The event `
|
87
|
+
The event `http_cache.faraday` will be published every time the middleware
|
88
88
|
processes a request. In the event payload, `:env` contains the response Faraday env and
|
89
89
|
`:cache_status` contains a Symbol indicating the status of the cache processing for that request:
|
90
90
|
|
@@ -102,18 +102,18 @@ client = Faraday.new do |builder|
|
|
102
102
|
end
|
103
103
|
|
104
104
|
# Subscribes to all events from Faraday::HttpCache.
|
105
|
-
ActiveSupport::Notifications.subscribe "
|
105
|
+
ActiveSupport::Notifications.subscribe "http_cache.faraday" do |*args|
|
106
106
|
event = ActiveSupport::Notifications::Event.new(*args)
|
107
|
-
cache_status = event.payload
|
107
|
+
cache_status = event.payload[:cache_status]
|
108
108
|
statsd = Statsd.new
|
109
109
|
|
110
110
|
case cache_status
|
111
111
|
when :fresh, :valid
|
112
|
-
statsd.increment(
|
112
|
+
statsd.increment('api-calls.cache_hits')
|
113
113
|
when :invalid, :miss
|
114
|
-
statsd.increment(
|
114
|
+
statsd.increment('api-calls.cache_misses')
|
115
115
|
when :unacceptable
|
116
|
-
statsd.increment(
|
116
|
+
statsd.increment('api-calls.cache_bypass')
|
117
117
|
end
|
118
118
|
end
|
119
119
|
```
|
data/lib/faraday-http-cache.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require 'faraday/http_cache'
|
1
|
+
require 'faraday/http_cache' # rubocop:disable Style/FileName
|
data/lib/faraday/http_cache.rb
CHANGED
@@ -44,14 +44,14 @@ module Faraday
|
|
44
44
|
# end
|
45
45
|
class HttpCache < Faraday::Middleware
|
46
46
|
# Internal: valid options for the 'initialize' configuration Hash.
|
47
|
-
VALID_OPTIONS = [:store, :serializer, :logger, :shared_cache, :instrumenter]
|
47
|
+
VALID_OPTIONS = [:store, :serializer, :logger, :shared_cache, :instrumenter, :instrument_name]
|
48
48
|
|
49
49
|
UNSAFE_METHODS = [:post, :put, :delete, :patch]
|
50
50
|
|
51
51
|
ERROR_STATUSES = 400..499
|
52
52
|
|
53
53
|
# The name of the instrumentation event.
|
54
|
-
EVENT_NAME = '
|
54
|
+
EVENT_NAME = 'http_cache.faraday'
|
55
55
|
|
56
56
|
CACHE_STATUSES = [
|
57
57
|
# The request was not cacheable:
|
@@ -328,8 +328,7 @@ module Faraday
|
|
328
328
|
|
329
329
|
method = @request.method.to_s.upcase
|
330
330
|
path = @request.url.request_uri
|
331
|
-
|
332
|
-
@logger.debug(line)
|
331
|
+
@logger.debug { "HTTP Cache: [#{method} #{path}] #{@trace.join(', ')}" }
|
333
332
|
end
|
334
333
|
|
335
334
|
# Internal: instruments the request processing.
|
@@ -344,13 +343,16 @@ module Faraday
|
|
344
343
|
}
|
345
344
|
|
346
345
|
@instrumenter.instrument(@instrument_name, payload)
|
346
|
+
# DEPRECATED: Event name from the 1.1.1 release that isn't compatible
|
347
|
+
# with the `ActiveSupport::LogSubscriber` API.
|
348
|
+
@instrumenter.instrument('process_request.http_cache.faraday', payload)
|
347
349
|
end
|
348
350
|
|
349
351
|
# Internal: Extracts the cache status from a trace.
|
350
352
|
#
|
351
353
|
# Returns the Symbol status or nil if none was available.
|
352
354
|
def extract_status(trace)
|
353
|
-
CACHE_STATUSES.
|
355
|
+
CACHE_STATUSES.find { |status| trace.include?(status) }
|
354
356
|
end
|
355
357
|
|
356
358
|
# Internal: Checks if the given 'options' Hash contains only
|
@@ -5,7 +5,6 @@ module Faraday
|
|
5
5
|
# It breaks the several directives into keys/values and stores them into
|
6
6
|
# a Hash.
|
7
7
|
class CacheControl
|
8
|
-
|
9
8
|
# Internal: Initialize a new CacheControl.
|
10
9
|
def initialize(header)
|
11
10
|
@directives = parse(header.to_s)
|
@@ -74,7 +73,8 @@ module Faraday
|
|
74
73
|
#
|
75
74
|
# Returns the Cache Control string.
|
76
75
|
def to_s
|
77
|
-
booleans
|
76
|
+
booleans = []
|
77
|
+
values = []
|
78
78
|
|
79
79
|
@directives.each do |key, value|
|
80
80
|
if value == true
|
@@ -2,7 +2,6 @@ module Faraday
|
|
2
2
|
class HttpCache < Faraday::Middleware
|
3
3
|
# Internal: A class to represent a request
|
4
4
|
class Request
|
5
|
-
|
6
5
|
class << self
|
7
6
|
def from_env(env)
|
8
7
|
hash = env.to_hash
|
@@ -13,7 +12,7 @@ module Faraday
|
|
13
12
|
attr_reader :method, :url, :headers
|
14
13
|
|
15
14
|
def initialize(options)
|
16
|
-
@method, @url, @headers = options
|
15
|
+
@method, @url, @headers = options.values_at(:method, :url, :headers)
|
17
16
|
end
|
18
17
|
|
19
18
|
# Internal: Validates if the current request method is valid for caching.
|
@@ -175,7 +175,7 @@ module Faraday
|
|
175
175
|
#
|
176
176
|
# Returns the Time object, or nil if the header isn't present or isn't RFC 2616 compliant.
|
177
177
|
def expires
|
178
|
-
@expires ||= headers['Expires'] && Time.httpdate(headers['Expires']) rescue nil
|
178
|
+
@expires ||= headers['Expires'] && Time.httpdate(headers['Expires']) rescue nil # rubocop:disable Style/RescueModifier
|
179
179
|
end
|
180
180
|
|
181
181
|
# Internal: Gets the 'CacheControl' object.
|
data/spec/http_cache_spec.rb
CHANGED
@@ -9,6 +9,7 @@ describe Faraday::HttpCache do
|
|
9
9
|
stack.use Faraday::HttpCache, options
|
10
10
|
adapter = ENV['FARADAY_ADAPTER']
|
11
11
|
stack.headers['X-Faraday-Adapter'] = adapter
|
12
|
+
stack.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
12
13
|
stack.adapter adapter.to_sym
|
13
14
|
end
|
14
15
|
end
|
@@ -23,7 +24,7 @@ describe Faraday::HttpCache do
|
|
23
24
|
end
|
24
25
|
|
25
26
|
it 'logs that a POST request is unacceptable' do
|
26
|
-
expect(logger).to receive(:debug).
|
27
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [POST /post] unacceptable, delete') }
|
27
28
|
client.post('post').body
|
28
29
|
end
|
29
30
|
|
@@ -45,7 +46,7 @@ describe Faraday::HttpCache do
|
|
45
46
|
end
|
46
47
|
|
47
48
|
it 'logs that a POST request was deleted from the cache' do
|
48
|
-
expect(logger).to receive(:debug).
|
49
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [POST /counter] unacceptable, delete') }
|
49
50
|
client.post('counter')
|
50
51
|
end
|
51
52
|
|
@@ -62,7 +63,7 @@ describe Faraday::HttpCache do
|
|
62
63
|
end
|
63
64
|
|
64
65
|
it 'logs that a PUT request was deleted from the cache' do
|
65
|
-
expect(logger).to receive(:debug).
|
66
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [PUT /counter] unacceptable, delete') }
|
66
67
|
client.put('counter')
|
67
68
|
end
|
68
69
|
|
@@ -73,7 +74,7 @@ describe Faraday::HttpCache do
|
|
73
74
|
end
|
74
75
|
|
75
76
|
it 'logs that a DELETE request was deleted from the cache' do
|
76
|
-
expect(logger).to receive(:debug).
|
77
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [DELETE /counter] unacceptable, delete') }
|
77
78
|
client.delete('counter')
|
78
79
|
end
|
79
80
|
|
@@ -84,12 +85,12 @@ describe Faraday::HttpCache do
|
|
84
85
|
end
|
85
86
|
|
86
87
|
it 'logs that a PATCH request was deleted from the cache' do
|
87
|
-
expect(logger).to receive(:debug).
|
88
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [PATCH /counter] unacceptable, delete') }
|
88
89
|
client.patch('counter')
|
89
90
|
end
|
90
91
|
|
91
92
|
it 'logs that a response with a bad status code is invalid' do
|
92
|
-
expect(logger).to receive(:debug).
|
93
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [GET /broken] miss, invalid') }
|
93
94
|
client.get('broken')
|
94
95
|
end
|
95
96
|
|
@@ -115,7 +116,7 @@ describe Faraday::HttpCache do
|
|
115
116
|
end
|
116
117
|
|
117
118
|
it 'logs that a private response is invalid' do
|
118
|
-
expect(logger).to receive(:debug).
|
119
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [GET /private] miss, invalid') }
|
119
120
|
client.get('private')
|
120
121
|
end
|
121
122
|
end
|
@@ -129,7 +130,7 @@ describe Faraday::HttpCache do
|
|
129
130
|
end
|
130
131
|
|
131
132
|
it 'logs that a private response is stored' do
|
132
|
-
expect(logger).to receive(:debug).
|
133
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [GET /private] miss, store') }
|
133
134
|
client.get('private')
|
134
135
|
end
|
135
136
|
end
|
@@ -140,7 +141,7 @@ describe Faraday::HttpCache do
|
|
140
141
|
end
|
141
142
|
|
142
143
|
it 'logs that a response with a no-store directive is invalid' do
|
143
|
-
expect(logger).to receive(:debug).
|
144
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [GET /dontstore] miss, invalid') }
|
144
145
|
client.get('dontstore')
|
145
146
|
end
|
146
147
|
|
@@ -168,7 +169,7 @@ describe Faraday::HttpCache do
|
|
168
169
|
end
|
169
170
|
|
170
171
|
it 'logs that a request with the "Expires" is fresh and stored' do
|
171
|
-
expect(logger).to receive(:debug).
|
172
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [GET /expires] miss, store') }
|
172
173
|
client.get('expires')
|
173
174
|
end
|
174
175
|
|
@@ -190,20 +191,20 @@ describe Faraday::HttpCache do
|
|
190
191
|
end
|
191
192
|
|
192
193
|
it 'logs that a GET response is stored' do
|
193
|
-
expect(logger).to receive(:debug).
|
194
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [GET /get] miss, store') }
|
194
195
|
client.get('get')
|
195
196
|
end
|
196
197
|
|
197
198
|
it 'differs requests with different query strings in the log' do
|
198
|
-
expect(logger).to receive(:debug).
|
199
|
-
expect(logger).to receive(:debug).
|
199
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [GET /get] miss, store') }
|
200
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [GET /get?q=what] miss, store') }
|
200
201
|
client.get('get')
|
201
202
|
client.get('get', q: 'what')
|
202
203
|
end
|
203
204
|
|
204
205
|
it 'logs that a stored GET response is fresh' do
|
205
206
|
client.get('get')
|
206
|
-
expect(logger).to receive(:debug).
|
207
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [GET /get] fresh') }
|
207
208
|
client.get('get')
|
208
209
|
end
|
209
210
|
|
@@ -214,7 +215,7 @@ describe Faraday::HttpCache do
|
|
214
215
|
|
215
216
|
it 'logs that the request with "Last-Modified" was revalidated' do
|
216
217
|
client.get('timestamped')
|
217
|
-
expect(logger).to receive(:debug).
|
218
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [GET /timestamped] valid, store') }
|
218
219
|
expect(client.get('timestamped').body).to eq('1')
|
219
220
|
end
|
220
221
|
|
@@ -225,7 +226,7 @@ describe Faraday::HttpCache do
|
|
225
226
|
|
226
227
|
it 'logs that the request with "ETag" was revalidated' do
|
227
228
|
client.get('etag')
|
228
|
-
expect(logger).to receive(:debug).
|
229
|
+
expect(logger).to receive(:debug) { |&block| expect(block.call).to eq('HTTP Cache: [GET /etag] valid, store') }
|
229
230
|
expect(client.get('etag').body).to eq('1')
|
230
231
|
end
|
231
232
|
|
@@ -11,10 +11,10 @@ describe 'Instrumentation' do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
let(:events) { [] }
|
14
|
-
let(:subscriber) { lambda {|*args| events << ActiveSupport::Notifications::Event.new(*args) } }
|
14
|
+
let(:subscriber) { lambda { |*args| events << ActiveSupport::Notifications::Event.new(*args) } }
|
15
15
|
|
16
16
|
around do |example|
|
17
|
-
ActiveSupport::Notifications.subscribed(subscriber, '
|
17
|
+
ActiveSupport::Notifications.subscribed(subscriber, 'http_cache.faraday') do
|
18
18
|
example.run
|
19
19
|
end
|
20
20
|
end
|
data/spec/request_spec.rb
CHANGED
data/spec/storage_spec.rb
CHANGED
@@ -52,7 +52,9 @@ describe Faraday::HttpCache::Storage do
|
|
52
52
|
logger = double(:logger, warn: nil)
|
53
53
|
storage = Faraday::HttpCache::Storage.new(logger: logger)
|
54
54
|
|
55
|
-
expect {
|
55
|
+
expect {
|
56
|
+
storage.write(request, response)
|
57
|
+
}.to raise_error(Encoding::UndefinedConversionError)
|
56
58
|
expect(logger).to have_received(:warn).with(
|
57
59
|
'Response could not be serialized: "\xE2" from ASCII-8BIT to UTF-8. Try using Marshal to serialize.'
|
58
60
|
)
|
@@ -125,8 +127,8 @@ describe Faraday::HttpCache::Storage do
|
|
125
127
|
|
126
128
|
it 'is fresh until cached and that 1 second elapses then the response is no longer fresh' do
|
127
129
|
headers = {
|
128
|
-
|
129
|
-
|
130
|
+
'Date' => (Time.now - 39).httpdate,
|
131
|
+
'Expires' => (Time.now + 40).httpdate
|
130
132
|
}
|
131
133
|
|
132
134
|
response = Faraday::HttpCache::Response.new(response_headers: headers)
|
@@ -138,5 +140,4 @@ describe Faraday::HttpCache::Storage do
|
|
138
140
|
expect(cached_response).not_to be_fresh
|
139
141
|
end
|
140
142
|
end
|
141
|
-
|
142
143
|
end
|
data/spec/support/test_app.rb
CHANGED
@@ -2,7 +2,6 @@ require 'sinatra/base'
|
|
2
2
|
require 'json'
|
3
3
|
|
4
4
|
class TestApp < Sinatra::Base
|
5
|
-
|
6
5
|
set :environment, :test
|
7
6
|
set :server, 'webrick'
|
8
7
|
disable :protection
|
@@ -104,7 +103,7 @@ class TestApp < Sinatra::Base
|
|
104
103
|
tag = settings.counter > 2 ? '1' : '2'
|
105
104
|
|
106
105
|
if env['HTTP_IF_NONE_MATCH'] == tag
|
107
|
-
[304, { 'ETag' => tag, 'Cache-Control' => 'max-age=200', 'Date' => Time.now.httpdate, 'Expires' => (Time.now + 200).httpdate, 'Vary' => '*' },
|
106
|
+
[304, { 'ETag' => tag, 'Cache-Control' => 'max-age=200', 'Date' => Time.now.httpdate, 'Expires' => (Time.now + 200).httpdate, 'Vary' => '*' }, '']
|
108
107
|
else
|
109
108
|
[200, { 'ETag' => tag, 'Cache-Control' => 'max-age=0', 'Date' => settings.yesterday, 'Expires' => Time.now.httpdate, 'Vary' => 'Accept' }, increment_counter]
|
110
109
|
end
|
data/spec/support/test_server.rb
CHANGED
@@ -27,7 +27,7 @@ class TestServer
|
|
27
27
|
log.sync = true
|
28
28
|
webrick_opts = {
|
29
29
|
Port: @port,
|
30
|
-
Logger: WEBrick::Log
|
30
|
+
Logger: WEBrick::Log.new(log),
|
31
31
|
AccessLog: [[log, '[%{X-Faraday-Adapter}i] %m %U -> %s %b']]
|
32
32
|
}
|
33
33
|
Rack::Handler::WEBrick.run(TestApp, webrick_opts)
|
@@ -38,7 +38,7 @@ class TestServer
|
|
38
38
|
conn = Net::HTTP.new @host, @port
|
39
39
|
conn.open_timeout = conn.read_timeout = 0.1
|
40
40
|
|
41
|
-
responsive =
|
41
|
+
responsive = ->(path) { # rubocop:disable Style/BlockDelimiters
|
42
42
|
begin
|
43
43
|
res = conn.start { conn.get(path) }
|
44
44
|
res.is_a?(Net::HTTPSuccess)
|
@@ -48,11 +48,12 @@ class TestServer
|
|
48
48
|
}
|
49
49
|
|
50
50
|
server_pings = 0
|
51
|
-
|
51
|
+
loop do
|
52
|
+
break if responsive.call('/ping')
|
52
53
|
server_pings += 1
|
53
54
|
sleep 0.05
|
54
55
|
abort 'test server did not managed to start' if server_pings >= 50
|
55
|
-
end
|
56
|
+
end
|
56
57
|
end
|
57
58
|
|
58
59
|
def find_port
|
data/spec/validation_spec.rb
CHANGED
@@ -11,11 +11,11 @@ describe Faraday::HttpCache do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'maintains the "Content-Type" header for cached responses' do
|
14
|
-
backend.get('/test') { [200, { 'ETag' => '123ABC', 'Content-Type' => 'x' },
|
14
|
+
backend.get('/test') { [200, { 'ETag' => '123ABC', 'Content-Type' => 'x' }, ''] }
|
15
15
|
first_content_type = client.get('/test').headers['Content-Type']
|
16
16
|
|
17
17
|
# The Content-Type header of the validation response should be ignored.
|
18
|
-
backend.get('/test') { [304, { 'Content-Type' => 'y' },
|
18
|
+
backend.get('/test') { [304, { 'Content-Type' => 'y' }, ''] }
|
19
19
|
second_content_type = client.get('/test').headers['Content-Type']
|
20
20
|
|
21
21
|
expect(first_content_type).to eq('x')
|
@@ -23,11 +23,11 @@ describe Faraday::HttpCache do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'maintains the "Content-Length" header for cached responses' do
|
26
|
-
backend.get('/test') { [200, { 'ETag' => '123ABC', 'Content-Length' => 1 },
|
26
|
+
backend.get('/test') { [200, { 'ETag' => '123ABC', 'Content-Length' => 1 }, ''] }
|
27
27
|
first_content_length = client.get('/test').headers['Content-Length']
|
28
28
|
|
29
29
|
# The Content-Length header of the validation response should be ignored.
|
30
|
-
backend.get('/test') { [304, { 'Content-Length' => 2 },
|
30
|
+
backend.get('/test') { [304, { 'Content-Length' => 2 }, ''] }
|
31
31
|
second_content_length = client.get('/test').headers['Content-Length']
|
32
32
|
|
33
33
|
expect(first_content_length).to eq(1)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: faraday-http-cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lucas Mazza
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|