View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.http.impl.cookie;
28  
29  import java.util.Locale;
30  
31  import org.apache.http.annotation.Immutable;
32  import org.apache.http.conn.util.InetAddressUtils;
33  import org.apache.http.cookie.ClientCookie;
34  import org.apache.http.cookie.CommonCookieAttributeHandler;
35  import org.apache.http.cookie.Cookie;
36  import org.apache.http.cookie.CookieOrigin;
37  import org.apache.http.cookie.CookieRestrictionViolationException;
38  import org.apache.http.cookie.MalformedCookieException;
39  import org.apache.http.cookie.SetCookie;
40  import org.apache.http.util.Args;
41  import org.apache.http.util.TextUtils;
42  
43  /**
44   *
45   * @since 4.0
46   */
47  @Immutable
48  public class BasicDomainHandler implements CommonCookieAttributeHandler {
49  
50      public BasicDomainHandler() {
51          super();
52      }
53  
54      @Override
55      public void parse(final SetCookie cookie, final String value)
56              throws MalformedCookieException {
57          Args.notNull(cookie, "Cookie");
58          if (TextUtils.isBlank(value)) {
59              throw new MalformedCookieException("Blank or null value for domain attribute");
60          }
61          // Ignore domain attributes ending with '.' per RFC 6265, 4.1.2.3
62          if (value.endsWith(".")) {
63              return;
64          }
65          String domain = value;
66          if (domain.startsWith(".")) {
67              domain = domain.substring(1);
68          }
69          domain = domain.toLowerCase(Locale.ROOT);
70          cookie.setDomain(domain);
71      }
72  
73      @Override
74      public void validate(final Cookie cookie, final CookieOrigin origin)
75              throws MalformedCookieException {
76          Args.notNull(cookie, "Cookie");
77          Args.notNull(origin, "Cookie origin");
78          // Validate the cookies domain attribute.  NOTE:  Domains without
79          // any dots are allowed to support hosts on private LANs that don't
80          // have DNS names.  Since they have no dots, to domain-match the
81          // request-host and domain must be identical for the cookie to sent
82          // back to the origin-server.
83          final String host = origin.getHost();
84          final String domain = cookie.getDomain();
85          if (domain == null) {
86              throw new CookieRestrictionViolationException("Cookie 'domain' may not be null");
87          }
88          if (!host.equals(domain) && !domainMatch(domain, host)) {
89              throw new CookieRestrictionViolationException(
90                      "Illegal 'domain' attribute \"" + domain + "\". Domain of origin: \"" + host + "\"");
91          }
92      }
93  
94      static boolean domainMatch(final String domain, final String host) {
95          if (InetAddressUtils.isIPv4Address(host) || InetAddressUtils.isIPv6Address(host)) {
96              return false;
97          }
98          final String normalizedDomain = domain.startsWith(".") ? domain.substring(1) : domain;
99          if (host.endsWith(normalizedDomain)) {
100             final int prefix = host.length() - normalizedDomain.length();
101             // Either a full match or a prefix endidng with a '.'
102             if (prefix == 0) {
103                 return true;
104             }
105             if (prefix > 1 && host.charAt(prefix - 1) == '.') {
106                 return true;
107             }
108         }
109         return false;
110     }
111 
112     @Override
113     public boolean match(final Cookie cookie, final CookieOrigin origin) {
114         Args.notNull(cookie, "Cookie");
115         Args.notNull(origin, "Cookie origin");
116         final String host = origin.getHost();
117         String domain = cookie.getDomain();
118         if (domain == null) {
119             return false;
120         }
121         if (domain.startsWith(".")) {
122             domain = domain.substring(1);
123         }
124         domain = domain.toLowerCase(Locale.ROOT);
125         if (host.equals(domain)) {
126             return true;
127         }
128         if (cookie instanceof ClientCookie) {
129             if (((ClientCookie) cookie).containsAttribute(ClientCookie.DOMAIN_ATTR)) {
130                 return domainMatch(domain, host);
131             }
132         }
133         return false;
134     }
135 
136     @Override
137     public String getAttributeName() {
138         return ClientCookie.DOMAIN_ATTR;
139     }
140 
141 }