httparty-cache 0.0.1 → 0.0.2

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
  SHA256:
3
- metadata.gz: ff16750de74919a4428091908be24f05775deded7885af69960c38265ee1679b
4
- data.tar.gz: 12ccabffc3f4d24dfeef6327a3ac5649560b275051840826f31c3482e2075b2d
3
+ metadata.gz: 6b5ee7949c1ff90bad003ea68a65b11de85f2aba908c3aa3b733e53976d15b33
4
+ data.tar.gz: d7f636874b72c75534ec6e060fc44c1fd3eb3191f80986b0a69bdc6c41e29279
5
5
  SHA512:
6
- metadata.gz: f2d9b8a53ed1ef26b0ab22dc64108ea69cecfc76c13505b4d184e2df0823ddb78857ccf815152bc1adf202a94a0b1a3010af4c7714012842f675ee3428c6109e
7
- data.tar.gz: 5b33148ca9f3d650218f66ca59964c04c91e87dfa730f8cd997aaad87fe36d19decdf1833463512ecc3f457cbe1bb8b5fbe7c5f4527325fe686cde1718b335e7
6
+ metadata.gz: 9af68ad0b61042517beea619be96074c5e0f8c87c99e8f1094a6d6efdc63da87a5dcb31349435d17ae61755ac34ba7a9c50709f71b4b22ed87ff93db309bca60
7
+ data.tar.gz: 59fcbe7267b2eb0670605770bdf450784d06290089cbe8c0e66cd18919283564c77b798ba7556c4c24010e6c058e0c013b4018ca723fb1ddb60862732a7ab1c5
data/README.md CHANGED
@@ -33,8 +33,51 @@ class Client
33
33
  end
