17
17
import java .time .Instant ;
18
18
import java .util .ArrayList ;
19
19
import java .util .Collection ;
20
- import java .util .Collections ;
21
20
import java .util .HashMap ;
22
21
import java .util .Iterator ;
23
22
import java .util .List ;
24
23
import java .util .Locale ;
25
24
import java .util .Map ;
26
25
import java .util .Objects ;
26
+ import java .util .concurrent .locks .ReadWriteLock ;
27
+ import java .util .concurrent .locks .ReentrantReadWriteLock ;
27
28
import java .util .function .Predicate ;
28
29
29
30
import org .eclipse .jetty .util .NanoTime ;
30
31
import org .eclipse .jetty .util .StringUtil ;
31
- import org .eclipse .jetty .util .thread .AutoLock ;
32
32
33
33
/**
34
34
* <p>A container for {@link HttpCookie}s.</p>
@@ -51,20 +51,20 @@ public interface HttpCookieStore
51
51
* @param cookie the cookie to add
52
52
* @return whether the cookie has been added
53
53
*/
54
- public boolean add (URI uri , HttpCookie cookie );
54
+ boolean add (URI uri , HttpCookie cookie );
55
55
56
56
/**
57
57
* @return all the cookies
58
58
*/
59
- public List <HttpCookie > all ();
59
+ List <HttpCookie > all ();
60
60
61
61
/**
62
62
* <p>Returns the cookies that match the given {@code URI}.</p>
63
63
*
64
64
* @param uri the {@code URI} to match against
65
65
* @return a list of cookies that match the given {@code URI}
66
66
*/
67
- public List <HttpCookie > match (URI uri );
67
+ List <HttpCookie > match (URI uri );
68
68
69
69
/**
70
70
* <p>Removes the cookie associated with the given {@code URI}.</p>
@@ -73,19 +73,19 @@ public interface HttpCookieStore
73
73
* @param cookie the cookie to remove
74
74
* @return whether the cookie has been removed
75
75
*/
76
- public boolean remove (URI uri , HttpCookie cookie );
76
+ boolean remove (URI uri , HttpCookie cookie );
77
77
78
78
/**
79
79
* <p>Removes all the cookies from this store.</p>
80
80
*
81
81
* @return whether the store modified by this call
82
82
*/
83
- public boolean clear ();
83
+ boolean clear ();
84
84
85
85
/**
86
86
* <p>An implementation of {@link HttpCookieStore} that does not store any cookie.</p>
87
87
*/
88
- public static class Empty implements HttpCookieStore
88
+ class Empty implements HttpCookieStore
89
89
{
90
90
@ Override
91
91
public boolean add (URI uri , HttpCookie cookie )
@@ -121,9 +121,9 @@ public boolean clear()
121
121
/**
122
122
* <p>A default implementation of {@link HttpCookieStore}.</p>
123
123
*/
124
- public static class Default implements HttpCookieStore
124
+ class Default implements HttpCookieStore
125
125
{
126
- private final AutoLock lock = new AutoLock ();
126
+ private final ReadWriteLock lock = new ReentrantReadWriteLock ();
127
127
private final Map <String , List <StoredHttpCookie >> cookies = new HashMap <>();
128
128
129
129
@ Override
@@ -143,7 +143,8 @@ public boolean add(URI uri, HttpCookie cookie)
143
143
// This facilitates the matching algorithm.
144
144
boolean [] added = new boolean [1 ];
145
145
StoredHttpCookie storedCookie = new StoredHttpCookie (cookie , uri , resolvedDomain , resolvedPath );
146
- try (AutoLock ignored = lock .lock ())
146
+ lock .writeLock ().lock ();
147
+ try
147
148
{
148
149
String key = resolvedDomain .toLowerCase (Locale .ENGLISH );
149
150
cookies .compute (key , (k , v ) ->
@@ -164,9 +165,12 @@ public boolean add(URI uri, HttpCookie cookie)
164
165
v .add (storedCookie );
165
166
return v ;
166
167
});
168
+ return added [0 ];
169
+ }
170
+ finally
171
+ {
172
+ lock .writeLock ().unlock ();
167
173
}
168
-
169
- return added [0 ];
170
174
}
171
175
172
176
private String resolveDomain (URI uri , HttpCookie cookie )
@@ -260,14 +264,19 @@ protected boolean allowDomain(String domain)
260
264
@ Override
261
265
public List <HttpCookie > all ()
262
266
{
263
- try (AutoLock ignored = lock .lock ())
267
+ lock .readLock ().lock ();
268
+ try
264
269
{
265
270
return cookies .values ().stream ()
266
271
.flatMap (Collection ::stream )
267
272
.filter (Predicate .not (StoredHttpCookie ::isExpired ))
268
273
.map (HttpCookie .class ::cast )
269
274
.toList ();
270
275
}
276
+ finally
277
+ {
278
+ lock .readLock ().unlock ();
279
+ }
271
280
}
272
281
273
282
@ Override
@@ -283,8 +292,10 @@ public List<HttpCookie> match(URI uri)
283
292
284
293
boolean secure = HttpScheme .isSecure (uri .getScheme ());
285
294
286
- List <HttpCookie > result = new ArrayList <>();
287
- try (AutoLock ignored = lock .lock ())
295
+ List <HttpCookie > result = null ;
296
+ Map <String , List <StoredHttpCookie >> expired = null ;
297
+ lock .readLock ().lock ();
298
+ try
288
299
{
289
300
// Given the way cookies are stored in the Map, the matching
290
301
// algorithm starts with the URI domain and iterates chopping
@@ -300,37 +311,68 @@ public List<HttpCookie> match(URI uri)
300
311
while (domain != null )
301
312
{
302
313
List <StoredHttpCookie > stored = cookies .get (domain );
303
- Iterator <StoredHttpCookie > iterator = stored == null ? Collections .emptyIterator () : stored .iterator ();
304
- while (iterator .hasNext ())
314
+ if (stored != null )
305
315
{
306
- StoredHttpCookie cookie = iterator .next ();
307
-
308
- // Check and remove expired cookies.
309
- if (cookie .isExpired ())
316
+ for (StoredHttpCookie cookie : stored )
310
317
{
311
- iterator .remove ();
312
- continue ;
313
- }
318
+ // Check for expired cookies.
319
+ if (cookie .isExpired ())
320
+ {
321
+ if (expired == null )
322
+ expired = new HashMap <>();
323
+ expired .computeIfAbsent (domain , k -> new ArrayList <>()).add (cookie );
324
+ continue ;
325
+ }
314
326
315
- // Check whether the cookie is secure.
316
- if (cookie .isSecure () && !secure )
317
- continue ;
327
+ // Match whether the cookie is secure.
328
+ if (cookie .isSecure () && !secure )
329
+ continue ;
318
330
319
- // Match the domain.
320
- if (!domainMatches (uriDomain , cookie .domain , cookie .getWrapped ().getDomain ()))
321
- continue ;
331
+ // Match the domain.
332
+ if (!domainMatches (uriDomain , cookie .domain , cookie .getWrapped ().getDomain ()))
333
+ continue ;
322
334
323
- // Match the path.
324
- if (!pathMatches (path , cookie .path ))
325
- continue ;
335
+ // Match the path.
336
+ if (!pathMatches (path , cookie .path ))
337
+ continue ;
326
338
327
- result .add (cookie );
339
+ if (result == null )
340
+ result = new ArrayList <>();
341
+ result .add (cookie );
342
+ }
328
343
}
329
344
domain = parentDomain (domain );
330
345
}
331
346
}
347
+ finally
348
+ {
349
+ lock .readLock ().unlock ();
350
+ }
332
351
333
- return result ;
352
+ if (expired != null )
353
+ {
354
+ lock .writeLock ().lock ();
355
+ try
356
+ {
357
+ for (Map .Entry <String , List <StoredHttpCookie >> entry : expired .entrySet ())
358
+ {
359
+ String domain = entry .getKey ();
360
+ List <StoredHttpCookie > stored = cookies .get (domain );
361
+ if (stored != null )
362
+ {
363
+ stored .removeAll (entry .getValue ());
364
+ if (stored .isEmpty ())
365
+ cookies .remove (domain );
366
+ }
367
+ }
368
+ }
369
+ finally
370
+ {
371
+ lock .writeLock ().unlock ();
372
+ }
373
+ }
374
+
375
+ return result == null ? List .of () : result ;
334
376
}
335
377
336
378
private static boolean domainMatches (String uriDomain , String domain , String cookieDomain )
@@ -380,7 +422,8 @@ public boolean remove(URI uri, HttpCookie cookie)
380
422
String resolvedPath = resolvePath (uri , cookie );
381
423
382
424
boolean [] removed = new boolean [1 ];
383
- try (AutoLock ignored = lock .lock ())
425
+ lock .writeLock ().lock ();
426
+ try
384
427
{
385
428
String domain = uriDomain .toLowerCase (Locale .ENGLISH );
386
429
while (domain != null )
@@ -411,8 +454,12 @@ public boolean remove(URI uri, HttpCookie cookie)
411
454
});
412
455
domain = parentDomain (domain );
413
456
}
457
+ return removed [0 ];
458
+ }
459
+ finally
460
+ {
461
+ lock .writeLock ().unlock ();
414
462
}
415
- return removed [0 ];
416
463
}
417
464
418
465
private String parentDomain (String domain )
@@ -431,13 +478,18 @@ private String parentDomain(String domain)
431
478
@ Override
432
479
public boolean clear ()
433
480
{
434
- try (AutoLock ignored = lock .lock ())
481
+ lock .writeLock ().lock ();
482
+ try
435
483
{
436
484
if (cookies .isEmpty ())
437
485
return false ;
438
486
cookies .clear ();
439
487
return true ;
440
488
}
489
+ finally
490
+ {
491
+ lock .writeLock ().unlock ();
492
+ }
441
493
}
442
494
443
495
private static class StoredHttpCookie extends HttpCookie .Wrapper
0 commit comments