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

hazendaz / httpunit / 646

06 Dec 2025 08:11PM UTC coverage: 80.526% (+0.02%) from 80.509%
646

push

github

hazendaz
Cleanup array usage

3213 of 4105 branches covered (78.27%)

Branch coverage included in aggregate %.

4 of 4 new or added lines in 3 files covered. (100.0%)

532 existing lines in 26 files now uncovered.

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
 * MIT License
3
 *
4
 * Copyright 2011-2025 Russell Gold
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
9
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions
12
 * of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
15
 * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
17
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
 * DEALINGS IN THE SOFTWARE.
19
 */
20
package com.meterware.httpunit.cookies;
21

22
import java.io.IOException;
23
import java.io.StreamTokenizer;
24
import java.io.StringReader;
25
import java.net.URL;
26
import java.util.ArrayList;
27
import java.util.Collection;
28
import java.util.HashMap;
29
import java.util.HashSet;
30
import java.util.Iterator;
31
import java.util.List;
32
import java.util.Locale;
33

34
/**
35
 * A collection of HTTP cookies, which can interact with cookie and set-cookie header values.
36
 **/
37
public class CookieJar {
38

39
    /** The Constant DEFAULT_HEADER_SIZE. */
40
    private static final int DEFAULT_HEADER_SIZE = 80;
41

42
    /** The cookies. */
43
    private ArrayList _cookies = new ArrayList<>();
1✔
44

45
    /** The global cookies. */
46
    private ArrayList _globalCookies = new ArrayList<>();
1✔
47

48
    /** The press. */
49
    private CookiePress _press;
50

51
    /**
52
     * Creates an empty cookie jar.
53
     */
54
    public CookieJar() {
1✔
55
        _press = new CookiePress(null);
1✔
56
    }
1✔
57

58
    /**
59
     * Creates a cookie jar which is initially populated with cookies parsed from the <code>Set-Cookie</code> and
60
     * <code>Set-Cookie2</code> header fields.
61
     * <p>
62
     * Note that the parsing does not strictly follow the specifications, but attempts to imitate the behavior of
63
     * popular browsers. Specifically, it allows cookie values to contain commas, which the Netscape standard does not
64
     * allow for, but which is required by some servers.
65
     * </p>
66
     *
67
     * @param source
68
     *            the source
69
     */
70
    public CookieJar(CookieSource source) {
1✔
71
        _press = new CookiePress(source.getURL());
1✔
72
        findCookies(source.getHeaderFields("Set-Cookie"), new RFC2109CookieRecipe());
1✔
73
        findCookies(source.getHeaderFields("Set-Cookie2"), new RFC2965CookieRecipe());
1✔
74
    }
1✔
75

76
    /**
77
     * find the cookies in the given Header String array.
78
     *
79
     * @param cookieHeader
80
     *            - the strings to look for cookies
81
     * @param recipe
82
     *            - the recipe to use
83
     */
84
    private void findCookies(String cookieHeader[], CookieRecipe recipe) {
85
        for (String element : cookieHeader) {
1✔
86
            recipe.findCookies(element);
1✔
87
        }
88
    }
1✔
89

90
    /**
91
     * Empties this cookie jar of all contents.
92
     */
93
    public void clear() {
94
        _cookies.clear();
×
95
        _globalCookies.clear();
×
UNCOV
96
    }
×
97

98
    /**
99
     * Defines a cookie to be sent to the server on every request. This bypasses the normal mechanism by which only
100
     * certain cookies are sent based on their host and path.
101
     *
102
     * @param name
103
     *            the name
104
     * @param value
105
     *            the value
106
     *
107
     * @deprecated as of 1.6, use #putCookie
108
     */
109
    @Deprecated
110
    public void addCookie(String name, String value) {
111
        _globalCookies.add(new Cookie(name, value));
×
UNCOV
112
    }
×
113

114
    /**
115
     * Defines a cookie to be sent to the server on every request. This bypasses the normal mechanism by which only
116
     * certain cookies are sent based on their host and path. Values of null will result in the cookie being removed.
117
     * Any other value will leave the cookie unchanged expect for the value.
118
     *
119
     * @param name
120
     *            the name
121
     * @param value
122
     *            the value
123
     */
124
    public void putCookie(String name, String value) {
125
        boolean foundCookie = false;
1✔
126
        for (Iterator iterator = _globalCookies.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();
1✔
134
                }
135
            }
136
        }