34
34
  ```
35
35
 
36
+ ### Caching requisites
37
+
38
+ * GET requests only.
39
+
40
+ * The server must send a `Cache-Control` header. Otherwise this gem
41
+ will always revalidate.
42
+
43
+ * A request is revalidated when:
44
+ * The server sends a `no-store` directive.
45
+ * The server sends a `no-cache` directive.
46
+ * The server sends a `max-age=0,must-revalidate` directive.
47
+
48
+ * A request is stale when its age is greater than `max-age`.
49
+
36
50
  ### Cache stores
37
51
 
52
+ Requests are stored by their URL and a cache key, and point at the
53
+ latest response.
54
+
55
+ The cache key is generated from requested URL and headers used. If the
56
+ headers change for every request or are sensitive (X-* headers used for
57
+ bespoke authentication), you can add the `cache_key: 'string'` option to
58
+ the request.
59
+
60
+ ```ruby
61
+ url = 'https://example.org'
62
+ sensitive_token = 'token'
63
+
64
+ HTTParty.get(
65
+ url,
66
+ headers: { 'X-Token': sensitive_token },
67
+ cache_key: url
68
+ )
69
+ ```
70
+
71
+ Otherwise you'll see many requests cached all pointing to the same
72
+ response.
73
+
74
+ `Date`, `Authorization`, `Signature` and `Cookie` headers are already
75
+ ignored.
76
+
77
+ Responses are stored by their URL and a cache key composed by its `Vary`
78
+ headers. This way if you send a request header that could change the
79
+ response, you'll get a new one.
80
+
38
81
  #### Redis
39
82
 
40
83
  If you want to use Redis as a cache store:
@@ -6,6 +6,7 @@ module HTTParty
6
6
  #
7
7
  # @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching}
8
8
  module Request
9
+ SENSITIVE_HEADERS = %w[Cookie Authorization Date Signature].freeze
9
10
  CACHE_REVALIDATION_HEADERS = {
10
11
  'ETag' => 'If-None-Match',
11
12
  'Last-Modified' => 'If-Modified-Since'
@@ -15,7 +16,14 @@ module HTTParty
15
16
  #
16
17
  # @return [String]
17
18
  def cache_key
18
- @cache_key ||= "request:#{uri}##{URI.encode_www_form(options[:headers] || {})}"
19
+ @cache_key ||= "http-party-cache:request:#{uri}##{URI.encode_www_form(cache_params)}"
20
+ end
21
+
22
+ # @return [Hash]
23
+ def cache_params
24
+ return { 'X-Cache-Key' => options[:cache_key] } if options.key? :cache_key
25
+
26
+ options[:headers].to_h.except(*SENSITIVE_HEADERS) || {}
19
27
  end
20
28
 
21
29
  def validate
@@ -24,14 +32,21 @@ module HTTParty
24
32
  raise ArgumentError, 'Caching is enabled but store was not provided' if caching? && cache_store.nil?
25
33
  end
26
34
 
35
+ # A cacheable request
36
+ #
37
+ # @return [Boolean]
38
+ def cacheable?
39
+ caching? && http_method == Net::HTTP::Get
40
+ end
41
+
27
42
  # Patch HTTParty::Request#perform to provide caching for GET
28
43
  # requests
29
44
  #
30
45
  # @return [HTTParty::Response]
31
46
  def perform(&block)
32
- return super(&block) unless caching? && http_method == Net::HTTP::Get
47
+ return super(&block) unless cacheable?
33
48
 
34
- if cached?
49
+ if response_cached?
35
50
  handle_revalidation
36
51
  else
37
52
  super(&block).tap do |response|
@@ -46,24 +61,27 @@ module HTTParty
46
61
  # evicted from cache or is corrupted
47
62
  #
48
63
  # @return [Bool]
49
- def cached?
64
+ def response_cached?
50
65
  cache_store.key?(cache_key) &&
51
66
  cache_store.key?(cache_store.get(cache_key)) &&
52
- cache_store.get(cache_store.get(cache_key)).is_a?(HTTParty::Response)
67
+ cached_response.is_a?(HTTParty::Response)
53
68
  end
54
69
 
55
70
  def caching?
56
71
  !!options[:caching]
57
72
  end
58
73
 
74
+ # @return [HTTParty::Response]
75
+ def cached_response
76
+ @cached_response ||= cache_store.get(cache_store.get(cache_key))
77
+ end
78
+
59
79
  private
60
80
 
61
81
  # Revalidates request
62
82
  #
63
83
  # @return [HTTParty::Response]
64
84
  def handle_revalidation
65
- cached_response = cache_store.get(cache_store.get(cache_key))
66
-
67
85
  if cached_response.revalidate? || cached_response.stale?
68
86
  self.http_method = Net::HTTP::Head
69
87
  options[:cached_response] = cached_response
@@ -80,7 +98,7 @@ module HTTParty
80
98
  # Remove from cache so we can perform the request, otherwise
81
99
  # we produce an infinite loop
82
100
  cache_store.delete(cache_key)
83
- response = perform
101
+ @cached_response = response = perform
84
102
  end
85
103
 
86
104
  cache_store.set(response.cache_key, response)
@@ -6,11 +6,6 @@ module HTTParty
6
6
  #
7
7
  # @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching}
8
8
  module Response
9
- # Detects if response is cached
10
- def cached?
11
- code == 304
12
- end
13
-
14
9
  # Parses Cache-Control headers
15
10
  #
16
11
  # @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/cache-control}
@@ -54,7 +49,13 @@ module HTTParty
54
49
  # @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#force_revalidation}
55
50
  # @return [Bool]
56
51
  def revalidate?
57
- !!(cache_control[:no_cache] || (cache_control[:max_age]&.zero? && cache_control[:must_revalidate]))
52
+ cache_control.empty? ||
53
+ cache_control[:no_store] ||
54
+ cache_control[:no_cache] ||
55
+ (
56
+ cache_control[:max_age]&.zero? &&
57
+ cache_control[:must_revalidate]
58
+ )
58
59
  end
59
60
 
60
61
  # Returns the request headers that vary responses
@@ -68,7 +69,7 @@ module HTTParty
68
69
  #
69
70
  # @return [String]
70
71
  def cache_key
71
- @cache_key ||= "response:#{request.uri}##{URI.encode_www_form vary}"
72
+ @cache_key ||= "httparty-cache:response:#{request.uri}##{URI.encode_www_form vary}"
72
73
  end
73
74
  end
74
75
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: httparty-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - f
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-31 00:00:00.000000000 Z
11
+ date: 2024-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -129,35 +129,35 @@ dependencies:
129
129
  - !ruby/object:Gem::Version
130
130
  version: 0.14.0
131
131
  - !ruby/object:Gem::Dependency
132
- name: redis-client
132
+ name: jekyll
133
133
  requirement: !ruby/object:Gem::Requirement
134
134
  requirements:
135
- - - "~>"
135
+ - - ">="
136
136
  - !ruby/object:Gem::Version
137
- version: 0.14.0
137
+ version: '0'
138
138
  type: :development
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
- - - "~>"
142
+ - - ">="
143
143
  - !ruby/object:Gem::Version
144
- version: 0.14.0
144
+ version: '0'
145
145
  - !ruby/object:Gem::Dependency
146
- name: rubocop
146
+ name: redis-client
147
147
  requirement: !ruby/object:Gem::Requirement
148
148
  requirements:
149
- - - ">="
149
+ - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: '0'
151
+ version: 0.14.0
152
152
  type: :development
153
153
  prerelease: false
154
154
  version_requirements: !ruby/object:Gem::Requirement
155
155
  requirements:
156
- - - ">="
156
+ - - "~>"
157
157
  - !ruby/object:Gem::Version
158
- version: '0'
158
+ version: 0.14.0
159
159
  - !ruby/object:Gem::Dependency
160
- name: timecop
160
+ name: rubocop
161
161
  requirement: !ruby/object:Gem::Requirement
162
162
  requirements:
163
163
  - - ">="
@@ -171,7 +171,7 @@ dependencies:
171
171
  - !ruby/object:Gem::Version
172
172
  version: '0'
173
173
  - !ruby/object:Gem::Dependency
174
- name: jekyll
174
+ name: timecop
175
175
  requirement: !ruby/object:Gem::Requirement
176
176
  requirements:
177
177
  - - ">="