httparty-cache 0.0.2 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -0
- data/lib/httparty/cache/request.rb +17 -9
- data/lib/httparty/cache/response.rb +52 -3
- data/lib/httparty/cache/store/jekyll.rb +8 -0
- data/lib/httparty/cache/store/memory.rb +8 -0
- data/lib/httparty/cache/store/redis.rb +18 -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: 0fede8274e3bf761ebaa8b53d8ad10ab957e92c6bfba35391de1de907bd91800
|
4
|
+
data.tar.gz: 1b5ac5dcaf6da720d56f7b9e9b6c88ff706f4b7be2fe48383eec4ecd4359619c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a515bd37ba299cfa32ffb50cae4b073592652073e6857a505a48e80195c998a21eeb464384806f4703a8855b861f0013cf9ff2fe84e8284ddca6f2f998fedfc0
|
7
|
+
data.tar.gz: 171aac5d0d92adf07222824047462c20e88a3bf806426de0e0aaae08572ac4272767b10e6279415e2f1d7502bbbe1a7191b4a8f6edc7577bf084a8cc01878e5e
|
data/README.md
CHANGED
@@ -123,3 +123,11 @@ class Client
|
|
123
123
|
# or
|
124
124
|
cache_store HTTParty::Cache::Store::Jekyll.new(name: 'My::Jekyll::Cache')
|
125
125
|
end
|
126
|
+
```
|
127
|
+
|
128
|
+
## Caveats!
|
129
|
+
|
130
|
+
* Response marshaling has been changed to prevent stack level too deep
|
131
|
+
exceptions while marshaling the request. Bringing a response from the
|
132
|
+
cache will have a request with the original HTTP method, path and
|
133
|
+
headers sent.
|
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'digest/sha2'
|
4
|
+
|
3
5
|
module HTTParty
|
4
6
|
module Cache
|
5
7
|
# Extends HTTParty::Request with caching methods
|
6
8
|
#
|
7
9
|
# @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching}
|
8
10
|
module Request
|
9
|
-
SENSITIVE_HEADERS = %w[
|
11
|
+
SENSITIVE_HEADERS = %w[cookie authorization date signature].freeze
|
10
12
|
CACHE_REVALIDATION_HEADERS = {
|
11
13
|
'ETag' => 'If-None-Match',
|
12
14
|
'Last-Modified' => 'If-Modified-Since'
|
@@ -16,14 +18,18 @@ module HTTParty
|
|
16
18
|
#
|
17
19
|
# @return [String]
|
18
20
|
def cache_key
|
19
|
-
@cache_key ||=
|
21
|
+
@cache_key ||=
|
22
|
+
begin
|
23
|
+
key = "#{uri}##{URI.encode_www_form(cache_params)}"
|
24
|
+
"httpparty-cache:request:#{Digest::SHA2.hexdigest(key)}"
|
25
|
+
end
|
20
26
|
end
|
21
27
|
|
22
28
|
# @return [Hash]
|
23
29
|
def cache_params
|
24
|
-
return { '
|
30
|
+
return { 'x-cache-key' => options[:cache_key] } if options.key? :cache_key
|
25
31
|
|
26
|
-
options[:headers].to_h.except(*SENSITIVE_HEADERS)
|
32
|
+
options[:headers].to_h.transform_keys(&:downcase).except(*SENSITIVE_HEADERS)
|
27
33
|
end
|
28
34
|
|
29
35
|
def validate
|
@@ -47,7 +53,7 @@ module HTTParty
|
|
47
53
|
return super(&block) unless cacheable?
|
48
54
|
|
49
55
|
if response_cached?
|
50
|
-
handle_revalidation
|
56
|
+
handle_revalidation(&block)
|
51
57
|
else
|
52
58
|
super(&block).tap do |response|
|
53
59
|
# Point current request to cached response
|
@@ -81,24 +87,26 @@ module HTTParty
|
|
81
87
|
# Revalidates request
|
82
88
|
#
|
83
89
|
# @return [HTTParty::Response]
|
84
|
-
def handle_revalidation
|
90
|
+
def handle_revalidation(&block)
|
85
91
|
if cached_response.revalidate? || cached_response.stale?
|
86
92
|
self.http_method = Net::HTTP::Head
|
87
|
-
options[:cached_response] = cached_response
|
88
93
|
|
89
94
|
add_cache_revalidation_headers
|
90
95
|
|
96
|
+
# Don't run the block here
|
91
97
|
response = perform
|
92
98
|
|
93
99
|
if response.not_modified?
|
94
100
|
cached_response.headers['date'] = response.headers['date']
|
95
101
|
response = cached_response
|
102
|
+
response.hit!
|
96
103
|
else
|
97
104
|
self.http_method = Net::HTTP::Get
|
98
105
|
# Remove from cache so we can perform the request, otherwise
|
99
106
|
# we produce an infinite loop
|
100
107
|
cache_store.delete(cache_key)
|
101
|
-
@cached_response = response = perform
|
108
|
+
@cached_response = response = perform(&block)
|
109
|
+
response.miss!
|
102
110
|
end
|
103
111
|
|
104
112
|
cache_store.set(response.cache_key, response)
|
@@ -120,7 +128,7 @@ module HTTParty
|
|
120
128
|
options[:headers] ||= {}
|
121
129
|
|
122
130
|
CACHE_REVALIDATION_HEADERS.each_pair do |original_header, revalidation_header|
|
123
|
-
next if (value =
|
131
|
+
next if (value = cached_response.headers[original_header]).nil?
|
124
132
|
|
125
133
|
options[:headers][revalidation_header] ||= value
|
126
134
|
end
|
@@ -1,11 +1,56 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'digest/sha2'
|
4
|
+
|
3
5
|
module HTTParty
|
4
6
|
module Cache
|
5
7
|
# Extends HTTParty::Response with caching methods
|
6
8
|
#
|
7
9
|
# @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching}
|
8
10
|
module Response
|
11
|
+
X_HEADER = 'x-httparty-cache'
|
12
|
+
HIT = 'hit'
|
13
|
+
MISS = 'miss'
|
14
|
+
|
15
|
+
# Prevent stack too deep errors while keeping important
|
16
|
+
# information
|
17
|
+
def _dump(_level)
|
18
|
+
_request = HTTParty::Request.new(request.http_method, request.path, headers: request.options[:headers]&.to_hash)
|
19
|
+
_body = response.instance_variable_get(:@body)
|
20
|
+
_read_adapter = _body.is_a?(Net::ReadAdapter)
|
21
|
+
|
22
|
+
response.instance_variable_set(:@body, nil) if _read_adapter
|
23
|
+
|
24
|
+
Marshal.dump([_request, response, parsed_response, body]).tap do
|
25
|
+
response.instance_variable_set(:@body, _body) if _read_adapter
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def hit!
|
30
|
+
response[X_HEADER] = headers[X_HEADER] = HIT
|
31
|
+
end
|
32
|
+
|
33
|
+
def miss!
|
34
|
+
response[X_HEADER] = headers[X_HEADER] = MISS
|
35
|
+
end
|
36
|
+
|
37
|
+
def fresh!
|
38
|
+
response.delete(X_HEADER)
|
39
|
+
headers.delete(X_HEADER)
|
40
|
+
end
|
41
|
+
|
42
|
+
def hit?
|
43
|
+
headers[X_HEADER] == HIT
|
44
|
+
end
|
45
|
+
|
46
|
+
def miss?
|
47
|
+
headers[X_HEADER] == MISS
|
48
|
+
end
|
49
|
+
|
50
|
+
def reused?
|
51
|
+
headers.key?(X_HEADER)
|
52
|
+
end
|
53
|
+
|
9
54
|
# Parses Cache-Control headers
|
10
55
|
#
|
11
56
|
# @see {https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/cache-control}
|
@@ -62,18 +107,22 @@ module HTTParty
|
|
62
107
|
#
|
63
108
|
# @return [Hash]
|
64
109
|
def vary
|
65
|
-
@vary ||= request.options[:headers].to_h.slice(*headers['
|
110
|
+
@vary ||= request.options[:headers].to_h.slice(*headers['vary'].to_s.split(',').map(&:strip).sort).transform_keys(&:downcase)
|
66
111
|
end
|
67
112
|
|
68
113
|
# Generates a cache key
|
69
114
|
#
|
70
115
|
# @return [String]
|
71
116
|
def cache_key
|
72
|
-
@cache_key ||=
|
117
|
+
@cache_key ||=
|
118
|
+
begin
|
119
|
+
key = "#{uri}##{URI.encode_www_form(vary)}"
|
120
|
+
"httparty-cache:response:#{Digest::SHA2.hexdigest(key)}"
|
121
|
+
end
|
73
122
|
end
|
74
123
|
end
|
75
124
|
end
|
76
125
|
end
|
77
126
|
|
78
127
|
# Patch HTTParty::Response
|
79
|
-
HTTParty::Response.
|
128
|
+
HTTParty::Response.prepend HTTParty::Cache::Response
|
@@ -21,6 +21,14 @@ module HTTParty
|
|
21
21
|
@store = ::Jekyll::Cache.new(name)
|
22
22
|
end
|
23
23
|
|
24
|
+
def _dump(_)
|
25
|
+
Marshal.dump(options[:name])
|
26
|
+
end
|
27
|
+
|
28
|
+
def self._load(string)
|
29
|
+
new(name: Marshal.load(string))
|
30
|
+
end
|
31
|
+
|
24
32
|
def set(key, response)
|
25
33
|
@store[key] = response
|
26
34
|
response
|
@@ -21,6 +21,14 @@ module HTTParty
|
|
21
21
|
|
22
22
|
# @param :redis_url [String]
|
23
23
|
def initialize(redis_url: nil)
|
24
|
+
marshal_load(redis_url)
|
25
|
+
end
|
26
|
+
|
27
|
+
def marshal_dump
|
28
|
+
options[:redis_url]
|
29
|
+
end
|
30
|
+
|
31
|
+
def marshal_load(redis_url)
|
24
32
|
@options = {}
|
25
33
|
@options[:redis_url] = redis_url || ENV['REDIS_URL']
|
26
34
|
@config = RedisClient.config(url: @options[:redis_url])
|
@@ -28,6 +36,16 @@ module HTTParty
|
|
28
36
|
@redis.call('PING')
|
29
37
|
end
|
30
38
|
|
39
|
+
# I couldn't get this to work! It's never called even if I dump
|
40
|
+
# the store directly
|
41
|
+
def _dump(level)
|
42
|
+
options[:redis_url]
|
43
|
+
end
|
44
|
+
|
45
|
+
def self._load(string)
|
46
|
+
new(redis_url: string)
|
47
|
+
end
|
48
|
+
|
31
49
|
# Retrieves a key
|
32
50
|
#
|
33
51
|
# @param :key [String]
|
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.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- f
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|