async-http-cache 0.4.5 → 0.4.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: 5ef0cd31192b81f8fc4acfefdb378d2ae673ec004b572555e1c1298a0afa5ba6
4
- data.tar.gz: 554b926efed070b44a672c2e422cf7be1aa243cd619ab4260210d468321ff044
3
+ metadata.gz: 7ae1d78b87d12a34eb5217c0cf6a49d6ecd81c5322790d563568a48e951733fe
4
+ data.tar.gz: 44a915c95e0eced20d783f702179b701c1ba07678bc62e3201d8adce1b5d204c
5
5
  SHA512:
6
- metadata.gz: f8e688e64d6cf8e734f80ef3cf1422de4b5ae89055d926b047c80d39ef2c23c70a5e085082e86a70fa09d912767505fc2bcaed1d837c3c3c1ce50a45efd3cc7e
7
- data.tar.gz: 3e702d6db9c8764fd0d2932ba9bc3a27aafc76b001380f2dee77fcc4ceae350044593d36cb3661b945bda78f47bb951db43fa6b99d7fab5e51732a50d3cc3e18
6
+ metadata.gz: b2faf1e2713d8f273e9b938b6dfd01ece309533a8b96173306fc93c1cd02ca84305eada3dc99967d27605f6fca369bef6c57a745361882243a6e519a32987c48
7
+ data.tar.gz: ec998fd4509ec25c908c176ce894904eb7e3515073b7a750e56ac47022d6c336c4d6d0437ee2be1e9fa3bdc5c7f53868028a4dd82395691e2fc15d5e72437786
checksums.yaml.gz.sig CHANGED
Binary file
@@ -0,0 +1,80 @@
1
+ # Getting Started
2
+
3
+ This guide explains how to get started with `async-http-cache`, a cache middleware for `Async::HTTP` clients and servers.
4
+
5
+ ## Installation
6
+
7
+ Add the gem to your project:
8
+
9
+ ```bash
10
+ $ bundle add async-http-cache
11
+ ```
12
+
13
+ ## Core Concepts
14
+
15
+ `async-http-cache` has several core concepts:
16
+
17
+ - A {Async::HTTP::Cache::General} which represents the main cache middleware that implements a general shared cache according to RFC 9111.
18
+ - A cache store system that handles the actual storage and retrieval of cached responses.
19
+ - Cache-aware request and response handling that respects HTTP caching headers.
20
+
21
+ ## Usage
22
+
23
+ The cache middleware can be used with both `Async::HTTP` clients and servers to provide transparent HTTP caching.
24
+
25
+ ### Client Side Caching
26
+
27
+ Here's how to use the cache with an HTTP client:
28
+
29
+ ```ruby
30
+ require "async"
31
+ require "async/http"
32
+ require "async/http/cache"
33
+
34
+ endpoint = Async::HTTP::Endpoint.parse("https://www.oriontransfer.co.nz")
35
+ client = Async::HTTP::Client.new(endpoint)
36
+ cache = Async::HTTP::Cache::General.new(client)
37
+
38
+ Async do
39
+ 2.times do
40
+ response = cache.get("/products/index")
41
+ puts response.inspect
42
+ # <Async::HTTP::Protocol::HTTP2::Response ...>
43
+ # <Async::HTTP::Cache::Response ...>
44
+ response.finish
45
+ end
46
+ ensure
47
+ cache.close
48
+ end
49
+ ```
50
+
51
+ In this example:
52
+
53
+ 1. We create an HTTP client as usual
54
+ 2. We wrap it with `Async::HTTP::Cache::General` to add caching capability
55
+ 3. The first request will hit the remote server
56
+ 4. The second identical request will be served from the cache (if the response is cacheable)
57
+
58
+ ### Caching Behavior
59
+
60
+ The cache middleware automatically handles:
61
+
62
+ - **Cacheable Methods**: Only `GET` and `HEAD` requests are cached
63
+ - **Cache Headers**: Respects `Cache-Control`, `Expires`, and other standard HTTP caching headers
64
+ - **Response Codes**: Only certain response codes (200, 203, 300, 301, 302, 404, 410) are cached
65
+ - **Request Validation**: Requests with authorization headers, cookies, or request bodies are not cached
66
+
67
+ ### Important Notes on Vary Header
68
+
69
+ The `vary` header creates a headache for proxy implementations, because it creates a combinatorial explosion of cache keys, even if the content is the same. Try to avoid it unless absolutely necessary.
70
+
71
+ ## Custom Cache Stores
72
+
73
+ By default, the cache uses an in-memory store, but you can provide custom storage backends:
74
+
75
+ ```ruby
76
+ # Use a custom store
77
+ cache = Async::HTTP::Cache::General.new(client, store: MyCustomStore.new)
78
+ ```
79
+
80
+ The store must implement the interface defined by {Async::HTTP::Cache::Store}.
@@ -0,0 +1,12 @@
1
+ # Automatically generated context index for Utopia::Project guides.
2
+ # Do not edit then files in this directory directly, instead edit the guides and then run `bake utopia:project:agent:context:update`.
3
+ ---
4
+ description: Standard-compliant cache for async-http.
5
+ metadata:
6
+ documentation_uri: https://socketry.github.io/async-http-cache/
7
+ source_code_uri: https://github.com/socketry/async-http-cache.git
8
+ files:
9
+ - path: getting-started.md
10
+ title: Getting Started
11
+ description: This guide explains how to get started with `async-http-cache`, a cache
12
+ middleware for `Async::HTTP` clients and servers.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2024, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
 
6
6
  require "protocol/http/body/rewindable"
7
7
  require "protocol/http/body/completable"
@@ -13,10 +13,17 @@ require "console/event/failure"
13
13
  module Async
14
14
  module HTTP
15
15
  module Cache
16
+ # Provides utilities for wrapping HTTP response bodies with caching capabilities.
16
17
  module Body
17
18
  TRAILER = "trailer"
18
19
  ETAG = "etag"
19
20
 
21
+ # Wrap a response body with caching functionality, including ETag generation and completion handling.
22
+ # @parameter response [Protocol::HTTP::Response] The HTTP response to wrap.
23
+ # @yields {|response, body| ...} The block to execute when caching is complete.
24
+ # @parameter response [Protocol::HTTP::Response] The wrapped response.
25
+ # @parameter body [Protocol::HTTP::Body::Buffered, nil] The buffered response body.
26
+ # @returns [Protocol::HTTP::Response] The original response, potentially with modified headers.
20
27
  def self.wrap(response, &block)
21
28
  if body = response.body
22
29
  if body.empty?
@@ -27,13 +34,13 @@ module Async
27
34
  rewindable = ::Protocol::HTTP::Body::Rewindable.wrap(response)
28
35
 
29
36
  unless response.headers.include?(ETAG)
37
+ # Add the etag header to the trailers:
38
+ response.headers.add(TRAILER, ETAG)
39
+
30
40
  # Compute a digest and add it to the response headers:
31
41
  ::Protocol::HTTP::Body::Digestable.wrap(response) do |wrapper|
32
42
  response.headers.add(ETAG, wrapper.etag)
33
43
  end
34
-
35
- # Ensure the etag is listed as a trailer:
36
- response.headers.add(TRAILER, ETAG)
37
44
  end
38
45
 
39
46
  # Wrap the response with the callback:
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2024, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
  # Copyright, 2022, by Colin Kelley.
6
6
 
7
7
  require "set"
@@ -37,6 +37,9 @@ module Async
37
37
  410 => true # Gone
38
38
  }.freeze
39
39
 
40
+ # Initialize a new cache middleware instance.
41
+ # @parameter app [Object] The downstream application or middleware.
42
+ # @parameter store [Store] The cache store to use for persistence.
40
43
  def initialize(app, store: Store.default)
41
44
  super(app)
42
45
 
@@ -48,18 +51,25 @@ module Async
48
51
  attr :count
49
52
  attr :store
50
53
 
54
+ # Close the cache and clean up resources.
51
55
  def close
52
56
  @store.close
53
57
  ensure
54
58
  super
55
59
  end
56
60
 
61
+ # Generate a cache key for the given request.
62
+ # @parameter request [Protocol::HTTP::Request] The HTTP request.
63
+ # @returns [Array] A cache key array containing authority, method, and path.
57
64
  def key(request)
58
65
  @store.normalize(request)
59
66
 
60
67
  [request.authority, request.method, request.path]
61
68
  end
62
69
 
70
+ # Determine if a request is cacheable based on method, headers, and body.
71
+ # @parameter request [Protocol::HTTP::Request] The HTTP request to check.
72
+ # @returns [Boolean] True if the request can be cached.
63
73
  def cacheable_request?(request)
64
74
  # We don't support caching requests which have a request body:
65
75
  if request.body
@@ -88,6 +98,9 @@ module Async
88
98
  return true
89
99
  end
90
100
 
101
+ # Check if response headers allow caching.
102
+ # @parameter headers [Protocol::HTTP::Headers] The response headers to check.
103
+ # @returns [Boolean] True if headers permit caching.
91
104
  def cacheable_response_headers?(headers)
92
105
  if cache_control = headers[CACHE_CONTROL]
93
106
  if cache_control.no_store? || cache_control.private?
@@ -100,10 +113,13 @@ module Async
100
113
  Console.logger.debug(self) {"Cannot cache response with set-cookie header!"}
101
114
  return false
102
115
  end
103
-
116
+
104
117
  return true
105
118
  end
106
119
 
120
+ # Determine if a response is cacheable based on status code and headers.
121
+ # @parameter response [Protocol::HTTP::Response] The HTTP response to check.
122
+ # @returns [Boolean] True if the response can be cached.
107
123
  def cacheable_response?(response)
108
124
  # At this point, we know response.status and response.headers.
109
125
  # But we don't know response.body or response.headers.trailer.
@@ -162,6 +178,9 @@ module Async
162
178
  end
163
179
  end
164
180
 
181
+ # Process an HTTP request, checking cache first and storing responses when appropriate.
182
+ # @parameter request [Protocol::HTTP::Request] The HTTP request to process.
183
+ # @returns [Protocol::HTTP::Response] Either a cached response or a fresh response from upstream.
165
184
  def call(request)
166
185
  cache_control = request.headers[CACHE_CONTROL]
167
186
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2024, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
 
6
6
  require "protocol/http/response"
7
7
  require "async/clock"
@@ -9,12 +9,16 @@ require "async/clock"
9
9
  module Async
10
10
  module HTTP
11
11
  module Cache
12
+ # Represents a cached HTTP response with cache-specific metadata and functionality.
12
13
  class Response < ::Protocol::HTTP::Response
13
14
  CACHE_CONTROL = "cache-control"
14
15
  ETAG = "etag"
15
16
 
16
17
  X_CACHE = "x-cache"
17
18
 
19
+ # Initialize a new cached response.
20
+ # @parameter response [Protocol::HTTP::Response] The original HTTP response.
21
+ # @parameter body [Protocol::HTTP::Body] The response body.
18
22
  def initialize(response, body)
19
23
  @generated_at = Async::Clock.now
20
24
 
@@ -34,20 +38,28 @@ module Async
34
38
 
35
39
  attr :generated_at
36
40
 
41
+ # Get the ETag header value for this cached response.
42
+ # @returns [String, nil] The ETag value or nil if not present.
37
43
  def etag
38
44
  @etag ||= @headers[ETAG]
39
45
  end
40
46
 
47
+ # Calculate the age of this cached response in seconds.
48
+ # @returns [Float] The number of seconds since the response was generated.
41
49
  def age
42
50
  Async::Clock.now - @generated_at
43
51
  end
44
52
 
53
+ # Check if this cached response has expired based on its max-age.
54
+ # @returns [Boolean, nil] True if expired, false if still valid, nil if no max-age set.
45
55
  def expired?
46
56
  if @max_age
47
57
  self.age > @max_age
48
58
  end
49
59
  end
50
60
 
61
+ # Create a duplicate of this cached response with independent body and headers.
62
+ # @returns [Response] A new Response instance with duplicated body and headers.
51
63
  def dup
52
64
  dup = super
53
65
 
@@ -1,13 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2024, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
 
6
6
  module Async
7
7
  module HTTP
8
8
  module Cache
9
9
  module Store
10
+ # Represents an in-memory cache store with automatic pruning of expired entries.
10
11
  class Memory
12
+ # Initialize a new in-memory cache store.
13
+ # @parameter limit [Integer] Maximum number of entries to store.
14
+ # @parameter maximum_size [Integer] Maximum size in bytes for individual cached responses.
15
+ # @parameter prune_interval [Integer] Interval in seconds between automatic pruning operations.
11
16
  def initialize(limit: 1024, maximum_size: 1024*64, prune_interval: 60)
12
17
  @index = {}
13
18
  @limit = limit
@@ -42,6 +47,7 @@ module Async
42
47
  end
43
48
  end
44
49
 
50
+ # Close the cache store and stop background pruning.
45
51
  def close
46
52
  @gardener.stop
