1 /*
2 * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/cookie/RFC2109Spec.java,v 1.14 2003/05/26 17:58:03 olegk Exp $
3 * $Revision: 1.14 $
4 * $Date: 2003/05/26 17:58:03 $
5 *
6 * ====================================================================
7 *
8 * The Apache Software License, Version 1.1
9 *
10 * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
11 * reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 *
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 *
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in
22 * the documentation and/or other materials provided with the
23 * distribution.
24 *
25 * 3. The end-user documentation included with the redistribution, if
26 * any, must include the following acknowlegement:
27 * "This product includes software developed by the
28 * Apache Software Foundation (http://www.apache.org/)."
29 * Alternately, this acknowlegement may appear in the software itself,
30 * if and wherever such third-party acknowlegements normally appear.
31 *
32 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
33 * Foundation" must not be used to endorse or promote products derived
34 * from this software without prior written permission. For written
35 * permission, please contact apache@apache.org.
36 *
37 * 5. Products derived from this software may not be called "Apache"
38 * nor may "Apache" appear in their names without prior written
39 * permission of the Apache Group.
40 *
41 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
45 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
48 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
49 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 * ====================================================================
54 *
55 * This software consists of voluntary contributions made by many
56 * individuals on behalf of the Apache Software Foundation. For more
57 * information on the Apache Software Foundation, please see
58 * <http://www.apache.org/>.
59 *
60 * [Additional notices, if required by prior licensing conditions]
61 *
62 */
63
64 package org.apache.commons.httpclient.cookie;
65
66 import org.apache.commons.httpclient.NameValuePair;
67 import org.apache.commons.httpclient.Cookie;
68
69 /***
70 * <p>RFC 2109 specific cookie management functions
71 *
72 * @author B.C. Holmes
73 * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
74 * @author <a href="mailto:dsale@us.britannica.com">Doug Sale</a>
75 * @author Rod Waldhoff
76 * @author dIon Gillard
77 * @author Sean C. Sullivan
78 * @author <a href="mailto:JEvans@Cyveillance.com">John Evans</a>
79 * @author Marc A. Saegesser
80 * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
81 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
82 *
83 * @since 2.0
84 */
85
86 public class RFC2109Spec extends CookieSpecBase {
87
88 /*** Default constructor */
89 public RFC2109Spec() {
90 super();
91 }
92
93
94 /***
95 * Parse RFC 2109 specific cookie attribute and update the corresponsing
96 * {@link Cookie} properties.
97 *
98 * @param attribute {@link NameValuePair} cookie attribute from the
99 * <tt>Set- Cookie</tt>
100 * @param cookie {@link Cookie} to be updated
101 * @throws MalformedCookieException if an exception occurs during parsing
102 */
103 public void parseAttribute(
104 final NameValuePair attribute, final Cookie cookie)
105 throws MalformedCookieException {
106
107 if (attribute == null) {
108 throw new IllegalArgumentException("Attribute may not be null.");
109 }
110 if (cookie == null) {
111 throw new IllegalArgumentException("Cookie may not be null.");
112 }
113 final String paramName = attribute.getName().toLowerCase();
114 final String paramValue = attribute.getValue();
115
116 if (paramName.equals("path")) {
117 if (paramValue == null) {
118 throw new MalformedCookieException(
119 "Missing value for path attribute");
120 }
121 if (paramValue.trim().equals("")) {
122 throw new MalformedCookieException(
123 "Blank value for path attribute");
124 }
125 cookie.setPath(paramValue);
126 cookie.setPathAttributeSpecified(true);
127 }
128 else if (paramName.equals("version")) {
129
130 if (paramValue == null) {
131 throw new MalformedCookieException(
132 "Missing value for version attribute");
133 }
134 try {
135 cookie.setVersion(Integer.parseInt(paramValue));
136 } catch (NumberFormatException e) {
137 throw new MalformedCookieException("Invalid version: "
138 + e.getMessage());
139 }
140
141 } else {
142 super.parseAttribute(attribute, cookie);
143 }
144 }
145
146 /***
147 * Performs RFC 2109 compliant {@link Cookie} validation
148 *
149 * @param host the host from which the {@link Cookie} was received
150 * @param port the port from which the {@link Cookie} was received
151 * @param path the path from which the {@link Cookie} was received
152 * @param secure <tt>true</tt> when the {@link Cookie} was received using a
153 * secure connection
154 * @param cookie The cookie to validate
155 * @throws MalformedCookieException if an exception occurs during
156 * validation
157 */
158 public void validate(String host, int port, String path,
159 boolean secure, final Cookie cookie) throws MalformedCookieException {
160
161 LOG.trace("enter RFC2109Spec.validate(String, int, String, "
162 + "boolean, Cookie)");
163
164 // Perform generic validation
165 super.validate(host, port, path, secure, cookie);
166 // Perform RFC 2109 specific validation
167 if (cookie.isDomainAttributeSpecified()
168 && (!cookie.getDomain().equals(host))) {
169
170 // domain must start with dot
171 if (!cookie.getDomain().startsWith(".")) {
172 throw new MalformedCookieException("Domain attribute \""
173 + cookie.getDomain()
174 + "\" violates RFC 2109: domain must start with a dot");
175 }
176 // domain must have at least one embedded dot
177 int dotIndex = cookie.getDomain().indexOf('.', 1);
178 if (dotIndex < 0 || dotIndex == cookie.getDomain().length() - 1) {
179 throw new MalformedCookieException("Domain attribute \""
180 + cookie.getDomain()
181 + "\" violates RFC 2109: domain must contain an embedded dot");
182 }
183 host = host.toLowerCase();
184 if (host.indexOf('.') >= 0) {
185 if (!host.endsWith(cookie.getDomain())) {
186 throw new MalformedCookieException(
187 "Illegal domain attribute \"" + cookie.getDomain()
188 + "\". Domain of origin: \"" + host + "\"");
189 }
190 // host minus domain may not contain any dots
191 String hostWithoutDomain = host.substring(0, host.length()
192 - cookie.getDomain().length());
193 if (hostWithoutDomain.indexOf('.') != -1) {
194 throw new MalformedCookieException("Domain attribute \""
195 + cookie.getDomain()
196 + "\" violates RFC 2109: host minus domain may not contain any dots");
197 }
198 }
199 }
200 }
201
202
203 /***
204 * Return a name/value string suitable for sending in a <tt>"Cookie"</tt>
205 * header as defined in RFC 2109 for backward compatibility with cookie
206 * version 0
207 * @param name The name.
208 * @param value The value
209 * @param version The cookie version
210 * @return a string suitable for sending in a <tt>"Cookie"</tt> header.
211 */
212
213 private String formatNameValuePair(
214 final String name, final String value, int version) {
215
216 final StringBuffer buffer = new StringBuffer();
217 if (version < 1) {
218 buffer.append(name);
219 buffer.append("=");
220 if (value != null) {
221 buffer.append(value);
222 }
223 } else {
224 buffer.append(name);
225 buffer.append("=\"");
226 if (value != null) {
227 buffer.append(value);
228 }
229 buffer.append("\"");
230 }
231 return buffer.toString();
232 }
233
234 /***
235 * Return a string suitable for sending in a <tt>"Cookie"</tt> header
236 * as defined in RFC 2109 for backward compatibility with cookie version 0
237 * @param cookie a {@link Cookie} to be formatted as string
238 * @param version The version to use.
239 * @return a string suitable for sending in a <tt>"Cookie"</tt> header.
240 */
241 private String formatCookieAsVer(Cookie cookie, int version) {
242 LOG.trace("enter RFC2109Spec.formatCookieAsVer(Cookie)");
243 if (cookie == null) {
244 throw new IllegalArgumentException("Cookie may not be null");
245 }
246 StringBuffer buf = new StringBuffer();
247 buf.append(formatNameValuePair(cookie.getName(),
248 cookie.getValue(), version));
249 if (cookie.getDomain() != null
250 && cookie.isDomainAttributeSpecified()) {
251
252 buf.append("; ");
253 buf.append(formatNameValuePair("$Domain",
254 cookie.getDomain(), version));
255 }
256 if (cookie.getPath() != null && cookie.isPathAttributeSpecified()) {
257 buf.append("; ");
258 buf.append(formatNameValuePair("$Path", cookie.getPath(), version));
259 }
260 return buf.toString();
261 }
262
263
264 /***
265 * Return a string suitable for sending in a <tt>"Cookie"</tt> header as
266 * defined in RFC 2109
267 * @param cookie a {@link Cookie} to be formatted as string
268 * @return a string suitable for sending in a <tt>"Cookie"</tt> header.
269 */
270 public String formatCookie(Cookie cookie) {
271 LOG.trace("enter RFC2109Spec.formatCookie(Cookie)");
272 if (cookie == null) {
273 throw new IllegalArgumentException("Cookie may not be null");
274 }
275 int ver = cookie.getVersion();
276 StringBuffer buffer = new StringBuffer();
277 buffer.append(formatNameValuePair("$Version",
278 Integer.toString(ver), ver));
279 buffer.append("; ");
280 buffer.append(formatCookieAsVer(cookie, ver));
281 return buffer.toString();
282 }
283
284 /***
285 * Create a RFC 2109 compliant <tt>"Cookie"</tt> header value containing all
286 * {@link Cookie}s in <i>cookies</i> suitable for sending in a <tt>"Cookie"
287 * </tt> header
288 * @param cookies an array of {@link Cookie}s to be formatted
289 * @return a string suitable for sending in a Cookie header.
290 */
291 public String formatCookies(Cookie[] cookies) {
292 LOG.trace("enter RFC2109Spec.formatCookieHeader(Cookie[])");
293 int version = Integer.MAX_VALUE;
294 // Pick the lowerest common denominator
295 for (int i = 0; i < cookies.length; i++) {
296 Cookie cookie = cookies[i];
297 if (cookie.getVersion() < version) {
298 version = cookie.getVersion();
299 }
300 }
301 final StringBuffer buffer = new StringBuffer();
302 buffer.append(formatNameValuePair("$Version",
303 Integer.toString(version), version));
304 for (int i = 0; i < cookies.length; i++) {
305 buffer.append("; ");
306 buffer.append(formatCookieAsVer(cookies[i], version));
307 }
308 return buffer.toString();
309 }
310 }
This page was automatically generated by Maven