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 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