1✔
137

138
        for (Iterator iterator = _cookies.iterator(); iterator.hasNext();) {
1✔
139
            Cookie cookie = (Cookie) iterator.next();
1✔
140
            if (name.equals(cookie.getName())) {
1!
141
                foundCookie = true;
1✔
142
                if (value != null) {
1!
143
                    cookie.setValue(value);
1✔
144
                } else {
UNCOV
145
                    iterator.remove();
×
146
                }
147
            }
148
        }
1✔
149

150
        // only add it if it does not already exist
151
        if (!foundCookie) {
1✔
152
            _globalCookies.add(new Cookie(name, value));
1✔
153
        }
154
    }
1✔
155

156
    /**
157
     * Define a non-global cookie. This cookie can be overwritten by subsequent cookie definitions in http headers. This
158
     * cookie definition requires a domain and path. If a global cookie is defined with the same name, this cookie is
159
     * not added.
160
     *
161
     * @param name
162
     *            the name
163
     * @param value
164
     *            the value
165
     * @param domain
166
     *            the domain
167
     * @param path
168
     *            the path
169
     */
170
    public void putSingleUseCookie(String name, String value, String domain, String path) {
171
        for (Iterator iterator = _globalCookies.iterator(); iterator.hasNext();) {
1!
172
            Cookie cookie = (Cookie) iterator.next();
×
173
            if (name.equals(cookie.getName())) {
×
UNCOV
174
                return;
×
175
            }
UNCOV
176
        }
×
177

178
        for (Iterator iterator = _cookies.iterator(); iterator.hasNext();) {
1!
179
            Cookie cookie = (Cookie) iterator.next();
×
180
            if (name.equals(cookie.getName())) {
×
UNCOV
181
                iterator.remove();
×
182
            }
UNCOV
183
        }
×
184

185
        _cookies.add(new Cookie(name, value, domain, path));
1✔
186
    }
1✔
187

188
    /**
189
     * Returns the name of all the active cookies in this cookie jar.
190
     *
191
     * @return the cookie names
192
     */
193
    public String[] getCookieNames() {
194
        final int numGlobalCookies = _globalCookies.size();
1✔
195
        String[] names = new String[_cookies.size() + numGlobalCookies];
1✔
196
        for (int i = 0; i < numGlobalCookies; i++) {
1✔
197
            names[i] = ((Cookie) _globalCookies.get(i)).getName();
1✔
198
        }
199
        for (int i = numGlobalCookies; i < names.length; i++) {
1✔
200
            names[i] = ((Cookie) _cookies.get(i - numGlobalCookies)).getName();
1✔
201
        }
202
        return names;
1✔
203
    }
204

205
    /**
206
     * Returns a collection containing all of the cookies in this jar.
207
     *
208
     * @return the cookies
209
     */
210
    public Collection getCookies() {
211
        final Collection collection = (Collection) _cookies.clone();
1✔
212
        collection.addAll(_globalCookies);
1✔
213
        return collection;
1✔
214
    }
215

216
    /**
217
     * Returns the value of the specified cookie.
218
     *
219
     * @param name
220
     *            - the name of the cookie to get the value for
221
     *
222
     * @return the value of the cookie
223
     **/
224
    public String getCookieValue(String name) {
225
        Cookie cookie = getCookie(name);
1✔
226
        return cookie == null ? null : cookie.getValue();
1✔
227
    }
228

229
    /**
230
     * Returns the value of the specified cookie.
231
     *
232
     * @param name
233
     *            the name
234
     *
235
     * @return the cookie
236
     */
237
    public Cookie getCookie(String name) {
238
        if (name == null) {
1!
UNCOV
239
            throw new IllegalArgumentException("getCookieValue: no name specified");
×
240
        }
241
        for (Iterator iterator = _cookies.iterator(); iterator.hasNext();) {
1✔
242
            Cookie cookie = (Cookie) iterator.next();
1✔
243
            if (name.equals(cookie.getName())) {
1✔
244
                return cookie;
1✔
245
            }
246
        }
1✔
247
        for (Iterator iterator = _globalCookies.iterator(); iterator.hasNext();) {
1✔
248
            Cookie cookie = (Cookie) iterator.next();
1✔
249
            if (name.equals(cookie.getName())) {
1!
250
                return cookie;
1✔
251
            }
UNCOV
252
        }
×
253
        return null;
1✔
254
    }
