response_bank 1.6.0 → 1.8.0

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: 4049027dc5a512bb6f1225b179ac82989b995e8e77f0b384fce0154c58cd76c0
4
- data.tar.gz: 0351324db2bb6a5d00d2585d7e2fb52d5f1f17860f19ec56e23bc848d411ce0f
3
+ metadata.gz: 29c24e1f40f49dfe75fb0fee30851a8892ed5ca93d3740038fc059c3eb23eac1
4
+ data.tar.gz: 6b1d0473f7abcf5b7b3377da97e67d4954fd14f90b9c4a75b7ebe3d0f136d8e7
5
5
  SHA512:
6
- metadata.gz: 278e15de6e89c0a006c13da52ff42a326be704050ef905d8ad7c0541a8444359253923a9331747440f72fe2855ac7addf3af3b917c75c5a2775c052618aa62fb
7
- data.tar.gz: 9ec95ddb14b3a4d6763dd7ddd0e40b9f5367a3943baad464890b64723747b849627cbb513e1d3b982640563f3c73e1f18d8a437470e6303853369c07bf9b8154
6
+ metadata.gz: 06d5965eed82aba811616d52444a07287e566aff3f43451d1ff343eb55b2f8be47773daa8a9388589e69465e2d728654162925108614fbdd39c173bc16671e2f
7
+ data.tar.gz: 5f47dd03e0ed7fc61ef67306416040be136faa4e6c1fe0bc8552a3ef150b531cad370212772420bdfe36452d3918adf38722da7e56b560a8f892db6fb43a2456
data/README.md CHANGED
@@ -305,6 +305,19 @@ Advanced integrations can still install the per-request injector directly in the
305
305
  env[ResponseBank::BrotliSpliceSlot::INJECTOR_ENV_KEY] = injector
306
306
  ```
307
307
 
308
+ ## Observing server cache hits
309
+
310
+ After successfully serving an entry from the server cache, ResponseBank exposes its generation time and stale-while-revalidate status in the Rack environment:
311
+
312
+ ```ruby
313
+ timestamp = env['cacheable.timestamp']
314
+ stale = env['cacheable.stale']
315
+ ```
316
+
317
+ `cacheable.timestamp` is only set after successfully serving a server-cache entry.
318
+ `cacheable.stale` is initialized to `false` when a server-cache entry is evaluated
319
+ and set to `true` only when ResponseBank serves it through stale-while-revalidate.
320
+
308
321
  ## Exception Handling
309
322
 
310
323
  ResponseBank handles all exceptions gracefully during cache operations. If an exception occurs while reading from cache, deserializing cached data, or writing to cache, the middleware will:
@@ -133,6 +133,7 @@ module ResponseBank
133
133
  @env['cacheable.compression_level'] = compression_level
134
134
 
135
135
  @env['cacheable.locked'] ||= false
136
+ @env['cacheable.stale'] = false
136
137
 
137
138
  # to preserve the unversioned/versioned logging messages from past releases we split the match_entity_tag test
138
139
  if match_entity_tag == "*"
@@ -149,6 +150,7 @@ module ResponseBank
149
150
  return
150
151
  elsif stale_while_revalidate?(timestamp, cache_age_tolerance)
151
152
  # cache is being regenerated, can we avoid piling on and use a stale version in the interim?
153
+ @env['cacheable.stale'] = true
152
154
  ResponseBank.log("Cache hit: server (recent)")
153
155
  else
154
156
  ResponseBank.log("Found an unversioned cache entry, but it was too old (#{timestamp})")
@@ -184,6 +186,7 @@ module ResponseBank
184
186
  @env.delete(ResponseBank::METADATA_ENV_KEY)
185
187
  end
186
188
 
189
+ @env['cacheable.timestamp'] = timestamp
187
190
  [status, @headers, [body]]
188
191
 
189
192
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ResponseBank
3
- VERSION = "1.6.0"
3
+ VERSION = "1.8.0"
4
4
  end
data/lib/response_bank.rb CHANGED
@@ -114,16 +114,20 @@ module ResponseBank
114
114
  when Hash
115
115
  return data.inspect unless data.key?(:key)
116
116
 
117
- key = hash_value_str(data[:key])
117
+ # Components are joined as bytes, so values in different encodings can't raise.
118
+ key = String.new(encoding: Encoding::BINARY)
118
119
 
119
- key = %{#{data[:key_schema_version]}:#{key}} if data[:key_schema_version]
120
+ key << hash_value_str(data[:key_schema_version]) << ":" if data[:key_schema_version]
120
121
 
121
- key = %{#{key}:#{hash_value_str(data[:version])}} if data[:version]
122
+ key << hash_value_str(data[:key])
123
+
124
+ key << ":" << hash_value_str(data[:version]) if data[:version]
122
125
 
123
126
  # add the encoding to only the cache key but don't expose this detail in the entity_tag
124
- key = %{#{key}:#{hash_value_str(data[:encoding])}} if data[:encoding]
127
+ key << ":" << hash_value_str(data[:encoding]) if data[:encoding]
125
128
 
126
- key
129
+ key.force_encoding(Encoding::UTF_8)
130
+ key.valid_encoding? ? key : key.force_encoding(Encoding::BINARY)
127
131
  when Array
128
132
  data.inspect
129
133
  when Time, DateTime
@@ -152,10 +156,32 @@ module ResponseBank
152
156
 
153
157
  def hash_value_str(data)
154
158
  if data.is_a?(Hash)
155
- data.values.join(",")
159
+ append_key_component(String.new(encoding: Encoding::BINARY), data)
160
+ else
161
+ data.to_s.b
162
+ end
163
+ end
164
+
165
+ # Hashes and Arrays are written as a type tag and element count, followed
166
+ # by their elements; Hash entries are written as name then value, in
167
+ # insertion order. Every other value is written as the byte length of its
168
+ # #to_s followed by those bytes, so no value can be read as part of another.
169
+ def append_key_component(buffer, data)
170
+ case data
171
+ when Hash
172
+ buffer << "h" << data.size.to_s << ":"
173
+ data.each do |name, value|
174
+ append_key_component(buffer, name)
175
+ append_key_component(buffer, value)
176
+ end
177
+ when Array
178
+ buffer << "a" << data.size.to_s << ":"
179
+ data.each { |value| append_key_component(buffer, value) }
156
180
  else
157
- data.to_s
181
+ value = data.to_s.b
182
+ buffer << value.bytesize.to_s << ":" << value
158
183
  end
184
+ buffer
159
185
  end
160
186
  end
161
187
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: response_bank
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Lütke
@@ -176,7 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
176
176
  - !ruby/object:Gem::Version
177
177
  version: '0'
178
178
  requirements: []
179
- rubygems_version: 4.0.21
179
+ rubygems_version: 4.0.23
180
180
  specification_version: 4
181
181
  summary: Simple response caching for Ruby applications
182
182
  test_files: []