View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.httpclient;
16  
17  import static org.htmlunit.BrowserVersionFeatures.HTTP_COOKIE_REMOVE_DOT_FROM_ROOT_DOMAINS;
18  
19  import java.net.InetAddress;
20  import java.net.UnknownHostException;
21  import java.util.Locale;
22  
23  import org.apache.http.cookie.Cookie;
24  import org.apache.http.cookie.CookieOrigin;
25  import org.apache.http.cookie.MalformedCookieException;
26  import org.apache.http.cookie.SetCookie;
27  import org.apache.http.impl.cookie.BasicDomainHandler;
28  import org.apache.http.util.Args;
29  import org.apache.http.util.TextUtils;
30  import org.htmlunit.BrowserVersion;
31  import org.htmlunit.HttpHeader;
32  
33  /**
34   * Customized BasicDomainHandler for HtmlUnit.
35   *
36   * @author Ronald Brill
37   * @author Ahmed Ashour
38   */
39  final class HtmlUnitDomainHandler extends BasicDomainHandler {
40      private final BrowserVersion browserVersion_;
41  
42      HtmlUnitDomainHandler(final BrowserVersion browserVersion) {
43          super();
44          browserVersion_ = browserVersion;
45      }
46  
47      @Override
48      public void parse(final SetCookie cookie, final String value)
49              throws MalformedCookieException {
50          Args.notNull(cookie, HttpHeader.COOKIE);
51          if (TextUtils.isBlank(value)) {
52              throw new MalformedCookieException("Blank or null value for domain attribute");
53          }
54          // Ignore domain attributes ending with '.' per RFC 6265, 4.1.2.3
55          if (value.endsWith(".")) {
56              return;
57          }
58          String domain = value.toLowerCase(Locale.ROOT);
59  
60          final int dotIndex = domain.indexOf('.');
61          if (browserVersion_.hasFeature(HTTP_COOKIE_REMOVE_DOT_FROM_ROOT_DOMAINS)
62                  && dotIndex == 0 && domain.length() > 1 && domain.indexOf('.', 1) == -1) {
63              domain = domain.substring(1);
64          }
65          if (dotIndex > 0) {
66              domain = '.' + domain;
67          }
68  
69          cookie.setDomain(domain);
70      }
71  
72      /**
73       * {@inheritDoc}
74       */
75      @Override
76      public boolean match(final Cookie cookie, final CookieOrigin origin) {
77          String domain = cookie.getDomain();
78          if (domain == null) {
79              return false;
80          }
81  
82          final int dotIndex = domain.indexOf('.');
83          if (dotIndex == 0 && domain.length() > 1 && domain.indexOf('.', 1) == -1) {
84              final String host = origin.getHost();
85              if (browserVersion_.hasFeature(HTTP_COOKIE_REMOVE_DOT_FROM_ROOT_DOMAINS)) {
86                  domain = domain.substring(1);
87              }
88              return host.equalsIgnoreCase(domain);
89          }
90  
91          if (dotIndex == -1
92                  && !HtmlUnitBrowserCompatCookieSpec.LOCAL_FILESYSTEM_DOMAIN.equalsIgnoreCase(domain)) {
93              try {
94                  InetAddress.getByName(domain);
95              }
96              catch (final UnknownHostException e) {
97                  return false;
98              }
99          }
100 
101         return super.match(cookie, origin);
102     }
103 }