Open Source Repository

Home /commons-httpclient/commons-httpclient-2.0.2 | Repository Home



org/apache/commons/httpclient/cookie/RFC2109Spec.java
/*
 * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/cookie/RFC2109Spec.java,v 1.14.2.3 2004/06/05 16:32:01 olegk Exp $
 * $Revision: 1.14.2.3 $
 * $Date: 2004/06/05 16:32:01 $
 
 * ====================================================================
 *
 *  Copyright 2002-2004 The Apache Software Foundation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * [Additional notices, if required by prior licensing conditions]
 *
 */

package org.apache.commons.httpclient.cookie;

import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.Cookie;

/**
 <p>RFC 2109 specific cookie management functions
 *
 @author  B.C. Holmes
 @author <a href="mailto:[email protected]">Park, Sung-Gu</a>
 @author <a href="mailto:[email protected]">Doug Sale</a>
 @author Rod Waldhoff
 @author dIon Gillard
 @author Sean C. Sullivan
 @author <a href="mailto:[email protected]">John Evans</a>
 @author Marc A. Saegesser
 @author <a href="mailto:[email protected]">Oleg Kalnichevski</a>
 @author <a href="mailto:[email protected]">Mike Bowler</a>
 
 @since 2.0 
 */

public class RFC2109Spec extends CookieSpecBase {

    /** Default constructor */    
    public RFC2109Spec() {
        super();
    }


    /**
      * Parse RFC 2109 specific cookie attribute and update the corresponsing
      {@link Cookie} properties.
      *
      @param attribute {@link NameValuePair} cookie attribute from the
      <tt>Set- Cookie</tt>
      @param cookie {@link Cookie} to be updated
      @throws MalformedCookieException if an exception occurs during parsing
      */
    public void parseAttribute(
        final NameValuePair attribute, final Cookie cookie)
        throws MalformedCookieException {
          
        if (attribute == null) {
            throw new IllegalArgumentException("Attribute may not be null.");
        }
        if (cookie == null) {
            throw new IllegalArgumentException("Cookie may not be null.");
        }
        final String paramName = attribute.getName().toLowerCase();
        final String paramValue = attribute.getValue();

        if (paramName.equals("path")) {
            if (paramValue == null) {
                throw new MalformedCookieException(
                    "Missing value for path attribute");
            }
            if (paramValue.trim().equals("")) {
                throw new MalformedCookieException(
                    "Blank value for path attribute");
            }
            cookie.setPath(paramValue);
            cookie.setPathAttributeSpecified(true);
        else if (paramName.equals("version")) {

            if (paramValue == null) {
                throw new MalformedCookieException(
                    "Missing value for version attribute");
            }
            try {
               cookie.setVersion(Integer.parseInt(paramValue));
            catch (NumberFormatException e) {
                throw new MalformedCookieException("Invalid version: " 
                    + e.getMessage());
            }

        else {
            super.parseAttribute(attribute, cookie);
        }
    }

    /**
      * Performs RFC 2109 compliant {@link Cookie} validation
      *
      @param host the host from which the {@link Cookie} was received
      @param port the port from which the {@link Cookie} was received
      @param path the path from which the {@link Cookie} was received
      @param secure <tt>true</tt> when the {@link Cookie} was received using a
      * secure connection
      @param cookie The cookie to validate
      @throws MalformedCookieException if an exception occurs during
      * validation
      */
    public void validate(String host, int port, String path, 
        boolean secure, final Cookie cookiethrows MalformedCookieException {
            
        LOG.trace("enter RFC2109Spec.validate(String, int, String, "
            "boolean, Cookie)");
            
        // Perform generic validation
        super.validate(host, port, path, secure, cookie);
        // Perform RFC 2109 specific validation
        
        if (cookie.getName().indexOf(' '!= -1) {
            throw new MalformedCookieException("Cookie name may not contain blanks");
        }
        if (cookie.getName().startsWith("$")) {
            throw new MalformedCookieException("Cookie name may not start with $");
        }
        
        if (cookie.isDomainAttributeSpecified() 
            && (!cookie.getDomain().equals(host))) {
                
            // domain must start with dot
            if (!cookie.getDomain().startsWith(".")) {
                throw new MalformedCookieException("Domain attribute \"" 
                    + cookie.getDomain() 
                    "\" violates RFC 2109: domain must start with a dot");
            }
            // domain must have at least one embedded dot
            int dotIndex = cookie.getDomain().indexOf('.'1);
            if (dotIndex < || dotIndex == cookie.getDomain().length() 1) {
                throw new MalformedCookieException("Domain attribute \"" 
                    + cookie.getDomain() 
                    "\" violates RFC 2109: domain must contain an embedded dot");
            }
            host = host.toLowerCase();
            if (host.indexOf('.'>= 0) {
                if (!host.endsWith(cookie.getDomain())) {
                    throw new MalformedCookieException(
                        "Illegal domain attribute \"" + cookie.getDomain() 
                        "\". Domain of origin: \"" + host + "\"");
                }
                // host minus domain may not contain any dots
                String hostWithoutDomain = host.substring(0, host.length() 
                    - cookie.getDomain().length());
                if (hostWithoutDomain.indexOf('.'!= -1) {
                    throw new MalformedCookieException("Domain attribute \"" 
                        + cookie.getDomain() 
                        "\" violates RFC 2109: host minus domain may not contain any dots");
                }
            }
        }
    }


    /**
     * Return a name/value string suitable for sending in a <tt>"Cookie"</tt>
     * header as defined in RFC 2109 for backward compatibility with cookie
     * version 0
     @param name The name.
     @param value The value
     @param version The cookie version 
     @return a string suitable for sending in a <tt>"Cookie"</tt> header.
     */

    private String formatNameValuePair(
        final String name, final String value, int version) {
            
        final StringBuffer buffer = new StringBuffer();
        if (version < 1) {
            buffer.append(name);
            buffer.append("=");
            if (value != null) {
                buffer.append(value);   
            }
        else {
            buffer.append(name);
            buffer.append("=\"");
            if (value != null) {
                buffer.append(value);
            }
            buffer.append("\"");
        }
        return buffer.toString()
    }

    /**
     * Return a string suitable for sending in a <tt>"Cookie"</tt> header 
     * as defined in RFC 2109 for backward compatibility with cookie version 0
     @param cookie a {@link Cookie} to be formatted as string
     @param version The version to use.
     @return a string suitable for sending in a <tt>"Cookie"</tt> header.
     */
    private String formatCookieAsVer(Cookie cookie, int version) {
        LOG.trace("enter RFC2109Spec.formatCookieAsVer(Cookie)");
        if (cookie == null) {
            throw new IllegalArgumentException("Cookie may not be null");
        }
        StringBuffer buf = new StringBuffer();
        buf.append(formatNameValuePair(cookie.getName()
            cookie.getValue(), version));
        if (cookie.getDomain() != null 
            && cookie.isDomainAttributeSpecified()) {
                
            buf.append("; ");
            buf.append(formatNameValuePair("$Domain"
                cookie.getDomain(), version));
        }
        if (cookie.getPath() != null && cookie.isPathAttributeSpecified()) {
            buf.append("; ");
            buf.append(formatNameValuePair("$Path", cookie.getPath(), version));
        }
        return buf.toString();
    }


    /**
     * Return a string suitable for sending in a <tt>"Cookie"</tt> header as
     * defined in RFC 2109
     @param cookie a {@link Cookie} to be formatted as string
     @return a string suitable for sending in a <tt>"Cookie"</tt> header.
     */
    public String formatCookie(Cookie cookie) {
        LOG.trace("enter RFC2109Spec.formatCookie(Cookie)");
        if (cookie == null) {
            throw new IllegalArgumentException("Cookie may not be null");
        }
        int ver = cookie.getVersion();
        StringBuffer buffer = new StringBuffer();
        buffer.append(formatNameValuePair("$Version"
          Integer.toString(ver), ver));
        buffer.append("; ");
        buffer.append(formatCookieAsVer(cookie, ver));
        return buffer.toString();
    }

    /**
     * Create a RFC 2109 compliant <tt>"Cookie"</tt> header value containing all
     {@link Cookie}s in <i>cookies</i> suitable for sending in a <tt>"Cookie"
     </tt> header
     @param cookies an array of {@link Cookie}s to be formatted
     @return a string suitable for sending in a Cookie header.
     */
    public String formatCookies(Cookie[] cookies) {
        LOG.trace("enter RFC2109Spec.formatCookieHeader(Cookie[])");
        int version = Integer.MAX_VALUE;
        // Pick the lowerest common denominator
        for (int i = 0; i < cookies.length; i++) {
            Cookie cookie = cookies[i];
            if (cookie.getVersion() < version) {
                version = cookie.getVersion();
            }
        }
        final StringBuffer buffer = new StringBuffer();
        buffer.append(formatNameValuePair("$Version"
            Integer.toString(version), version));
        for (int i = 0; i < cookies.length; i++) {
            buffer.append("; ");
            buffer.append(formatCookieAsVer(cookies[i], version));
        }
        return buffer.toString();
    }
}