Skip to content

Commit 1be5aff

Browse files
committed
Better CookieJar & CacheStore
1 parent 891f1a4 commit 1be5aff

43 files changed

Lines changed: 769 additions & 896 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/TurboHTTP.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ namespace TurboHTTP
167167
public static TurboHTTP.ITurboHttpClientBuilder UseResponse(this TurboHTTP.ITurboHttpClientBuilder builder, System.Func<System.Net.Http.HttpRequestMessage, System.Net.Http.HttpResponseMessage, System.Net.Http.HttpResponseMessage> transform) { }
168168
public static TurboHTTP.ITurboHttpClientBuilder WithCache(this TurboHTTP.ITurboHttpClientBuilder builder, System.Action<TurboHTTP.CacheOptions>? configure = null) { }
169169
public static TurboHTTP.ITurboHttpClientBuilder WithCache(this TurboHTTP.ITurboHttpClientBuilder builder, TurboHTTP.Protocol.Caching.ICacheStore store, System.Action<TurboHTTP.CacheOptions>? configure = null) { }
170-
public static TurboHTTP.ITurboHttpClientBuilder WithCookies(this TurboHTTP.ITurboHttpClientBuilder builder, TurboHTTP.Protocol.Cookies.ICookieJar? jar = null) { }
170+
public static TurboHTTP.ITurboHttpClientBuilder WithCookies(this TurboHTTP.ITurboHttpClientBuilder builder) { }
171+
public static TurboHTTP.ITurboHttpClientBuilder WithCookies(this TurboHTTP.ITurboHttpClientBuilder builder, TurboHTTP.Protocol.Cookies.ICookieStore store) { }
171172
public static TurboHTTP.ITurboHttpClientBuilder WithDecompression(this TurboHTTP.ITurboHttpClientBuilder builder, bool enabled = true) { }
172173
public static TurboHTTP.ITurboHttpClientBuilder WithExpectContinue(this TurboHTTP.ITurboHttpClientBuilder builder, System.Action<TurboHTTP.Expect100Options>? configure = null) { }
173174
public static TurboHTTP.ITurboHttpClientBuilder WithRedirect(this TurboHTTP.ITurboHttpClientBuilder builder, System.Action<TurboHTTP.RedirectOptions>? configure = null) { }
@@ -237,6 +238,14 @@ namespace TurboHTTP.Diagnostics
237238
}
238239
namespace TurboHTTP.Protocol.Caching
239240
{
241+
public sealed class CacheBody : System.IDisposable
242+
{
243+
public bool IsEmpty { get; }
244+
public int Length { get; }
245+
public System.ReadOnlyMemory<byte> Memory { get; }
246+
public System.ReadOnlySpan<byte> Span { get; }
247+
public void Dispose() { }
248+
}
240249
public sealed class CacheControl : System.IEquatable<TurboHTTP.Protocol.Caching.CacheControl>
241250
{
242251
public CacheControl() { }
@@ -257,6 +266,43 @@ namespace TurboHTTP.Protocol.Caching
257266
public bool Public { get; init; }
258267
public System.TimeSpan? SMaxAge { get; init; }
259268
}
269+
public sealed class CacheControlStoreEntry : System.IEquatable<TurboHTTP.Protocol.Caching.CacheControlStoreEntry>
270+
{
271+
public CacheControlStoreEntry() { }
272+
public bool Immutable { get; init; }
273+
public System.TimeSpan? MaxAge { get; init; }
274+
public System.TimeSpan? MaxStale { get; init; }
275+
public System.TimeSpan? MinFresh { get; init; }
276+
public bool MustRevalidate { get; init; }
277+
public bool MustUnderstand { get; init; }
278+
public bool NoCache { get; init; }
279+
public string[] NoCacheFields { get; init; }
280+
public bool NoStore { get; init; }
281+
public bool NoTransform { get; init; }
282+
public bool OnlyIfCached { get; init; }
283+
public bool Private { get; init; }
284+
public string[] PrivateFields { get; init; }
285+
public bool ProxyRevalidate { get; init; }
286+
public bool Public { get; init; }
287+
public System.TimeSpan? SMaxAge { get; init; }
288+
}
289+
public sealed class CacheStoreEntry : System.IDisposable
290+
{
291+
public CacheStoreEntry() { }
292+
public int? AgeSeconds { get; init; }
293+
public required TurboHTTP.Protocol.Caching.CacheBody Body { get; init; }
294+
public TurboHTTP.Protocol.Caching.CacheControlStoreEntry? CacheControl { get; init; }
295+
public System.DateTimeOffset? Date { get; init; }
296+
public string? ETag { get; init; }
297+
public System.DateTimeOffset? Expires { get; init; }
298+
public System.DateTimeOffset? LastModified { get; init; }
299+
public required System.DateTimeOffset RequestTime { get; init; }
300+
public required System.Net.Http.HttpResponseMessage Response { get; init; }
301+
public required System.DateTimeOffset ResponseTime { get; init; }
302+
public string[] VaryHeaderNames { get; init; }
303+
public System.Collections.Generic.Dictionary<string, string?> VaryRequestValues { get; init; }
304+
public void Dispose() { }
305+
}
260306
public interface ICacheEntry : System.IDisposable
261307
{
262308
int? AgeSeconds { get; }
@@ -272,18 +318,43 @@ namespace TurboHTTP.Protocol.Caching
272318
System.Collections.Generic.IReadOnlyList<string> VaryHeaderNames { get; }
273319
System.Collections.Generic.IReadOnlyDictionary<string, string?> VaryRequestValues { get; }
274320
}
275-
public interface ICacheStore
321+
public interface ICacheStore : System.IDisposable
276322
{
277-
TurboHTTP.Protocol.Caching.ICacheEntry? Get(System.Net.Http.HttpRequestMessage request);
278-
void Invalidate(System.Uri uri);
279-
void Put(System.Net.Http.HttpRequestMessage request, System.Net.Http.HttpResponseMessage response, System.Buffers.IMemoryOwner<byte> bodyOwner, int bodyLength, System.DateTimeOffset requestTime, System.DateTimeOffset responseTime);
323+
void Clear();
324+
bool Remove(string key);
325+
void Set(string key, TurboHTTP.Protocol.Caching.CacheStoreEntry entry);
326+
bool TryGet(string key, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out TurboHTTP.Protocol.Caching.CacheStoreEntry? entry);
280327
}
281328
}
282329
namespace TurboHTTP.Protocol.Cookies
283330
{
284-
public interface ICookieJar
331+
public sealed class CookieStoreEntry : System.IEquatable<TurboHTTP.Protocol.Cookies.CookieStoreEntry>
332+
{
333+
public CookieStoreEntry(string Name, string Value, string Domain, string Path, System.DateTimeOffset? ExpiresAt, bool Secure, bool HttpOnly, TurboHTTP.Protocol.Cookies.SameSitePolicy SameSite, bool IsHostOnly, System.DateTimeOffset CreatedAt) { }
334+
public System.DateTimeOffset CreatedAt { get; init; }
335+
public string Domain { get; init; }
336+
public System.DateTimeOffset? ExpiresAt { get; init; }
337+
public bool HttpOnly { get; init; }
338+
public bool IsHostOnly { get; init; }
339+
public string Name { get; init; }
340+
public string Path { get; init; }
341+
public TurboHTTP.Protocol.Cookies.SameSitePolicy SameSite { get; init; }
342+
public bool Secure { get; init; }
343+
public string Value { get; init; }
344+
}
345+
public interface ICookieStore
346+
{
347+
int Count { get; }
348+
void Add(TurboHTTP.Protocol.Cookies.CookieStoreEntry entry);
349+
void Clear();
350+
System.Collections.Generic.IReadOnlyList<TurboHTTP.Protocol.Cookies.CookieStoreEntry> GetAll();
351+
void Remove(string name, string domain, string path);
352+
}
353+
public enum SameSitePolicy
285354
{
286-
void AddCookiesToRequest(System.Uri requestUri, ref System.Net.Http.HttpRequestMessage request);
287-
void ProcessResponse(System.Uri requestUri, System.Net.Http.HttpResponseMessage response);
355+
Unspecified = 0,
356+
Strict = 1,
357+
Lax = 2,
358+
None = 3,
288359
}
289360
}

src/TurboHTTP.AcceptanceTests/H10/CacheSpec.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace TurboHTTP.AcceptanceTests.H10;
99
public sealed class CacheSpec : AcceptanceTestBase
1010
{
1111
private async Task<HttpResponseMessage> SendAsync(ResponseMap map, HttpRequestMessage request,
12-
CacheStore store, CachePolicy? policy = null)
12+
Cache store, CachePolicy? policy = null)
1313
{
1414
var cache = BidiFlow.FromGraph(new CacheBidiStage(store, policy));
1515
var fake = ResponseMapFake.Create(map);
@@ -69,7 +69,7 @@ public async Task Cache_should_serve_max_age_response_from_cache()
6969
return CacheableResponse($"max-age-body-{callCount}", "max-age=3600");
7070
});
7171

72-
var store = new CacheStore(CachePolicy.Default);
72+
var store = new Cache(CachePolicy.Default);
7373

7474
var response1 = await SendAsync(map,
7575
new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/max-age/3600"), store);
@@ -97,7 +97,7 @@ public async Task Cache_should_force_revalidation_with_no_cache()
9797
return CacheableResponse($"no-cache-body-{callCount}", "no-cache");
9898
});
9999

100-
var store = new CacheStore(CachePolicy.Default);
100+
var store = new Cache(CachePolicy.Default);
101101

102102
var response1 = await SendAsync(map,
103103
new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/no-cache"), store);
@@ -119,7 +119,7 @@ public async Task Cache_should_never_cache_no_store_response()
119119
var map = new ResponseMap()
120120
.On("/cache/no-store", _ => CacheableResponse("no-store-resource", "no-store"));
121121

122-
var store = new CacheStore(CachePolicy.Default);
122+
var store = new Cache(CachePolicy.Default);
123123

124124
var response1 = await SendAsync(map,
125125
new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/no-store"), store);
@@ -143,7 +143,7 @@ public async Task Cache_should_send_if_none_match_for_etag_revalidation()
143143
.On("/cache/etag/test1", _ => CacheableResponse("etag-resource-test1", "max-age=3600",
144144
etag: "etag-test1"));
145145

146-
var store = new CacheStore(CachePolicy.Default);
146+
var store = new Cache(CachePolicy.Default);
147147

148148
var response1 = await SendAsync(map,
149149
new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/etag/test1"), store);
@@ -167,7 +167,7 @@ public async Task Cache_should_send_if_modified_since_for_last_modified_revalida
167167
.On("/cache/last-modified/doc1", _ => CacheableResponse("last-modified-resource-doc1",
168168
"max-age=3600", lastModified: DateTimeOffset.UtcNow.AddHours(-1)));
169169

170-
var store = new CacheStore(CachePolicy.Default);
170+
var store = new Cache(CachePolicy.Default);
171171

172172
var response1 = await SendAsync(map,
173173
new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/last-modified/doc1"), store);
@@ -195,7 +195,7 @@ public async Task Cache_should_produce_different_entries_for_vary_header_values(
195195
vary: "Accept-Language");
196196
});
197197

198-
var store = new CacheStore(CachePolicy.Default);
198+
var store = new Cache(CachePolicy.Default);
199199

200200
var request1 = new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/vary/Accept-Language");
201201
request1.Headers.TryAddWithoutValidation("Accept-Language", "en");
@@ -249,7 +249,7 @@ public async Task Cache_should_force_revalidation_when_must_revalidate()
249249
etag: "mr-etag-2");
250250
});
251251

252-
var store = new CacheStore(CachePolicy.Default);
252+
var store = new Cache(CachePolicy.Default);
253253

254254
var response1 = await SendAsync(map,
255255
new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/must-revalidate"), store);
@@ -277,7 +277,7 @@ public async Task Cache_should_respect_s_maxage_by_shared_cache()
277277
});
278278

279279
var policy = new CachePolicy { SharedCache = true };
280-
var store = new CacheStore(policy);
280+
var store = new Cache(policy);
281281

282282
var response1 = await SendAsync(map,
283283
new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/s-maxage/3600"), store, policy);
@@ -305,7 +305,7 @@ public async Task Cache_should_enable_caching_with_expires_header()
305305
expires: DateTimeOffset.UtcNow.AddHours(1));
306306
});
307307

308-
var store = new CacheStore(CachePolicy.Default);
308+
var store = new Cache(CachePolicy.Default);
309309

310310
var response1 = await SendAsync(map,
311311
new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/expires"), store);
@@ -332,7 +332,7 @@ public async Task Cache_should_cache_private_response_by_private_cache()
332332
return CacheableResponse($"private-body-{callCount}", "private, max-age=3600");
333333
});
334334

335-
var store = new CacheStore(CachePolicy.Default);
335+
var store = new Cache(CachePolicy.Default);
336336

337337
var response1 = await SendAsync(map,
338338
new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/private"), store);
@@ -360,7 +360,7 @@ public async Task Cache_must_not_cache_private_response_by_shared_cache()
360360
});
361361

362362
var policy = new CachePolicy { SharedCache = true };
363-
var store = new CacheStore(policy);
363+
var store = new Cache(policy);
364364

365365
var response1 = await SendAsync(map,
366366
new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/private"), store, policy);

src/TurboHTTP.AcceptanceTests/H10/FeatureInteractionSpec.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ private async Task<HttpResponseMessage> SendCookieRedirectAsync(ResponseMap map,
5353
}
5454

5555
private async Task<HttpResponseMessage> SendCacheAsync(ResponseMap map, HttpRequestMessage request,
56-
CacheStore store, CachePolicy? policy = null)
56+
Cache store, CachePolicy? policy = null)
5757
{
5858
var cache = BidiFlow.FromGraph(new CacheBidiStage(store, policy));
5959
var fake = ResponseMapFake.Create(map);
@@ -103,7 +103,7 @@ private async Task<HttpResponseMessage> SendCookieRetryAsync(ResponseMap map, Ht
103103
}
104104

105105
private async Task<HttpResponseMessage> SendCacheCookieAsync(ResponseMap map, HttpRequestMessage request,
106-
CacheStore store, CookieJar jar)
106+
Cache store, CookieJar jar)
107107
{
108108
var cache = BidiFlow.FromGraph(new CacheBidiStage(store));
109109
var cookie = BidiFlow.FromGraph(new CookieBidiStage(jar));
@@ -120,7 +120,7 @@ private async Task<HttpResponseMessage> SendCacheCookieAsync(ResponseMap map, Ht
120120
}
121121

122122
private async Task<HttpResponseMessage> SendCacheRetryAsync(ResponseMap map, HttpRequestMessage request,
123-
CacheStore store, RetryPolicy retryPolicy)
123+
Cache store, RetryPolicy retryPolicy)
124124
{
125125
var cache = BidiFlow.FromGraph(new CacheBidiStage(store));
126126
var retry = BidiFlow.FromGraph(new RetryBidiStage(retryPolicy));
@@ -178,7 +178,7 @@ public async Task FeatureInteraction_should_serve_compressed_response_from_cache
178178
return r;
179179
});
180180

181-
var store = new CacheStore(CachePolicy.Default);
181+
var store = new Cache(CachePolicy.Default);
182182

183183
var res1 = await SendCacheAsync(map,
184184
new HttpRequestMessage(HttpMethod.Get, "http://localhost/interaction/cache-gzip"), store);
@@ -294,7 +294,7 @@ public async Task FeatureInteraction_should_separate_cache_entries_with_vary_hea
294294
return r;
295295
});
296296

297-
var store = new CacheStore(CachePolicy.Default);
297+
var store = new Cache(CachePolicy.Default);
298298

299299
var req1 = new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/vary/Accept-Language");
300300
req1.Headers.Add("Accept-Language", "en");
@@ -364,7 +364,7 @@ public async Task FeatureInteraction_should_bypass_retry_logic_on_cache_hit()
364364
return r;
365365
});
366366

367-
var store = new CacheStore(CachePolicy.Default);
367+
var store = new Cache(CachePolicy.Default);
368368

369369
var res1 = await SendCacheRetryAsync(map,
370370
new HttpRequestMessage(HttpMethod.Get, "http://localhost/cache/max-age/3600"),

0 commit comments

Comments
 (0)