255

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

295
    /**
296
     * Updates the cookies maintained in this cookie jar with those in another cookie jar. Any duplicate cookies in the
297
     * new jar will replace those in this jar.
298
     *
299
     * @param newJar
300
     *            the new jar
301
     */
302
    public void updateCookies(CookieJar newJar) {
303
        for (Iterator i = newJar._cookies.iterator(); i.hasNext();) {
1✔
304
            addUniqueCookie((Cookie) i.next());
1✔
305
        }
306
    }
1✔
307

308
    /**
309
     * Add the cookie to this jar, replacing any previous matching cookie.
310
     *
311
     * @param cookie
312
     *            the cookie
313
     */
314
    void addUniqueCookie(Cookie cookie) {
315
        _cookies.remove(cookie);
1✔
316
        for (Iterator i = _cookies.iterator(); i.hasNext();) {
1✔
317
            Cookie c = (Cookie) i.next();
1✔
318
            if (c.getName().equals(cookie.getName()) && compareDomain(c.getDomain(), cookie.getDomain())) {
1!
319
                if (c.getPath() != null && cookie.getPath() != null && c.getPath().equals(cookie.getPath())) {
1!
320
                    i.remove();
1✔
321
                }
322
            }
323
        }
1✔
324
        _cookies.add(cookie);
1✔
325
    }
1✔
326

327
    /**
328
     * compare the two domains given for "cookie-equality".
329
     *
330
     * @param domain
331
     *            the domain
332
     * @param newDomain
333
     *            the new domain
334
     *
335
     * @return true, if successful
336
     */
337
    private boolean compareDomain(String domain, String newDomain) {
338
        if (domain.charAt(0) == '.' && newDomain.endsWith(domain)
1!
339
                || newDomain.charAt(0) == '.' && domain.endsWith(newDomain)) {
1!
340
            return true;
1✔
341
        }
342

UNCOV
343
        return domain.equals(newDomain);
×
344
    }
345

346
    /**
347
     * base class for the cookie recipies - there are two different implementations of this.
348
     */
349
    abstract class CookieRecipe {
1✔
350

351
        /**
352
         * Extracts cookies from a cookie header. Works in conjunction with a cookie press class, which actually creates
353
         * the cookies and adds them to the jar as appropriate. 1. Parse the header into tokens, separated by ',' and
354
         * ';' (respecting single and double quotes) 2. Process tokens from the end: a. if the token contains an '=' we
355
         * have a name/value pair. Add them to the cookie press, which will decide if it is a cookie name or an
356
         * attribute name. b. if the token is a reserved word, flush the cookie press and continue. c. otherwise, add
357
         * the token to the cookie press, passing along the last character of the previous token.
358
         *
359
         * @param cookieHeader
360
         *            the cookie header
361
         */
362
        void findCookies(String cookieHeader) {
363
            List tokens = getCookieTokens(cookieHeader);
1✔
364

365
            for (int i = tokens.size() - 1; i >= 0; i--) {
1✔
366
                String token = (String) tokens.get(i);
1✔
367

368
                int equalsIndex = getEqualsIndex(token);
1✔
369
                if (equalsIndex != -1) {
1✔
370
                    _press.addTokenWithEqualsSign(this, token, equalsIndex);
1✔
371
                } else if (isCookieReservedWord(token)) {
1!
UNCOV
372
                    _press.clear();
×
373
                } else {
374
                    _press.addToken(token, lastCharOf(i == 0 ? "" : (String) tokens.get(i - 1)));
1!
375
                }
376
            }
377
        }
1✔
378

379
        /**
380
         * Last char of.
381
         *
382
         * @param string
383
         *            the string
384
         *
385
         * @return the char
386
         */
387
        private char lastCharOf(String string) {
388
            return string.isEmpty() ? ' ' : string.charAt(string.length() - 1);
1!
389
        }
390

391
        /**
392
         * Returns the index (if any) of the equals sign separating a cookie name from the its value. Equals signs at
393
         * the end of the token are ignored in this calculation, since they may be part of a Base64-encoded value.
394
         *
395
         * @param token
396
         *            the token
397
         *
398
         * @return the equals index
399
         */
400
        private int getEqualsIndex(String token) {
401
            if (!token.endsWith("==")) {
1✔
402
                return token.indexOf('=');
1✔
403
            }
404
            return getEqualsIndex(token.substring(0, token.length() - 2));
1✔
405
        }
406

407
        /**
408
         * Tokenizes a cookie header and returns the tokens in a <code>List</code>. handles the broken syntax for
409
         * expires= fields ...
410
         *
411
         * @param cookieHeader
412
         *            - the header to read
413
         *
414
         * @return a List of cookieTokens as name=value pairs
415
         **/
416
        private List getCookieTokens(String cookieHeader) {
417
            StringReader sr = new StringReader(cookieHeader);
1✔
418
            StreamTokenizer st = new StreamTokenizer(sr);
1✔
419
            List tokens = new ArrayList<>();
1✔
420

421
            // clear syntax tables of the StreamTokenizer
422
            st.resetSyntax();
1✔
423

424
            // set all characters as word characters
425
            st.wordChars(0, Character.MAX_VALUE);
1✔
426

427
            // set up characters for quoting
428
            st.quoteChar('"'); // double quotes
1✔
429
            st.quoteChar('\''); // single quotes
1✔
430

431
            // set up characters to separate tokens
432
            st.whitespaceChars(59, 59); // semicolon
1✔
433
            // and here we run into trouble ...
434
            // see http://www.mnot.net/blog/2006/10/27/cookie_fun
435
            // ... Notice something about the above? It uses a comma inside of
436
            // the date,
437
            // without quoting the value. This makes it difficult for generic
438
            // processors to handle the Set-Cookie header.
439
            st.whitespaceChars(44, 44); // comma
1✔
440

441
            try {
442
                while (st.nextToken() != StreamTokenizer.TT_EOF) {
1✔
443
                    String tokenContent = st.sval;
1✔
444
                    // fix expires comma delimiter token problem
445
                    if (tokenContent.toLowerCase(Locale.ENGLISH).startsWith("expires=")
1✔
446
                            && st.nextToken() != StreamTokenizer.TT_EOF) {
1!
447
                        tokenContent += "," + st.sval;
1✔
448
                    } // if // if
449
                    tokenContent = tokenContent.trim();
1✔
450
                    tokens.add(tokenContent);
1✔
451
                }
1✔
UNCOV
452
            } catch (IOException ioe) {
×
453
                // this will never happen with a StringReader
454
            }
1✔
455
            sr.close();
1✔
456
            return tokens;
1✔
457
        }
458

459
        /**
460
         * Checks if is cookie attribute.
461
         *
462
         * @param stringLowercase
463
         *            the string lowercase
464
         *
465
         * @return true, if is cookie attribute
466
         */
467
        abstract protected boolean isCookieAttribute(String stringLowercase);
468

469
        /**
470
         * Checks if is cookie reserved word.
471
         *
472
         * @param token
473
         *            the token
474
         *
475
         * @return true, if is cookie reserved word
476
         */
477
        abstract protected boolean isCookieReservedWord(String token);
478

479
    }
480

481
    /**
482
     * cookie Factory - creates cookies for URL s.
483
     */
484
    class CookiePress {
485

486
        /** The value. */
487
        // the current value
488
        private StringBuilder _value = new StringBuilder();
1✔
489

490
        /** The attributes. */
491
        private HashMap _attributes = new HashMap<>();
1✔
492

493
        /** The source URL. */
494
        private URL _sourceURL;
495

496
        /**
497
         * create a cookie press for the given URL.
498
         *
499
         * @param sourceURL
500
         *            the source URL
501
         */
502
        public CookiePress(URL sourceURL) {
1✔
503
            _sourceURL = sourceURL;
1✔
504
        }
1✔
505

506
        /**
507
         * clear the attributes and the cookie value.
508
         */
509
        void clear() {
510
            _value.setLength(0);
×
UNCOV
511
            _attributes.clear();
×
UNCOV
512
        }
×
513

514
        /**
515
         * add the token content.
516
         *
517
         * @param token
518
         *            the token
519
         * @param lastChar
520
         *            the last char
521
         */
522
        void addToken(String token, char lastChar) {
523
            _value.insert(0, token);
1✔
524
            if (lastChar != '=') {
1!
525
                _value.insert(0, ',');
1✔
526
            }
527
        }
1✔
528

529
        /**
530
         * add from a token.
531
         *
532
         * @param recipe
533
         *            - the recipe to use
534
         * @param token
535
         *            - the token to use
536
         * @param equalsIndex
537
         *            - the position of the equal sign
538
         */
539
        void addTokenWithEqualsSign(CookieRecipe recipe, String token, int equalsIndex) {
540
            final String name = token.substring(0, equalsIndex).trim();
1✔
541
            final String value = token.substring(equalsIndex + 1).trim();
1✔
542
            _value.insert(0, value);
1✔
543
            final String fvalue = _value.toString();
1✔
544
            if (recipe.isCookieAttribute(name.toLowerCase(Locale.ENGLISH))) {
1✔
545
                _attributes.put(name.toLowerCase(Locale.ENGLISH), value);
1✔
546
            } else {
547
                addCookieIfValid(new Cookie(name, fvalue, _attributes));
1✔
548
                _attributes.clear();
1✔
549
            }
550
            _value.setLength(0);
1✔
551
        }
1✔
552

553
        /**
554
         * add the given cookie if it is valid.
555
         *
556
         * @param cookie
557
         *            the cookie
558
         */
559
        private void addCookieIfValid(Cookie cookie) {
560
            if (acceptCookie(cookie)) {
1✔
561
                addUniqueCookie(cookie);
1✔
562
            }
563
        }
1✔
564

565
        /**
566
         * accept the given cookie.
567
         *
568
         * @param cookie
569
         *            the cookie
570
         *
571
         * @return true, if successful
572
         */
573
        private boolean acceptCookie(Cookie cookie) {
574
            if (cookie.getPath() == null) {
1✔
575
                cookie.setPath(getParentPath(_sourceURL.getPath()));
1✔
576
            } else {
577
                int status = getPathAttributeStatus(cookie.getPath(), _sourceURL.getPath());
1✔
578
                if (status != CookieListener.ACCEPTED) {
1✔
579
                    reportCookieRejected(status, cookie.getPath(), cookie.getName());
1✔
580
                    return false;
1✔
581
                }
582
            }
583

584
            if (cookie.getDomain() == null || !CookieProperties.isDomainMatchingStrict()
1✔
585
                    && cookie.getDomain().equalsIgnoreCase(_sourceURL.getHost())) {
1✔
586
                cookie.setDomain(_sourceURL.getHost());
1✔
587
            } else {
588
                int status = getDomainAttributeStatus(cookie, _sourceURL.getHost());
1✔
589
                if (status != CookieListener.ACCEPTED) {
1✔
590
                    reportCookieRejected(status, cookie.getDomain(), cookie.getName());
1✔
591
                    return false;
1✔
592
                }
593
            }
594

595
            return true;
1✔
596
        }
597

598
        /**
599
         * Gets the parent path.
600
         *
601
         * @param path
602
         *            the path
603
         *
604
         * @return the parent path
605
         */
606
        private String getParentPath(String path) {
607
            int rightmostSlashIndex = path.lastIndexOf('/');
1✔
608
            return rightmostSlashIndex < 0 ? "/" : path.substring(0, rightmostSlashIndex);
1✔
609
        }
610

611
        /**
612
         * Gets the path attribute status.
613
         *
614
         * @param pathAttribute
615
         *            the path attribute
616
         * @param sourcePath
617
         *            the source path
618
         *
619
         * @return the path attribute status
620
         */
621
        private int getPathAttributeStatus(String pathAttribute, String sourcePath) {
622
            if (!CookieProperties.isPathMatchingStrict() || sourcePath.isEmpty()
1✔
623
                    || sourcePath.startsWith(pathAttribute)) {
1✔
624
                return CookieListener.ACCEPTED;
1✔
625
            }
626
            return CookieListener.PATH_NOT_PREFIX;
1✔
627
        }
628

629
        /**
630
         * get the domainAttribute Status for the given cookie with the given sourceHost.
631
         *
632
         * @param cookie
633
         *            - the cookie to use
634
         * @param sourceHost
635
         *            the source host
636
         *
637
         * @return the domain attribute status
638
         *
639
         * @see http://wp.netscape.com/newsref/std/cookie_spec.html
640
         */
641
        private int getDomainAttributeStatus(Cookie cookie, String sourceHost) {
642
            String domainAttribute = cookie.getDomain();
1✔
643
            // patch according to [ 1476380 ] Cookies incorrectly rejected
644
            // despite valid domain
645
            if (domainAttribute.equals(sourceHost)) {
1✔
646
                return CookieListener.ACCEPTED;
1✔
647
            }
648
            if (!domainAttribute.startsWith(".")) {
1✔
649
                domainAttribute = '.' + domainAttribute;
1✔
650
            }
651

652
            if (domainAttribute.lastIndexOf('.') == 0) {
1✔
653
                return CookieListener.DOMAIN_ONE_DOT;
1✔
654
            }
655
            if (!sourceHost.endsWith(domainAttribute)) {
1✔
656
                return CookieListener.DOMAIN_NOT_SOURCE_SUFFIX;
1✔
657
            }
658
            if (CookieProperties.isDomainMatchingStrict()
1✔
659
                    && sourceHost.lastIndexOf(domainAttribute) > sourceHost.indexOf('.')) {
1✔
660
                return CookieListener.DOMAIN_TOO_MANY_LEVELS;
1✔
661
            }
662
            // modified for Bugreport 2825872 Cookie domains not stored correctly - ID: 2825872
663
            // http://sourceforge.net/tracker/?func=detail&aid=2825872&group_id=6550&atid=106550
664
            cookie.setDomain(domainAttribute);
1✔
665
            return CookieListener.ACCEPTED;
1✔
666
        }
667

668
        /**
669
         * Report cookie rejected.
670
         *
671
         * @param reason
672
         *            the reason
673
         * @param attribute
674
         *            the attribute
675
         * @param source
676
         *            the source
677
         *
678
         * @return true, if successful
679
         */
680
        private boolean reportCookieRejected(int reason, String attribute, String source) {
681
            CookieProperties.reportCookieRejected(reason, attribute, source);
1✔
682
            return false;
1✔
683
        }
684

685
    }
686

687
    /**
688
     * Parses cookies according to <a href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a> <br />
689
     * These cookies come from the <code>Set-Cookie:</code> header
690
     **/
691
    class RFC2109CookieRecipe extends CookieRecipe {
1✔
692

693
        /**
694
         * check whether the given lower case String is a cookie attribute
695
         *
696
         * @param stringLowercase
697
         *            - the string to check
698
         *
699
         * @return true - if the string is the name of a valid cookie attribute
700
         */
701
        @Override
702
        protected boolean isCookieAttribute(String stringLowercase) {
703
            return stringLowercase.equals("path") || stringLowercase.equals("domain")
1✔
704
                    || stringLowercase.equals("expires") || stringLowercase.equals("comment")
1!
705
                    || stringLowercase.equals("max-age") || stringLowercase.equals("version");
1!
706
        }
707

708
        @Override
709
        protected boolean isCookieReservedWord(String token) {
710
            return token.equalsIgnoreCase("secure");
1✔
711
        }
712
    }
713

714
    /**
715
     * Parses cookies according to <a href="http://www.ietf.org/rfc/rfc2965.txt">RFC 2965</a> <br />
716
     * These cookies come from the <code>Set-Cookie2:</code> header
717
     **/
718
    class RFC2965CookieRecipe extends CookieRecipe {
1✔
719

720
        @Override
721
        protected boolean isCookieAttribute(String stringLowercase) {
722
            return stringLowercase.equals("path") || stringLowercase.equals("domain")
×
723
                    || stringLowercase.equals("comment") || stringLowercase.equals("commenturl")
×
UNCOV
724
                    || stringLowercase.equals("max-age") || stringLowercase.equals("version")
×
UNCOV
725
                    || stringLowercase.equals("$version") || stringLowercase.equals("port");
×
726
        }
727

728
        @Override
729
        protected boolean isCookieReservedWord(String token) {
UNCOV
730
            return token.equalsIgnoreCase("discard") || token.equalsIgnoreCase("secure");
×
731
        }
732
    }
733

734
}
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