47
53
  end
@@ -51,6 +57,10 @@ module Async
51
57
  IF_NONE_MATCH = "if-none-match"
52
58
  NOT_MODIFIED = ::Protocol::HTTP::Response[304]
53
59
 
60
+ # Look up a cached response for the given key and request.
61
+ # @parameter key [Array] The cache key to look up.
62
+ # @parameter request [Protocol::HTTP::Request] The HTTP request.
63
+ # @returns [Protocol::HTTP::Response, nil] The cached response or nil if not found/expired.
54
64
  def lookup(key, request)
55
65
  if response = @index[key]
56
66
  if response.expired?
@@ -77,6 +87,10 @@ module Async
77
87
  end
78
88
  end
79
89
 
90
+ # Insert a response into the cache if it meets size and limit constraints.
91
+ # @parameter key [Array] The cache key.
92
+ # @parameter request [Protocol::HTTP::Request] The HTTP request.
93
+ # @parameter response [Protocol::HTTP::Response] The HTTP response to cache.
80
94
  def insert(key, request, response)
81
95
  if @index.size < @limit
82
96
  length = response.body&.length
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2024, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
 
6
6
  module Async
7
7
  module HTTP
@@ -10,18 +10,25 @@ module Async
10
10
  VARY = "vary"
11
11
  ACCEPT_ENCODING = "accept-encoding"
12
12
 
13
+ # Represents a cache store wrapper that handles HTTP Vary header functionality.
13
14
  class Vary
15
+ # Initialize a new Vary store wrapper.
16
+ # @parameter delegate [Store] The underlying cache store to delegate to.
17
+ # @parameter vary [Hash] Initial vary header mappings.
14
18
  def initialize(delegate, vary = {})
15
19
  @delegate = delegate
16
20
  @vary = vary
17
21
  end
18
22
 
23
+ # Close the vary store and its delegate.
19
24
  def close
20
25
  @delegate.close
21
26
  end
22
27
 
23
28
  attr :delegate
24
29
 
30
+ # Normalize request headers to reduce cache key variations.
31
+ # @parameter request [Protocol::HTTP::Request] The HTTP request to normalize.
25
32
  def normalize(request)
26
33
  if accept_encoding = request.headers[ACCEPT_ENCODING]
27
34
  if accept_encoding.include?("gzip")
@@ -32,10 +39,18 @@ module Async
32
39
  end
33
40
  end
34
41
 
42
+ # Generate vary-specific key components from request headers.
43
+ # @parameter headers [Protocol::HTTP::Headers] The request headers.
44
+ # @parameter vary [Array] Array of header names that affect caching.
45
+ # @returns [Array] Array of header values for the vary keys.
35
46
  def key_for(headers, vary)
36
47
  vary.map{|key| headers[key]}
37
48
  end
38
49
 
50
+ # Look up a cached response, accounting for vary headers.
51
+ # @parameter key [Array] The base cache key.
52
+ # @parameter request [Protocol::HTTP::Request] The HTTP request.
53
+ # @returns [Protocol::HTTP::Response, nil] The cached response or nil if not found.
39
54
  def lookup(key, request)
40
55
  if vary = @vary[key]
41
56
  # We should provide user-supported normalization here:
@@ -45,6 +60,10 @@ module Async
45
60
  return @delegate.lookup(key, request)
46
61
  end
47
62
 
63
+ # Insert a response into the cache, handling vary headers appropriately.
64
+ # @parameter key [Array] The base cache key.
65
+ # @parameter request [Protocol::HTTP::Request] The HTTP request.
66
+ # @parameter response [Protocol::HTTP::Response] The HTTP response to cache.
48
67
  def insert(key, request, response)
49
68
  if vary = response.headers[VARY]&.sort
50
69
  @vary[key] = vary
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2024, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "store/memory"
7
7
  require_relative "store/vary"
@@ -9,7 +9,10 @@ require_relative "store/vary"
9
9
  module Async
10
10
  module HTTP
11
11
  module Cache
12
+ # Provides cache storage implementations and utilities.
12
13
  module Store
14
+ # Create a default cache store with Vary support over an in-memory store.
15
+ # @returns [Store::Vary] A default cache store instance.
13
16
  def self.default
14
17
  Vary.new(Memory.new)
15
18
  end
@@ -1,12 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2024, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
 
6
+ # @namespace
6
7
  module Async
8
+ # @namespace
7
9
  module HTTP
10
+ # @namespace
8
11
  module Cache
9
- VERSION = "0.4.5"
12
+ VERSION = "0.4.6"
10
13
  end
11
14
  end
12
15
  end
data/license.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright, 2020-2024, by Samuel Williams.
3
+ Copyright, 2020-2025, by Samuel Williams.
4
4
  Copyright, 2021, by Olle Jonsson.
5
5
  Copyright, 2022, by Colin Kelley.
6
6
 
data/readme.md CHANGED
@@ -6,33 +6,64 @@ Provides a cache middleware for `Async::HTTP` clients and servers.
6
6
 
7
7
  ## Usage
8
8
 
9
- ### Client Side
10
-
11
- ``` ruby
12
- require 'async'
13
- require 'async/http'
14
- require 'async/http/cache'
15
-
16
- endpoint = Async::HTTP::Endpoint.parse("https://www.oriontransfer.co.nz")
17
- client = Async::HTTP::Client.new(endpoint)
18
- cache = Async::HTTP::Cache::General.new(client)
19
-
20
- Async do
21
- 2.times do
22
- response = cache.get("/products/index")
23
- puts response.inspect
24
- # <Async::HTTP::Protocol::HTTP2::Response ...>
25
- # <Async::HTTP::Cache::Response ...>
26
- response.finish
27
- end
28
- ensure
29
- cache.close
30
- end
31
- ```
32
-
33
- ## Vary
34
-
35
- The `vary` header creates a headache for proxy implementations, because it creates a combinatorial explosion of cache keys, even if the content is the same. Try to avoid it unless absolutely necessary.
9
+ Please see the [project documentation](https://socketry.github.io/async-http-cache/) for more details.
10
+
11
+ - [Getting Started](https://socketry.github.io/async-http-cache/guides/getting-started/index) - This guide explains how to get started with `async-http-cache`, a cache middleware for `Async::HTTP` clients and servers.
12
+
13
+ ## Releases
14
+
15
+ Please see the [project releases](https://socketry.github.io/async-http-cache/releases/index) for all releases.
16
+
17
+ ### v0.4.6
18
+
19
+ - Improved documentation and agent context.
20
+
21
+ ### v0.4.5
22
+
23
+ - Modernized gem structure and dependencies.
24
+
25
+ ### v0.4.4
26
+
27
+ - Modernized gem structure and test suite.
28
+ - Added reference to RFC 9111 in documentation.
29
+ - Improved cache-ability checks by moving response validation to `General` class.
30
+
31
+ ### v0.4.3
32
+
33
+ - Improved `Memory` store with configurable limits and pruning intervals.
34
+ - Enhanced cache-control header handling for `no-store` and `private` directives.
35
+ - Fixed spelling of `cacheable?` method (was `cachable?`).
36
+ - Optimized cacheable response code checks using hash table lookup.
37
+ - Added external test suite for validation.
38
+
39
+ ### v0.4.2
40
+
41
+ - Improved memory cache gardener task to be transient with proper annotations.
42
+
43
+ ### v0.4.1
44
+
45
+ - Updated to use `Console.logger` for consistent logging.
46
+ - Modernized gem structure.
47
+
48
+ ### v0.4.0
49
+
50
+ - **Breaking**: Renamed `trailers` to `trailer` for consistency with HTTP specifications.
51
+ - Updated dependency on `async-http`.
52
+
53
+ ### v0.3.0
54
+
55
+ - Updated dependencies to latest versions.
56
+
57
+ ### v0.2.0
58
+
59
+ - Added support for ETag validation with `if-none-match` header handling.
60
+ - Improved streaming response handling with trailing ETag generation.
61
+ - Enhanced trailer support for body digest calculation.
62
+ - Removed support for end-of-life Ruby versions.
63
+
64
+ ### v0.1.5
65
+
66
+ - Fixed handling of responses with `nil` body length to prevent caching errors.
36
67
 
37
68
  ## Contributing
38
69
 
data/releases.md ADDED
@@ -0,0 +1,81 @@
1
+ # Releases
2
+
3
+ ## v0.4.6
4
+
5
+ - Improved documentation and agent context.
6
+
7
+ ## v0.4.5
8
+
9
+ - Modernized gem structure and dependencies.
10
+
11
+ ## v0.4.4
12
+
13
+ - Modernized gem structure and test suite.
14
+ - Added reference to RFC 9111 in documentation.
15
+ - Improved cache-ability checks by moving response validation to `General` class.
16
+
17
+ ## v0.4.3
18
+
19
+ - Improved `Memory` store with configurable limits and pruning intervals.
20
+ - Enhanced cache-control header handling for `no-store` and `private` directives.
21
+ - Fixed spelling of `cacheable?` method (was `cachable?`).
22
+ - Optimized cacheable response code checks using hash table lookup.
23
+ - Added external test suite for validation.
24
+
25
+ ## v0.4.2
26
+
27
+ - Improved memory cache gardener task to be transient with proper annotations.
28
+
29
+ ## v0.4.1
30
+
31
+ - Updated to use `Console.logger` for consistent logging.
32
+ - Modernized gem structure.
33
+
34
+ ## v0.4.0
35
+
36
+ - **Breaking**: Renamed `trailers` to `trailer` for consistency with HTTP specifications.
37
+ - Updated dependency on `async-http`.
38
+
39
+ ## v0.3.0
40
+
41
+ - Updated dependencies to latest versions.
42
+
43
+ ## v0.2.0
44
+
45
+ - Added support for ETag validation with `if-none-match` header handling.
46
+ - Improved streaming response handling with trailing ETag generation.
47
+ - Enhanced trailer support for body digest calculation.
48
+ - Removed support for end-of-life Ruby versions.
49
+
50
+ ## v0.1.5
51
+
52
+ - Fixed handling of responses with `nil` body length to prevent caching errors.
53
+
54
+ ## v0.1.4
55
+
56
+ - Fixed caching behavior for `HEAD` requests to handle empty bodies correctly.
57
+
58
+ ## v0.1.3
59
+
60
+ - Updated dependencies.
61
+
62
+ ## v0.1.2
63
+
64
+ - Improved handling of malformed or missing `cache-control` headers.
65
+
66
+ ## v0.1.1
67
+
68
+ - Added automatic cache pruning with background gardener task.
69
+ - Improved `vary` header handling with better key generation.
70
+ - Enhanced request `cache-control` header checking.
71
+ - Added detailed cache statistics logging.
72
+ - Improved error logging for response failures.
73
+
74
+ ## v0.1.0
75
+
76
+ - Initial release with HTTP caching middleware.
77
+ - Support for `GET` and `HEAD` request caching.
78
+ - In-memory cache store with configurable limits.
79
+ - Vary header support for content negotiation.
80
+ - Cache-control directive compliance.
81
+ - Response validation based on status codes and headers.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-http-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -38,7 +38,7 @@ cert_chain:
38
38
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
39
39
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
40
40
  -----END CERTIFICATE-----
41
- date: 2025-03-04 00:00:00.000000000 Z
41
+ date: 1980-01-02 00:00:00.000000000 Z
42
42
  dependencies:
43
43
  - !ruby/object:Gem::Dependency
44
44
  name: async-http
@@ -58,6 +58,8 @@ executables: []
58
58
  extensions: []
59
59
  extra_rdoc_files: []
60
60
  files:
61
+ - context/getting-started.md
62
+ - context/index.yaml
61
63
  - lib/async/http/cache.rb
62
64
  - lib/async/http/cache/body.rb
63
65
  - lib/async/http/cache/general.rb
@@ -68,10 +70,12 @@ files:
68
70
  - lib/async/http/cache/version.rb
69
71
  - license.md
70
72
  - readme.md
73
+ - releases.md
71
74
  homepage: https://github.com/socketry/async-http-cache
72
75
  licenses:
73
76
  - MIT
74
77
  metadata:
78
+ documentation_uri: https://socketry.github.io/async-http-cache/
75
79
  source_code_uri: https://github.com/socketry/async-http-cache.git
76
80
  rdoc_options: []
77
81
  require_paths:
@@ -80,14 +84,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
80
84
  requirements:
81
85
  - - ">="
82
86
  - !ruby/object:Gem::Version
83
- version: '3.1'
87
+ version: '3.2'
84
88
  required_rubygems_version: !ruby/object:Gem::Requirement
85
89
  requirements:
86
90
  - - ">="
87
91
  - !ruby/object:Gem::Version
88
92
  version: '0'
89
93
  requirements: []
90
- rubygems_version: 3.6.2
94
+ rubygems_version: 3.6.9
91
95
  specification_version: 4
92
96
  summary: Standard-compliant cache for async-http.
93
97
  test_files: []
metadata.gz.sig CHANGED
Binary file