faraday-http-cache 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 75eed5459ea58ad83130acdab34d7acf40967eaa
4
- data.tar.gz: f5847df239db40584db36489818143e31d821222
3
+ metadata.gz: 80c7adcab041a8cfdcc1bfa6ac4a8ddd30661d9b
4
+ data.tar.gz: 688398ca6e4d77ac6769f66925c3108d5257ecdd
5
5
  SHA512:
6
- metadata.gz: f95af2c373abe3e7b3055c10fcd92b2208b01c3725da597e9b07d9e56c0ee477e7028852f883b6a7870f02ba8a65bcbd8c338e05a0b2535cd9093a63cfdc7682
7
- data.tar.gz: 8abb220a303052b25b83c4e16f40c77c4dbc6e4bd87ee33e18be28d108fde5ef2600e2baf5f5802a37e30650a89f1e8f35c7d63ffc67799ce49b5b0dc961b89f
6
+ metadata.gz: 789666e8549d1cb08978ae0870d97333e333541f0a774ec7bc10563dce42d3b4f9cf4ec425d16d03d13ae81d5420f5f5ecb8e71962525370b0aa9b39edae0f7b
7
+ data.tar.gz: 936fd149b8b358248bdb868fd347c7a53bc5115dae097a9ef6137680afc8d2584bf2f6066f328664132cc0191a9e199a813d31ee803ee1b5bdd8af02f9f8c514
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Faraday Http Cache
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/plataformatec/faraday-http-cache.png)](https://travis-ci.org/plataformatec/faraday-http-cache)
3
+ [![Build Status](https://secure.travis-ci.org/plataformatec/faraday-http-cache.png?branch=master)](https://travis-ci.org/plataformatec/faraday-http-cache)
4
4
 
5
5
  a [Faraday](https://github.com/lostisland/faraday) middleware that respects HTTP cache,
6
6
  by checking expiration and validation of the stored responses.
@@ -34,13 +34,13 @@ endpoints, and any extra configuration option will be used to setup the cache st
34
34
  ```ruby
35
35
  # Connect the middleware to a Memcache instance.
36
36
  client = Faraday.new do |builder|
37
- builder.use :http_cache, :mem_cache_store, "localhost:11211"
37
+ builder.use :http_cache, store: :mem_cache_store, store_options: ['localhost:11211']
38
38
  builder.adapter Faraday.default_adapter
39
39
  end
40
40
 
41
41
  # Or use the Rails.cache instance inside your Rails app.
42
42
  client = Faraday.new do |builder|
43
- builder.use :http_cache, Rails.cache
43
+ builder.use :http_cache, store: Rails.cache
44
44
  builder.adapter Faraday.default_adapter
45
45
  end
46
46
  ```
@@ -48,6 +48,16 @@ end
48
48
  The default store provided by ActiveSupport is the `MemoryStore` one, so it's important to
49
49
  configure a proper one for your production environment.
50
50
 
51
+ MultiJson is used for serialization by default. If you expect to be dealing
52
+ with images, you can use [Marshal][marshal] instead.
53
+
54
+ ```ruby
55
+ client = Faraday.new do |builder|
56
+ builder.use :http_cache, serializer: Marshal
57
+ builder.adapter Faraday.default_adapter
58
+ end
59
+ ```
60
+
51
61
  ### Logging
52
62
 
53
63
  You can provide a `:logger` option that will be receive debug informations based on the middleware
@@ -55,7 +65,7 @@ operations:
55
65
 
56
66
  ```ruby
57
67
  client = Faraday.new do |builder|
58
- builder.use :http_cache, :logger => Rails.logger
68
+ builder.use :http_cache, logger: Rails.logger
59
69
  builder.adapter Faraday.default_adapter
60
70
  end
61
71
 
@@ -66,11 +76,25 @@ client.get('http://site/api/users')
66
76
  ## See it live
67
77
 
68
78
  You can clone this repository, install it's dependencies with Bundler (run `bundle install`) and
69
- execute the `examples/twitter.rb` file to see a sample of the middleware usage - it's issuing
70
- requests to the Twitter API and caching them, so the rate limit isn't reduced on every request by
71
- the client object. After sleeping for 5 minutes the cache will expire and the client will hit the
72
- Twitter API again.
79
+ execute the files under the `examples` directory to see a sample of the middleware usage.
80
+
81
+ ## What get's cached?
82
+
83
+ The middleware will use the following headers to make caching decisions:
84
+ - Cache-Control
85
+ - Age
86
+ - Last-Modified
87
+ - ETag
88
+ - Expires
89
+
90
+ ### Cache-Control
91
+
92
+ The `max-age`, `must-revalidate`, `proxy-revalidate` and `s-maxage` directives are checked.
93
+
94
+ Note: private caches are ignored.
73
95
 
74
96
  ## License
75
97
 
76
98
  Copyright (c) 2012-2013 Plataformatec. See LICENSE file.
99
+
100
+ [marshal]: http://www.ruby-doc.org/core-2.0/Marshal.html
@@ -2,6 +2,7 @@ require 'faraday'
2
2
  require 'multi_json'
3
3
 
4
4
  require 'active_support/core_ext/hash/slice'
5
+ require 'active_support/deprecation'
5
6
 
6
7
  require 'faraday/http_cache/storage'
7
8
  require 'faraday/http_cache/response'
@@ -26,13 +27,18 @@ module Faraday
26
27
  #
27
28
  # # Attach a Logger to the middleware.
28
29
  # client = Faraday.new do |builder|
29
- # builder.use :http_cache, :logger => my_logger_instance
30
+ # builder.use :http_cache, logger: my_logger_instance
30
31
  # builder.adapter Faraday.default_adapter
31
32
  # end
32
33
  #
33
34
  # # Provide an existing CacheStore (for instance, from a Rails app)
34
35
  # client = Faraday.new do |builder|
35
- # builder.use :http_cache, Rails.cache
36
+ # builder.use :http_cache, store: Rails.cache
37
+ # end
38
+ #
39
+ # # Use Marshal for serialization
40
+ # client = Faraday.new do |builder|
41
+ # builder.use :http_cache, serializer: Marshal
36
42
  # end
37
43
  class HttpCache < Faraday::Middleware
38
44
 
@@ -44,23 +50,27 @@ module Faraday
44
50
  # Examples:
45
51
  #
46
52
  # # Initialize the middleware with a logger.
47
- # Faraday::HttpCache.new(app, :logger => my_logger)
53
+ # Faraday::HttpCache.new(app, logger: my_logger)
54
+ #
55
+ # # Initialize the middleware with a logger and Marshal as a serializer
56
+ # Faraday:HttpCache.new(app, logger: my_logger, serializer: Marshal)
48
57
  #
49
58
  # # Initialize the middleware with a FileStore at the 'tmp' dir.
50
- # Faraday::HttpCache.new(app, :file_store, 'tmp')
51
- def initialize(app, *arguments)
59
+ # Faraday::HttpCache.new(app, store: :file_store, store_options: ['tmp'])
60
+ #
61
+ # # Initialize the middleware with a MemoryStore and logger
62
+ # Faraday::HttpCache.new(app, store: :memory_store, logger: my_logger, store_options: [size: 1024])
63
+ def initialize(app, *args)
52
64
  super(app)
53
-
54
- if arguments.last.is_a? Hash
55
- options = arguments.pop
56
- @logger = options.delete(:logger)
65
+ @logger = nil
66
+ if args.first.is_a? Hash
67
+ options = args.first
68
+ @logger = options[:logger]
57
69
  else
58
- options = arguments
70
+ options = parse_deprecated_options(*args)
59
71
  end
60
72
 
61
- store = arguments.shift
62
-
63
- @storage = Storage.new(store, options)
73
+ @storage = Storage.new(options)
64
74
  end
65
75
 
66
76
  # Public: Process the request into a duplicate of this instance to
@@ -98,6 +108,61 @@ module Faraday
98
108
  end
99
109
 
100
110
  private
111
+ # Internal: Receive the deprecated arguments to initialize the old API
112
+ # and returns a Hash compatible with the new API
113
+ #
114
+ # Examples:
115
+ #
116
+ # parse_deprecated_options(Rails.cache)
117
+ # # => { store: Rails.cache }
118
+ #
119
+ # parse_deprecated_options(:mem_cache_store)
120
+ # # => { store: :mem_cache_store }
121
+ #
122
+ # parse_deprecated_options(:mem_cache_store, logger: Rails.logger)
123
+ # # => { store: :mem_cache_store, logger: Rails.logger }
124
+ #
125
+ # parse_deprecated_options(:mem_cache_store, 'localhost:11211')
126
+ # # => { store: :mem_cache_store, store_options: ['localhost:11211] }
127
+ #
128
+ # parse_deprecated_options(:mem_cache_store, logger: Rails.logger, serializer: Marshal)
129
+ # # => { store: :mem_cache_store, logger: Rails.logger, serializer: Marshal }
130
+ #
131
+ # parse_deprecated_options(serializer: Marshal)
132
+ # # => { serializer: Marshal }
133
+ #
134
+ # parse_deprecated_options(:file_store, { serializer: Marshal }, 'tmp')
135
+ # # => { store: :file_store, serializer: Marshal, store_options: ['tmp'] }
136
+ #
137
+ # parse_deprecated_options(:memory_store, size: 1024)
138
+ # # => { store: :memory_store, store_options: [size: 1024] }
139
+ #
140
+ # Returns a hash with the following keys:
141
+ # - store
142
+ # - serializer
143
+ # - logger
144
+ # - store_options
145
+ #
146
+ # In order to check what each key means, check `Storage#initialize` description.
147
+ def parse_deprecated_options(*args)
148
+ options = {}
149
+ if args.length > 0
150
+ ActiveSupport::Deprecation.warn('This api is deprecated, refer to the documentation for the new one', caller)
151
+ end
152
+
153
+ options[:store] = args.shift
154
+
155
+ if args.first.is_a? Hash
156
+ hash_params = args.first
157
+ options[:serializer] = hash_params.delete(:serializer)
158
+
159
+ @logger = hash_params.delete(:logger)
160
+ end
161
+
162
+ options[:store_options] = args
163
+ options
164
+ end
165
+
101
166
  # Internal: Validates if the current request method is valid for caching.
102
167
  #
103
168
  # Returns true if the method is ':get' or ':head'.
@@ -147,13 +212,13 @@ module Faraday
147
212
  headers['If-Modified-Since'] = entry.last_modified if entry.last_modified
148
213
  headers['If-None-Match'] = entry.etag if entry.etag
149
214
 
150
- @app.call(env).on_complete do |env|
151
- response = Response.new(env)
215
+ @app.call(env).on_complete do |requested_env|
216
+ response = Response.new(requested_env)
152
217
  if response.not_modified?
153
218
  trace :valid
154
219
  updated_payload = entry.payload
155
220
  updated_payload[:response_headers].update(response.payload[:response_headers])
156
- env.update(updated_payload)
221
+ requested_env.update(updated_payload)
157
222
  response = Response.new(updated_payload)
158
223
  end
159
224
  store(response)
@@ -193,8 +258,8 @@ module Faraday
193
258
  # Returns the fresh 'Faraday::Response' instance.
194
259
  def fetch(env)
195
260
  trace :miss
196
- @app.call(env).on_complete do |env|
197
- response = Response.new(create_response(env))
261
+ @app.call(env).on_complete do |fresh_env|
262
+ response = Response.new(create_response(fresh_env))
198
263
  store(response)
199
264
  end
200
265
  end
@@ -238,7 +303,7 @@ module Faraday
238
303
  end
239
304
 
240
305
  if Faraday.respond_to?(:register_middleware)
241
- Faraday.register_middleware :http_cache => Faraday::HttpCache
306
+ Faraday.register_middleware http_cache: Faraday::HttpCache
242
307
  elsif Faraday::Middleware.respond_to?(:register_middleware)
243
- Faraday::Middleware.register_middleware :http_cache => Faraday::HttpCache
308
+ Faraday::Middleware.register_middleware http_cache: Faraday::HttpCache
244
309
  end
@@ -177,10 +177,12 @@ module Faraday
177
177
  @payload[:response_headers]
178
178
  end
179
179
 
180
- # Internal: prepares the response headers ready to be cached
180
+ # Internal: Prepares the response headers ready to be cached.
181
181
  #
182
- # removes the age header if present to allow cached responses to continue aging while cached
183
- # also normalizes the max age headers if age header provided to ensure accuracy once age header removed
182
+ # It removes the age header if present to allow cached responses
183
+ # to continue aging while cached. It also normalizes the 'max-age'
184
+ # related headers if the 'Age' header is provided to ensure accuracy
185
+ # once the 'Age' header is removed.
184
186
  def prepare_to_cache
185
187
  if headers.key? 'Age'
186
188
  cache_control.normalize_max_ages(headers['Age'].to_i)
@@ -188,7 +190,6 @@ module Faraday
188
190
  headers['Cache-Control'] = cache_control.to_s
189
191
  end
190
192
  end
191
-
192
193
  end
193
194
  end
194
195
  end
@@ -12,15 +12,24 @@ module Faraday
12
12
  #
13
13
  # # Reuse some other instance of a ActiveSupport::CacheStore object.
14
14
  # Faraday::HttpCache::Storage.new(Rails.cache)
15
+ #
16
+ # # Creates a new Storage using Marshal for serialization.
17
+ # Faraday::HttpCache::Storage.new(:memory_store, serializer: Marshal)
15
18
  class Storage
16
19
  attr_reader :cache
17
20
 
18
21
  # Internal: Initialize a new Storage object with a cache backend.
19
22
  #
20
- # store - An ActiveSupport::CacheStore identifier (default: nil).
21
- # options - The Hash options for the CacheStore backend (default: {}).
22
- def initialize(store = nil, options = {})
23
- @cache = ActiveSupport::Cache.lookup_store(store, options)
23
+ # options - Storage options (default: {}).
24
+ # :store - An ActiveSupport::CacheStore identifier.
25
+ # :serializer - A serializer class for the body.
26
+ # Should respond to #dump and #load.
27
+ # :store_options - An array containg the options for
28
+ # the cache store
29
+ def initialize(options = {})
30
+ store = options[:store]
31
+ @serializer = options[:serializer] || MultiJson
32
+ @cache = ActiveSupport::Cache.lookup_store(store, options[:store_options])
24
33
  end
25
34
 
26
35
  # Internal: Writes a response with a key based on the given request.
@@ -32,7 +41,7 @@ module Faraday
32
41
  # response - The Faraday::HttpCache::Response instance to be stored.
33
42
  def write(request, response)
34
43
  key = cache_key_for(request)
35
- value = MultiJson.dump(response.serializable_hash)
44
+ value = @serializer.dump(response.serializable_hash)
36
45
  cache.write(key, value)
37
46
  end
38
47
 
@@ -48,7 +57,7 @@ module Faraday
48
57
  value = cache.read(key)
49
58
 
50
59
  if value
51
- payload = MultiJson.load(value).symbolize_keys
60
+ payload = @serializer.load(value).symbolize_keys
52
61
  klass.new(payload)
53
62
  end
54
63
  end
@@ -63,7 +72,7 @@ module Faraday
63
72
  # Returns the encoded String.
64
73
  def cache_key_for(request)
65
74
  array = request.stringify_keys.to_a.sort
66
- Digest::SHA1.hexdigest(MultiJson.dump(array))
75
+ Digest::SHA1.hexdigest(@serializer.dump(array))
67
76
  end
68
77
  end
69
78
  end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Faraday::HttpCache do
4
+ let(:client) do
5
+ Faraday.new(url: ENV['FARADAY_SERVER']) do |stack|
6
+ stack.use :http_cache, serializer: Marshal
7
+ adapter = ENV['FARADAY_ADAPTER']
8
+ stack.headers['X-Faraday-Adapter'] = adapter
9
+ stack.adapter adapter.to_sym
10
+ end
11
+ end
12
+ let(:data) { IO.binread File.expand_path('../support/empty.png', __FILE__) }
13
+
14
+ it 'works fine with binary data' do
15
+ expect(client.get('image').body).to eq data
16
+ expect(client.get('image').body).to eq data
17
+ end
18
+ end
@@ -2,106 +2,106 @@ require 'spec_helper'
2
2
 
3
3
  describe Faraday::HttpCache::CacheControl do
4
4
  it 'takes a String with multiple name=value pairs' do
5
- instance = Faraday::HttpCache::CacheControl.new('max-age=600, max-stale=300, min-fresh=570')
6
- instance.max_age.should == 600
5
+ cache_control = Faraday::HttpCache::CacheControl.new('max-age=600, max-stale=300, min-fresh=570')
6
+ expect(cache_control.max_age).to eq(600)
7
7
  end
8
8
 
9
9
  it 'takes a String with a single flag value' do
10
- instance = Faraday::HttpCache::CacheControl.new('no-cache')
11
- instance.should be_no_cache
10
+ cache_control = Faraday::HttpCache::CacheControl.new('no-cache')
11
+ expect(cache_control).to be_no_cache
12
12
  end
13
13
 
14
14
  it 'takes a String with a bunch of all kinds of stuff' do
15
- instance =
15
+ cache_control =
16
16
  Faraday::HttpCache::CacheControl.new('max-age=600,must-revalidate,min-fresh=3000,foo=bar,baz')
17
- instance.max_age.should == 600
18
- instance.should be_must_revalidate
17
+ expect(cache_control.max_age).to eq(600)
18
+ expect(cache_control).to be_must_revalidate
19
19
  end
20
20
 
21
21
  it 'strips leading and trailing spaces' do
22
- instance = Faraday::HttpCache::CacheControl.new(' public, max-age = 600 ')
23
- instance.should be_public
24
- instance.max_age.should == 600
22
+ cache_control = Faraday::HttpCache::CacheControl.new(' public, max-age = 600 ')
23
+ expect(cache_control).to be_public
24
+ expect(cache_control.max_age).to eq(600)
25
25
  end
26
26
 
27
27
  it 'ignores blank segments' do
28
- instance = Faraday::HttpCache::CacheControl.new('max-age=600,,s-maxage=300')
29
- instance.max_age.should == 600
30
- instance.shared_max_age.should == 300
28
+ cache_control = Faraday::HttpCache::CacheControl.new('max-age=600,,s-maxage=300')
29
+ expect(cache_control.max_age).to eq(600)
30
+ expect(cache_control.shared_max_age).to eq(300)
31
31
  end
32
32
 
33
33
  it 'sorts alphabetically with boolean directives before value directives' do
34
- instance = Faraday::HttpCache::CacheControl.new('foo=bar, z, x, y, bling=baz, zoom=zib, b, a')
35
- instance.to_s.should == 'a, b, x, y, z, bling=baz, foo=bar, zoom=zib'
34
+ cache_control = Faraday::HttpCache::CacheControl.new('foo=bar, z, x, y, bling=baz, zoom=zib, b, a')
35
+ expect(cache_control.to_s).to eq('a, b, x, y, z, bling=baz, foo=bar, zoom=zib')
36
36
  end
37
37
 
38
38
  it 'responds to #max_age with an integer when max-age directive present' do
39
- instance = Faraday::HttpCache::CacheControl.new('public, max-age=600')
40
- instance.max_age.should == 600
39
+ cache_control = Faraday::HttpCache::CacheControl.new('public, max-age=600')
40
+ expect(cache_control.max_age).to eq(600)
41
41
  end
42
42
 
43
43
  it 'responds to #max_age with nil when no max-age directive present' do
44
- instance = Faraday::HttpCache::CacheControl.new('public')
45
- instance.max_age.should be_nil
44
+ cache_control = Faraday::HttpCache::CacheControl.new('public')
45
+ expect(cache_control.max_age).to be_nil
46
46
  end
47
47
 
48
48
  it 'responds to #shared_max_age with an integer when s-maxage directive present' do
49
- instance = Faraday::HttpCache::CacheControl.new('public, s-maxage=600')
50
- instance.shared_max_age.should == 600
49
+ cache_control = Faraday::HttpCache::CacheControl.new('public, s-maxage=600')
50
+ expect(cache_control.shared_max_age).to eq(600)
51
51
  end
52
52
 
53
53
  it 'responds to #shared_max_age with nil when no s-maxage directive present' do
54
- instance = Faraday::HttpCache::CacheControl.new('public')
55
- instance.shared_max_age.should be_nil
54
+ cache_control = Faraday::HttpCache::CacheControl.new('public')
55
+ expect(cache_control.shared_max_age).to be_nil
56
56
  end
57
57
 
58
58
  it 'responds to #public? truthfully when public directive present' do
59
- instance = Faraday::HttpCache::CacheControl.new('public')
60
- instance.should be_public
59
+ cache_control = Faraday::HttpCache::CacheControl.new('public')
60
+ expect(cache_control).to be_public
61
61
  end
62
62
 
63
63
  it 'responds to #public? non-truthfully when no public directive present' do
64
- instance = Faraday::HttpCache::CacheControl.new('private')
65
- instance.should_not be_public
64
+ cache_control = Faraday::HttpCache::CacheControl.new('private')
65
+ expect(cache_control).not_to be_public
66
66
  end
67
67
 
68
68
  it 'responds to #private? truthfully when private directive present' do
69
- instance = Faraday::HttpCache::CacheControl.new('private')
70
- instance.should be_private
69
+ cache_control = Faraday::HttpCache::CacheControl.new('private')
70
+ expect(cache_control).to be_private
71
71
  end
72
72
 
73
73
  it 'responds to #private? non-truthfully when no private directive present' do
74
- instance = Faraday::HttpCache::CacheControl.new('public')
75
- instance.should_not be_private
74
+ cache_control = Faraday::HttpCache::CacheControl.new('public')
75
+ expect(cache_control).not_to be_private
76
76
  end
77
77
 
78
78
  it 'responds to #no_cache? truthfully when no-cache directive present' do
79
- instance = Faraday::HttpCache::CacheControl.new('no-cache')
80
- instance.should be_no_cache
79
+ cache_control = Faraday::HttpCache::CacheControl.new('no-cache')
80
+ expect(cache_control).to be_no_cache
81
81
  end
82
82
 
83
83
  it 'responds to #no_cache? non-truthfully when no no-cache directive present' do
84
- instance = Faraday::HttpCache::CacheControl.new('max-age=600')
85
- instance.should_not be_no_cache
84
+ cache_control = Faraday::HttpCache::CacheControl.new('max-age=600')
85
+ expect(cache_control).not_to be_no_cache
86
86
  end
87
87
 
88
88
  it 'responds to #must_revalidate? truthfully when must-revalidate directive present' do
89
- instance = Faraday::HttpCache::CacheControl.new('must-revalidate')
90
- instance.should be_must_revalidate
89
+ cache_control = Faraday::HttpCache::CacheControl.new('must-revalidate')
90
+ expect(cache_control).to be_must_revalidate
91
91
  end
92
92
 
93
93
  it 'responds to #must_revalidate? non-truthfully when no must-revalidate directive present' do
94
- instance = Faraday::HttpCache::CacheControl.new('max-age=600')
95
- instance.should_not be_no_cache
94
+ cache_control = Faraday::HttpCache::CacheControl.new('max-age=600')
95
+ expect(cache_control).not_to be_must_revalidate
96
96
  end
97
97
 
98
98
  it 'responds to #proxy_revalidate? truthfully when proxy-revalidate directive present' do
99
- instance = Faraday::HttpCache::CacheControl.new('proxy-revalidate')
100
- instance.should be_proxy_revalidate
99
+ cache_control = Faraday::HttpCache::CacheControl.new('proxy-revalidate')
100
+ expect(cache_control).to be_proxy_revalidate
101
101
  end
102
102
 
103
103
  it 'responds to #proxy_revalidate? non-truthfully when no proxy-revalidate directive present' do
104
- instance = Faraday::HttpCache::CacheControl.new('max-age=600')
105
- instance.should_not be_no_cache
104
+ cache_control = Faraday::HttpCache::CacheControl.new('max-age=600')
105
+ expect(cache_control).not_to be_no_cache
106
106
  end
107
107
  end