• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/cookie/RFC2965DomainAttributeHandler.java $
3  * $Revision: 653041 $
4  * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
5  *
6  * ====================================================================
7  * Licensed to the Apache Software Foundation (ASF) under one
8  * or more contributor license agreements.  See the NOTICE file
9  * distributed with this work for additional information
10  * regarding copyright ownership.  The ASF licenses this file
11  * to you under the Apache License, Version 2.0 (the
12  * "License"); you may not use this file except in compliance
13  * with the License.  You may obtain a copy of the License at
14  *
15  *   http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing,
18  * software distributed under the License is distributed on an
19  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20  * KIND, either express or implied.  See the License for the
21  * specific language governing permissions and limitations
22  * under the License.
23  * ====================================================================
24  *
25  * This software consists of voluntary contributions made by many
26  * individuals on behalf of the Apache Software Foundation.  For more
27  * information on the Apache Software Foundation, please see
28  * <http://www.apache.org/>.
29  *
30  */
31 
32 package org.apache.http.impl.cookie;
33 
34 import java.util.Locale;
35 
36 import org.apache.http.cookie.ClientCookie;
37 import org.apache.http.cookie.Cookie;
38 import org.apache.http.cookie.CookieAttributeHandler;
39 import org.apache.http.cookie.CookieOrigin;
40 import org.apache.http.cookie.MalformedCookieException;
41 import org.apache.http.cookie.SetCookie;
42 
43 /**
44  * <tt>"Domain"</tt> cookie attribute handler for RFC 2965 cookie spec.
45  *
46  * @author jain.samit@gmail.com (Samit Jain)
47  *
48  * @since 3.1
49  */
50 public class RFC2965DomainAttributeHandler implements CookieAttributeHandler {
51 
RFC2965DomainAttributeHandler()52     public RFC2965DomainAttributeHandler() {
53         super();
54     }
55 
56     /**
57      * Parse cookie domain attribute.
58      */
parse(final SetCookie cookie, String domain)59     public void parse(final SetCookie cookie, String domain)
60             throws MalformedCookieException {
61         if (cookie == null) {
62             throw new IllegalArgumentException("Cookie may not be null");
63         }
64         if (domain == null) {
65             throw new MalformedCookieException(
66                     "Missing value for domain attribute");
67         }
68         if (domain.trim().length() == 0) {
69             throw new MalformedCookieException(
70                     "Blank value for domain attribute");
71         }
72         domain = domain.toLowerCase(Locale.ENGLISH);
73         if (!domain.startsWith(".")) {
74             // Per RFC 2965 section 3.2.2
75             // "... If an explicitly specified value does not start with
76             // a dot, the user agent supplies a leading dot ..."
77             // That effectively implies that the domain attribute
78             // MAY NOT be an IP address of a host name
79             domain = '.' + domain;
80         }
81         cookie.setDomain(domain);
82     }
83 
84     /**
85      * Performs domain-match as defined by the RFC2965.
86      * <p>
87      * Host A's name domain-matches host B's if
88      * <ol>
89      *   <ul>their host name strings string-compare equal; or</ul>
90      *   <ul>A is a HDN string and has the form NB, where N is a non-empty
91      *       name string, B has the form .B', and B' is a HDN string.  (So,
92      *       x.y.com domain-matches .Y.com but not Y.com.)</ul>
93      * </ol>
94      *
95      * @param host host name where cookie is received from or being sent to.
96      * @param domain The cookie domain attribute.
97      * @return true if the specified host matches the given domain.
98      */
domainMatch(String host, String domain)99     public boolean domainMatch(String host, String domain) {
100         boolean match = host.equals(domain)
101                         || (domain.startsWith(".") && host.endsWith(domain));
102 
103         return match;
104     }
105 
106     /**
107      * Validate cookie domain attribute.
108      */
validate(final Cookie cookie, final CookieOrigin origin)109     public void validate(final Cookie cookie, final CookieOrigin origin)
110             throws MalformedCookieException {
111         if (cookie == null) {
112             throw new IllegalArgumentException("Cookie may not be null");
113         }
114         if (origin == null) {
115             throw new IllegalArgumentException("Cookie origin may not be null");
116         }
117         String host = origin.getHost().toLowerCase(Locale.ENGLISH);
118         if (cookie.getDomain() == null) {
119             throw new MalformedCookieException("Invalid cookie state: " +
120                                                "domain not specified");
121         }
122         String cookieDomain = cookie.getDomain().toLowerCase(Locale.ENGLISH);
123 
124         if (cookie instanceof ClientCookie
125                 && ((ClientCookie) cookie).containsAttribute(ClientCookie.DOMAIN_ATTR)) {
126             // Domain attribute must start with a dot
127             if (!cookieDomain.startsWith(".")) {
128                 throw new MalformedCookieException("Domain attribute \"" +
129                     cookie.getDomain() + "\" violates RFC 2109: domain must start with a dot");
130             }
131 
132             // Domain attribute must contain at least one embedded dot,
133             // or the value must be equal to .local.
134             int dotIndex = cookieDomain.indexOf('.', 1);
135             if (((dotIndex < 0) || (dotIndex == cookieDomain.length() - 1))
136                 && (!cookieDomain.equals(".local"))) {
137                 throw new MalformedCookieException(
138                         "Domain attribute \"" + cookie.getDomain()
139                         + "\" violates RFC 2965: the value contains no embedded dots "
140                         + "and the value is not .local");
141             }
142 
143             // The effective host name must domain-match domain attribute.
144             if (!domainMatch(host, cookieDomain)) {
145                 throw new MalformedCookieException(
146                         "Domain attribute \"" + cookie.getDomain()
147                         + "\" violates RFC 2965: effective host name does not "
148                         + "domain-match domain attribute.");
149             }
150 
151             // effective host name minus domain must not contain any dots
152             String effectiveHostWithoutDomain = host.substring(
153                     0, host.length() - cookieDomain.length());
154             if (effectiveHostWithoutDomain.indexOf('.') != -1) {
155                 throw new MalformedCookieException("Domain attribute \""
156                                                    + cookie.getDomain() + "\" violates RFC 2965: "
157                                                    + "effective host minus domain may not contain any dots");
158             }
159         } else {
160             // Domain was not specified in header. In this case, domain must
161             // string match request host (case-insensitive).
162             if (!cookie.getDomain().equals(host)) {
163                 throw new MalformedCookieException("Illegal domain attribute: \""
164                                                    + cookie.getDomain() + "\"."
165                                                    + "Domain of origin: \""
166                                                    + host + "\"");
167             }
168         }
169     }
170 
171     /**
172      * Match cookie domain attribute.
173      */
match(final Cookie cookie, final CookieOrigin origin)174     public boolean match(final Cookie cookie, final CookieOrigin origin) {
175         if (cookie == null) {
176             throw new IllegalArgumentException("Cookie may not be null");
177         }
178         if (origin == null) {
179             throw new IllegalArgumentException("Cookie origin may not be null");
180         }
181         String host = origin.getHost().toLowerCase(Locale.ENGLISH);
182         String cookieDomain = cookie.getDomain();
183 
184         // The effective host name MUST domain-match the Domain
185         // attribute of the cookie.
186         if (!domainMatch(host, cookieDomain)) {
187             return false;
188         }
189         // effective host name minus domain must not contain any dots
190         String effectiveHostWithoutDomain = host.substring(
191                 0, host.length() - cookieDomain.length());
192         return effectiveHostWithoutDomain.indexOf('.') == -1;
193     }
194 
195 }