httparty-cache 0.0.2 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6b5ee7949c1ff90bad003ea68a65b11de85f2aba908c3aa3b733e53976d15b33
4
- data.tar.gz: d7f636874b72c75534ec6e060fc44c1fd3eb3191f80986b0a69bdc6c41e29279
3
+ metadata.gz: 0fede8274e3bf761ebaa8b53d8ad10ab957e92c6bfba35391de1de907bd91800
4
+ data.tar.gz: 1b5ac5dcaf6da720d56f7b9e9b6c88ff706f4b7be2fe48383eec4ecd4359619c
5
5
  SHA512:
6
- metadata.gz: 9af68ad0b61042517beea619be96074c5e0f8c87c99e8f1094a6d6efdc63da87a5dcb31349435d17ae61755ac34ba7a9c50709f71b4b22ed87ff93db309bca60
7
- data.tar.gz: 59fcbe7267b2eb0670605770bdf450784d06290089cbe8c0e66cd18919283564c77b798ba7556c4c24010e6c058e0c013b4018ca723fb1ddb60862732a7ab1c5
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[Cookie Authorization Date Signature].freeze
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 ||= "http-party-cache:request:#{uri}##{URI.encode_www_form(cache_params)}"
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 { 'X-Cache-Key' => options[:cache_key] } if options.key? :cache_key
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 = options[:cached_response].headers[original_header]).nil?
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['Vary'].to_s.split(',').map(&:strip).sort)
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 ||= "httparty-cache:response:#{request.uri}##{URI.encode_www_form vary}"
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.include HTTParty::Cache::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
@@ -19,6 +19,14 @@ module HTTParty
19
19
  clear
20
20
  end
21
21
 
22
+ def _dump(_)
23
+ Marshal.dump(nil)
24
+ end
25
+
26
+ def self._load(_)
27
+ new
28
+ end
29
+
22
30
  def getset(key)
23
31
  store[key] ||= yield
24
32
  end
@@ -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.2
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-02-08 00:00:00.000000000 Z
11
+ date: 2024-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty