• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / httpunit / 755

14 Feb 2026 07:14PM UTC coverage: 80.526%. Remained the same
755

push

github

hazendaz
[ci] Fix badge

3213 of 4105 branches covered (78.27%)

Branch coverage included in aggregate %.

8245 of 10124 relevant lines covered (81.44%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.49
/src/main/java/com/meterware/httpunit/cookies/CookieJar.java
1
/*
2
 * SPDX-License-Identifier: MIT
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2000-2026 Russell Gold
6
 * Copyright 2021-2000 hazendaz
7
 */
8
package com.meterware.httpunit.cookies;
9

10
import java.io.IOException;
11
import java.io.StreamTokenizer;
12
import java.io.StringReader;
13
import java.net.URL;
14
import java.util.ArrayList;
15
import java.util.Collection;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.Locale;
21

22
/**
23
 * A collection of HTTP cookies, which can interact with cookie and set-cookie header values.
24
 **/
25
public class CookieJar {
26

27
    /** The Constant DEFAULT_HEADER_SIZE. */
28
    private static final int DEFAULT_HEADER_SIZE = 80;
29

30
    /** The cookies. */
31
    private ArrayList _cookies = new ArrayList<>();
1✔
32

33
    /** The global cookies. */
34
    private ArrayList _globalCookies = new ArrayList<>();
1✔
35

36
    /** The press. */
37
    private CookiePress _press;
38

39
    /**
40
     * Creates an empty cookie jar.
41
     */
42
    public CookieJar() {
1✔
43
        _press = new CookiePress(null);
1✔
44
    }
1✔
45

46
    /**
47
     * Creates a cookie jar which is initially populated with cookies parsed from the <code>Set-Cookie</code> and
48
     * <code>Set-Cookie2</code> header fields.
49
     * <p>
50
     * Note that the parsing does not strictly follow the specifications, but attempts to imitate the behavior of
51
     * popular browsers. Specifically, it allows cookie values to contain commas, which the Netscape standard does not
52
     * allow for, but which is required by some servers.
53
     * </p>
54
     *
55
     * @param source
56
     *            the source
57
     */
58
    public CookieJar(CookieSource source) {
1✔
59
        _press = new CookiePress(source.getURL());
1✔
60
        findCookies(source.getHeaderFields("Set-Cookie"), new RFC2109CookieRecipe());
1✔
61
        findCookies(source.getHeaderFields("Set-Cookie2"), new RFC2965CookieRecipe());
1✔
62
    }
1✔
63

64
    /**
65
     * find the cookies in the given Header String array.
66
     *
67
     * @param cookieHeader
68
     *            - the strings to look for cookies
69
     * @param recipe
70
     *            - the recipe to use
71
     */
72
    private void findCookies(String cookieHeader[], CookieRecipe recipe) {
73
        for (String element : cookieHeader) {
1✔
74
            recipe.findCookies(element);
1✔
75
        }
76
    }
1✔
77

78
    /**
79
     * Empties this cookie jar of all contents.
80
     */
81
    public void clear() {
82
        _cookies.clear();
×
83
        _globalCookies.clear();
×
84
    }
×
85

86
    /**
87
     * Defines a cookie to be sent to the server on every request. This bypasses the normal mechanism by which only
88
     * certain cookies are sent based on their host and path.
89
     *
90
     * @param name
91
     *            the name
92
     * @param value
93
     *            the value
94
     *
95
     * @deprecated as of 1.6, use #putCookie
96
     */
97
    @Deprecated
98
    public void addCookie(String name, String value) {
99
        _globalCookies.add(new Cookie(name, value));
×
100
    }
×
101

102
    /**
103
     * Defines a cookie to be sent to the server on every request. This bypasses the normal mechanism by which only
104
     * certain cookies are sent based on their host and path. Values of null will result in the cookie being removed.
105
     * Any other value will leave the cookie unchanged expect for the value.
106
     *
107
     * @param name
108
     *            the name
109
     * @param value
110
     *            the value
111
     */
112
    public void putCookie(String name, String value) {
113
        boolean foundCookie = false;
1✔
114
        for (Iterator iterator = _globalCookies.iterator(); iterator.hasNext();) {
1✔
115
            Cookie cookie = (Cookie) iterator.next();
1✔
116
            if (name.equals(cookie.getName())) {
1✔
117
                foundCookie = true;
1✔
118
                if (value != null) {
1✔
119
                    cookie.setValue(value);
1✔
120
                } else {
121
                    iterator.remove();
1✔
122
                }
123
            }
124
        }
1✔
125

126
        for (Iterator iterator = _cookies.iterator(); iterator.hasNext();) {
1✔
127
            Cookie cookie = (Cookie) iterator.next();
1✔
128
            if (name.equals(cookie.getName())) {
1!
129
                foundCookie = true;
1✔
130
                if (value != null) {
1!
131
                    cookie.setValue(value);
1✔
132
                } else {
133
                    iterator.remove();
×
134
                }
135
            }
136
        }
1✔
137

138
        // only add it if it does not already exist
139
        if (!foundCookie) {
1✔
140
            _globalCookies.add(new Cookie(name, value));
1✔
141
        }
142
    }
1✔
143

144
    /**
145
     * Define a non-global cookie. This cookie can be overwritten by subsequent cookie definitions in http headers. This
146
     * cookie definition requires a domain and path. If a global cookie is defined with the same name, this cookie is
147
     * not added.
148
     *
149
     * @param name
150
     *            the name
151
     * @param value
152
     *            the value
153
     * @param domain
154
     *            the domain
155
     * @param path
156
     *            the path
157
     */
158
    public void putSingleUseCookie(String name, String value, String domain, String path) {
159
        for (Iterator iterator = _globalCookies.iterator(); iterator.hasNext();) {
1!
160
            Cookie cookie = (Cookie) iterator.next();
×
161
            if (name.equals(cookie.getName())) {
×
162
                return;
×
163
            }
164
        }
×
165

166
        for (Iterator iterator = _cookies.iterator(); iterator.hasNext();) {
1!
167
            Cookie cookie = (Cookie) iterator.next();
×
168
            if (name.equals(cookie.getName())) {
×
169
                iterator.remove();
×
170
            }
171
        }
×
172

173
        _cookies.add(new Cookie(name, value, domain, path));
1✔
174
    }
1✔
175

176
    /**
177
     * Returns the name of all the active cookies in this cookie jar.
178
     *
179
     * @return the cookie names
180
     */
181
    public String[] getCookieNames() {
182
        final int numGlobalCookies = _globalCookies.size();
1✔
183
        String[] names = new String[_cookies.size() + numGlobalCookies];
1✔
184
        for (int i = 0; i < numGlobalCookies; i++) {
1✔
185
            names[i] = ((Cookie) _globalCookies.get(i)).getName();
1✔
186
        }
187
        for (int i = numGlobalCookies; i < names.length; i++) {
1✔
188
            names[i] = ((Cookie) _cookies.get(i - numGlobalCookies)).getName();
1✔
189
        }
190
        return names;
1✔
191
    }
192

193
    /**
194
     * Returns a collection containing all of the cookies in this jar.
195
     *
196
     * @return the cookies
197
     */
198
    public Collection getCookies() {
199
        final Collection collection = (Collection) _cookies.clone();
1✔
200
        collection.addAll(_globalCookies);
1✔
201
        return collection;
1✔
202
    }
203

204
    /**
205
     * Returns the value of the specified cookie.
206
     *
207
     * @param name
208
     *            - the name of the cookie to get the value for
209
     *
210
     * @return the value of the cookie
211
     **/
212
    public String getCookieValue(String name) {
213
        Cookie cookie = getCookie(name);
1✔
214
        return cookie == null ? null : cookie.getValue();
1✔
215
    }
216

217
    /**
218
     * Returns the value of the specified cookie.
219
     *
220
     * @param name
221
     *            the name
222
     *
223
     * @return the cookie
224
     */
225
    public Cookie getCookie(String name) {
226
        if (name == null) {
1!
227
            throw new IllegalArgumentException("getCookieValue: no name specified");
×
228
        }
229
        for (Iterator iterator = _cookies.iterator(); iterator.hasNext();) {
1✔
230
            Cookie cookie = (Cookie) iterator.next();
1✔
231
            if (name.equals(cookie.getName())) {
1✔
232
                return cookie;
1✔
233
            }
234
        }
1✔
235
        for (Iterator iterator = _globalCookies.iterator(); iterator.hasNext();) {
1✔
236
            Cookie cookie = (Cookie) iterator.next();
1✔
237
            if (name.equals(cookie.getName())) {
1!
238
                return cookie;
1✔
239
            }
240
        }
×
241
        return null;
1✔
242
    }
243

244
    /**
245
     * Returns the value of the cookie header to be sent to the specified URL. Will return null if no compatible cookie
246
     * is defined.
247
     *
248
     * @param targetURL
249
     *            the target URL
250
     *
251
     * @return the cookie header field
252
     */
253
    public String getCookieHeaderField(URL targetURL) {
254
        if (_cookies.isEmpty() && _globalCookies.isEmpty()) {
1✔
255
            return null;
1✔
256
        }
257
        StringBuilder sb = new StringBuilder(DEFAULT_HEADER_SIZE);
1✔
258
        HashSet restrictedCookies = new HashSet<>();
1✔
259
        for (Iterator i = _cookies.iterator(); i.hasNext();) {
1✔
260
            Cookie cookie = (Cookie) i.next();
1✔
261
            if (!cookie.mayBeSentTo(targetURL)) {
1✔
262
                continue;
1✔
263
            }
264
            restrictedCookies.add(cookie.getName());
1✔
265
            if (sb.length() != 0) {
1✔
266
                sb.append("; ");
1✔
267
            }
268
            sb.append(cookie.getName()).append('=').append(cookie.getValue());
1✔
269
        }
1✔
270
        for (Iterator i = _globalCookies.iterator(); i.hasNext();) {
1✔
271
            Cookie cookie = (Cookie) i.next();
1✔
272
            if (restrictedCookies.contains(cookie.getName())) {
1✔
273
                continue;
1✔
274
            }
275
            if (sb.length() != 0) {
1✔
276
                sb.append("; ");
1✔
277
            }
278
            sb.append(cookie.getName()).append('=').append(cookie.getValue());
1✔
279
        }
1✔
280
        return sb.length() == 0 ? null : sb.toString();
1!
281
    }
282

283
    /**
284
     * Updates the cookies maintained in this cookie jar with those in another cookie jar. Any duplicate cookies in the
285
     * new jar will replace those in this jar.
286
     *
287
     * @param newJar
288
     *            the new jar
289
     */
290
    public void updateCookies(CookieJar newJar) {
291
        for (Iterator i = newJar._cookies.iterator(); i.hasNext();) {
1✔
292
            addUniqueCookie((Cookie) i.next());
1✔
293
        }
294
    }
1✔
295

296
    /**
297
     * Add the cookie to this jar, replacing any previous matching cookie.
298
     *
299
     * @param cookie
300
     *            the cookie
301
     */
302
    void addUniqueCookie(Cookie cookie) {
303
        _cookies.remove(cookie);
1✔
304
        for (Iterator i = _cookies.iterator(); i.hasNext();) {
1✔
305
            Cookie c = (Cookie) i.next();
1✔
306
            if (c.getName().equals(cookie.getName()) && compareDomain(c.getDomain(), cookie.getDomain())) {
1!
307
                if (c.getPath() != null && cookie.getPath() != null && c.getPath().equals(cookie.getPath())) {
1!
308
                    i.remove();
1✔
309
                }
310
            }
311
        }
1✔
312
        _cookies.add(cookie);
1✔
313
    }
1✔
314

315
    /**
316
     * compare the two domains given for "cookie-equality".
317
     *
318
     * @param domain
319
     *            the domain
320
     * @param newDomain
321
     *            the new domain
322
     *
323
     * @return true, if successful
324
     */
325
    private boolean compareDomain(String domain, String newDomain) {
326
        if (domain.charAt(0) == '.' && newDomain.endsWith(domain)
1!
327
                || newDomain.charAt(0) == '.' && domain.endsWith(newDomain)) {
1!
328
            return true;
1✔
329
        }
330

331
        return domain.equals(newDomain);
×
332
    }
333

334
    /**
335
     * base class for the cookie recipies - there are two different implementations of this.
336
     */
337
    abstract class CookieRecipe {
1✔
338

339
        /**
340
         * Extracts cookies from a cookie header. Works in conjunction with a cookie press class, which actually creates
341
         * the cookies and adds them to the jar as appropriate. 1. Parse the header into tokens, separated by ',' and
342
         * ';' (respecting single and double quotes) 2. Process tokens from the end: a. if the token contains an '=' we
343
         * have a name/value pair. Add them to the cookie press, which will decide if it is a cookie name or an
344
         * attribute name. b. if the token is a reserved word, flush the cookie press and continue. c. otherwise, add
345
         * the token to the cookie press, passing along the last character of the previous token.
346
         *
347
         * @param cookieHeader
348
         *            the cookie header
349
         */
350
        void findCookies(String cookieHeader) {
351
            List tokens = getCookieTokens(cookieHeader);
1✔
352

353
            for (int i = tokens.size() - 1; i >= 0; i--) {
1✔
354
                String token = (String) tokens.get(i);
1✔
355

356
                int equalsIndex = getEqualsIndex(token);
1✔
357
                if (equalsIndex != -1) {
1✔
358
                    _press.addTokenWithEqualsSign(this, token, equalsIndex);
1✔
359
                } else if (isCookieReservedWord(token)) {
1!
360
                    _press.clear();
×
361
                } else {
362
                    _press.addToken(token, lastCharOf(i == 0 ? "" : (String) tokens.get(i - 1)));
1!
363
                }
364
            }
365
        }
1✔
366

367
        /**
368
         * Last char of.
369
         *
370
         * @param string
371
         *            the string
372
         *
373
         * @return the char
374
         */
375
        private char lastCharOf(String string) {
376
            return string.isEmpty() ? ' ' : string.charAt(string.length() - 1);
1!
377
        }
378

379
        /**
380
         * Returns the index (if any) of the equals sign separating a cookie name from the its value. Equals signs at
381
         * the end of the token are ignored in this calculation, since they may be part of a Base64-encoded value.
382
         *
383
         * @param token
384
         *            the token
385
         *
386
         * @return the equals index
387
         */
388
        private int getEqualsIndex(String token) {
389
            if (!token.endsWith("==")) {
1✔
390
                return token.indexOf('=');
1✔
391
            }
392
            return getEqualsIndex(token.substring(0, token.length() - 2));
1✔
393
        }
394

395
        /**
396
         * Tokenizes a cookie header and returns the tokens in a <code>List</code>. handles the broken syntax for
397
         * expires= fields ...
398
         *
399
         * @param cookieHeader
400
         *            - the header to read
401
         *
402
         * @return a List of cookieTokens as name=value pairs
403
         **/
404
        private List getCookieTokens(String cookieHeader) {
405
            StringReader sr = new StringReader(cookieHeader);
1✔
406
            StreamTokenizer st = new StreamTokenizer(sr);
1✔
407
            List tokens = new ArrayList<>();
1✔
408

409
            // clear syntax tables of the StreamTokenizer
410
            st.resetSyntax();
1✔
411

412
            // set all characters as word characters
413
            st.wordChars(0, Character.MAX_VALUE);
1✔
414

415
            // set up characters for quoting
416
            st.quoteChar('"'); // double quotes
1✔
417
            st.quoteChar('\''); // single quotes
1✔
418

419
            // set up characters to separate tokens
420
            st.whitespaceChars(59, 59); // semicolon
1✔
421
            // and here we run into trouble ...
422
            // see http://www.mnot.net/blog/2006/10/27/cookie_fun
423
            // ... Notice something about the above? It uses a comma inside of
424
            // the date,
425
            // without quoting the value. This makes it difficult for generic
426
            // processors to handle the Set-Cookie header.
427
            st.whitespaceChars(44, 44); // comma
1✔
428

429
            try {
430
                while (st.nextToken() != StreamTokenizer.TT_EOF) {
1✔
431
                    String tokenContent = st.sval;
1✔
432
                    // fix expires comma delimiter token problem
433
                    if (tokenContent.toLowerCase(Locale.ENGLISH).startsWith("expires=")
1✔
434
                            && st.nextToken() != StreamTokenizer.TT_EOF) {
1!
435
                        tokenContent += "," + st.sval;
1✔
436
                    } // if // if
437
                    tokenContent = tokenContent.trim();
1✔
438
                    tokens.add(tokenContent);
1✔
439
                }
1✔
440
            } catch (IOException ioe) {
×
441
                // this will never happen with a StringReader
442
            }
1✔
443
            sr.close();
1✔
444
            return tokens;
1✔
445
        }
446

447
        /**
448
         * Checks if is cookie attribute.
449
         *
450
         * @param stringLowercase
451
         *            the string lowercase
452
         *
453
         * @return true, if is cookie attribute
454
         */
455
        abstract protected boolean isCookieAttribute(String stringLowercase);
456

457
        /**
458
         * Checks if is cookie reserved word.
459
         *
460
         * @param token
461
         *            the token
462
         *
463
         * @return true, if is cookie reserved word
464
         */
465
        abstract protected boolean isCookieReservedWord(String token);
466

467
    }
468

469
    /**
470
     * cookie Factory - creates cookies for URL s.
471
     */
472
    class CookiePress {
473

474
        /** The value. */
475
        // the current value
476
        private StringBuilder _value = new StringBuilder();
1✔
477

478
        /** The attributes. */
479
        private HashMap _attributes = new HashMap<>();
1✔
480

481
        /** The source URL. */
482
        private URL _sourceURL;
483

484
        /**
485
         * create a cookie press for the given URL.
486
         *
487
         * @param sourceURL
488
         *            the source URL
489
         */
490
        public CookiePress(URL sourceURL) {
1✔
491
            _sourceURL = sourceURL;
1✔
492
        }
1✔
493

494
        /**
495
         * clear the attributes and the cookie value.
496
         */
497
        void clear() {
498
            _value.setLength(0);
×
499
            _attributes.clear();
×
500
        }
×
501

502
        /**
503
         * add the token content.
504
         *
505
         * @param token
506
         *            the token
507
         * @param lastChar
508
         *            the last char
509
         */
510
        void addToken(String token, char lastChar) {
511
            _value.insert(0, token);
1✔
512
            if (lastChar != '=') {
1!
513
                _value.insert(0, ',');
1✔
514
            }
515
        }
1✔
516

517
        /**
518
         * add from a token.
519
         *
520
         * @param recipe
521
         *            - the recipe to use
522
         * @param token
523
         *            - the token to use
524
         * @param equalsIndex
525
         *            - the position of the equal sign
526
         */
527
        void addTokenWithEqualsSign(CookieRecipe recipe, String token, int equalsIndex) {
528
            final String name = token.substring(0, equalsIndex).trim();
1✔
529
            final String value = token.substring(equalsIndex + 1).trim();
1✔
530
            _value.insert(0, value);
1✔
531
            final String fvalue = _value.toString();
1✔
532
            if (recipe.isCookieAttribute(name.toLowerCase(Locale.ENGLISH))) {
1✔
533
                _attributes.put(name.toLowerCase(Locale.ENGLISH), value);
1✔
534
            } else {
535
                addCookieIfValid(new Cookie(name, fvalue, _attributes));
1✔
536
                _attributes.clear();
1✔
537
            }
538
            _value.setLength(0);
1✔
539
        }
1✔
540

541
        /**
542
         * add the given cookie if it is valid.
543
         *
544
         * @param cookie
545
         *            the cookie
546
         */
547
        private void addCookieIfValid(Cookie cookie) {
548
            if (acceptCookie(cookie)) {
1✔
549
                addUniqueCookie(cookie);
1✔
550
            }
551
        }
1✔
552

553
        /**
554
         * accept the given cookie.
555
         *
556
         * @param cookie
557
         *            the cookie
558
         *
559
         * @return true, if successful
560
         */
561
        private boolean acceptCookie(Cookie cookie) {
562
            if (cookie.getPath() == null) {
1✔
563
                cookie.setPath(getParentPath(_sourceURL.getPath()));
1✔
564
            } else {
565
                int status = getPathAttributeStatus(cookie.getPath(), _sourceURL.getPath());
1✔
566
                if (status != CookieListener.ACCEPTED) {
1✔
567
                    reportCookieRejected(status, cookie.getPath(), cookie.getName());
1✔
568
                    return false;
1✔
569
                }
570
            }
571

572
            if (cookie.getDomain() == null || !CookieProperties.isDomainMatchingStrict()
1✔
573
                    && cookie.getDomain().equalsIgnoreCase(_sourceURL.getHost())) {
1✔
574
                cookie.setDomain(_sourceURL.getHost());
1✔
575
            } else {
576
                int status = getDomainAttributeStatus(cookie, _sourceURL.getHost());
1✔
577
                if (status != CookieListener.ACCEPTED) {
1✔
578
                    reportCookieRejected(status, cookie.getDomain(), cookie.getName());
1✔
579
                    return false;
1✔
580
                }
581
            }
582

583
            return true;
1✔
584
        }
585

586
        /**
587
         * Gets the parent path.
588
         *
589
         * @param path
590
         *            the path
591
         *
592
         * @return the parent path
593
         */
594
        private String getParentPath(String path) {
595
            int rightmostSlashIndex = path.lastIndexOf('/');
1✔
596
            return rightmostSlashIndex < 0 ? "/" : path.substring(0, rightmostSlashIndex);
1✔
597
        }
598

599
        /**
600
         * Gets the path attribute status.
601
         *
602
         * @param pathAttribute
603
         *            the path attribute
604
         * @param sourcePath
605
         *            the source path
606
         *
607
         * @return the path attribute status
608
         */
609
        private int getPathAttributeStatus(String pathAttribute, String sourcePath) {
610
            if (!CookieProperties.isPathMatchingStrict() || sourcePath.isEmpty()
1✔
611
                    || sourcePath.startsWith(pathAttribute)) {
1✔
612
                return CookieListener.ACCEPTED;
1✔
613
            }
614
            return CookieListener.PATH_NOT_PREFIX;
1✔
615
        }
616

617
        /**
618
         * get the domainAttribute Status for the given cookie with the given sourceHost.
619
         *
620
         * @param cookie
621
         *            - the cookie to use
622
         * @param sourceHost
623
         *            the source host
624
         *
625
         * @return the domain attribute status
626
         *
627
         * @see http://wp.netscape.com/newsref/std/cookie_spec.html
628
         */
629
        private int getDomainAttributeStatus(Cookie cookie, String sourceHost) {
630
            String domainAttribute = cookie.getDomain();
1✔
631
            // patch according to [ 1476380 ] Cookies incorrectly rejected
632
            // despite valid domain
633
            if (domainAttribute.equals(sourceHost)) {
1✔
634
                return CookieListener.ACCEPTED;
1✔
635
            }
636
            if (!domainAttribute.startsWith(".")) {
1✔
637
                domainAttribute = '.' + domainAttribute;
1✔
638
            }
639

640
            if (domainAttribute.lastIndexOf('.') == 0) {
1✔
641
                return CookieListener.DOMAIN_ONE_DOT;
1✔
642
            }
643
            if (!sourceHost.endsWith(domainAttribute)) {
1✔
644
                return CookieListener.DOMAIN_NOT_SOURCE_SUFFIX;
1✔
645
            }
646
            if (CookieProperties.isDomainMatchingStrict()
1✔
647
                    && sourceHost.lastIndexOf(domainAttribute) > sourceHost.indexOf('.')) {
1✔
648
                return CookieListener.DOMAIN_TOO_MANY_LEVELS;
1✔
649
            }
650
            // modified for Bugreport 2825872 Cookie domains not stored correctly - ID: 2825872
651
            // http://sourceforge.net/tracker/?func=detail&aid=2825872&group_id=6550&atid=106550
652
            cookie.setDomain(domainAttribute);
1✔
653
            return CookieListener.ACCEPTED;
1✔
654
        }
655

656
        /**
657
         * Report cookie rejected.
658
         *
659
         * @param reason
660
         *            the reason
661
         * @param attribute
662
         *            the attribute
663
         * @param source
664
         *            the source
665
         *
666
         * @return true, if successful
667
         */
668
        private boolean reportCookieRejected(int reason, String attribute, String source) {
669
            CookieProperties.reportCookieRejected(reason, attribute, source);
1✔
670
            return false;
1✔
671
        }
672

673
    }
674

675
    /**
676
     * Parses cookies according to <a href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a> <br />
677
     * These cookies come from the <code>Set-Cookie:</code> header
678
     **/
679
    class RFC2109CookieRecipe extends CookieRecipe {
1✔
680

681
        /**
682
         * check whether the given lower case String is a cookie attribute
683
         *
684
         * @param stringLowercase
685
         *            - the string to check
686
         *
687
         * @return true - if the string is the name of a valid cookie attribute
688
         */
689
        @Override
690
        protected boolean isCookieAttribute(String stringLowercase) {
691
            return stringLowercase.equals("path") || stringLowercase.equals("domain")
1✔
692
                    || stringLowercase.equals("expires") || stringLowercase.equals("comment")
1!
693
                    || stringLowercase.equals("max-age") || stringLowercase.equals("version");
1!
694
        }
695

696
        @Override
697
        protected boolean isCookieReservedWord(String token) {
698
            return token.equalsIgnoreCase("secure");
1✔
699
        }
700
    }
701

702
    /**
703
     * Parses cookies according to <a href="http://www.ietf.org/rfc/rfc2965.txt">RFC 2965</a> <br />
704
     * These cookies come from the <code>Set-Cookie2:</code> header
705
     **/
706
    class RFC2965CookieRecipe extends CookieRecipe {
1✔
707

708
        @Override
709
        protected boolean isCookieAttribute(String stringLowercase) {
710
            return stringLowercase.equals("path") || stringLowercase.equals("domain")
×
711
                    || stringLowercase.equals("comment") || stringLowercase.equals("commenturl")
×
712
                    || stringLowercase.equals("max-age") || stringLowercase.equals("version")
×
713
                    || stringLowercase.equals("$version") || stringLowercase.equals("port");
×
714
        }
715

716
        @Override
717
        protected boolean isCookieReservedWord(String token) {
718
            return token.equalsIgnoreCase("discard") || token.equalsIgnoreCase("secure");
×
719
        }
720
    }
721

722
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc