alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  
/*
 * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HeaderElement.java,v 1.18 2003/04/14 04:06:55 mbecke Exp $
 * $Revision: 1.18 $
 * $Date: 2003/04/14 04:06:55 $
 *
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * 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
 * .
 *
 * [Additional notices, if required by prior licensing conditions]
 *
 */

package org.apache.commons.httpclient;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.BitSet;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.Vector;


/**
 * 

One element of an HTTP header's value.

*

* Some HTTP headers (such as the set-cookie header) have values that * can be decomposed into multiple elements. Such headers must be in the * following form: *

*
 * header  = [ element ] *( "," [ element ] )
 * element = name [ "=" [ value ] ] *( ";" [ param ] )
 * param   = name [ "=" [ value ] ]
 *
 * name    = token
 * value   = ( token | quoted-string )
 *
 * token         = 1*<any char except "=", ",", ";", <"> and
 *                       white space>
 * quoted-string = <"> *( text | quoted-char ) <">
 * text          = any char except <">
 * quoted-char   = "\" char
 * 
*

* Any amount of white space is allowed between any part of the * header, element or param and is ignored. A missing value in any * element or param will be stored as the empty {@link String}; * if the "=" is also missing null will be stored instead. *

*

* This class represents an individual header element, containing * both a name/value pair (value may be null) and optionally * a set of additional parameters. *

*

* This class also exposes a {@link #parse} method for parsing a * {@link Header} value into an array of elements. *

* * @see Header * * @author B.C. Holmes * @author Park, Sung-Gu * @author Mike Bowler * * @since 1.0 * @version $Revision: 1.18 $ $Date: 2003/04/14 04:06:55 $ */ public class HeaderElement extends NameValuePair { // ----------------------------------------------------------- Constructors /** * Default constructor. */ public HeaderElement() { this(null, null, null); } /** * Constructor. * @param name my name * @param value my (possibly null) value */ public HeaderElement(String name, String value) { this(name, value, null); } /** * Constructor with name, value and parameters. * * @param name my name * @param value my (possibly null) value * @param parameters my (possibly null) parameters */ public HeaderElement(String name, String value, NameValuePair[] parameters) { super(name, value); setParameters(parameters); } // -------------------------------------------------------- Constants /** Log object for this class. */ private static final Log LOG = LogFactory.getLog(HeaderElement.class); /** * Map of numeric values to whether or not the * corresponding character is a "separator * character" (tspecial). */ private static final BitSet SEPARATORS = new BitSet(128); /** * Map of numeric values to whether or not the * corresponding character is a "token * character". */ private static final BitSet TOKEN_CHAR = new BitSet(128); /** * Map of numeric values to whether or not the * corresponding character is an "unsafe * character". */ private static final BitSet UNSAFE_CHAR = new BitSet(128); /** * Static initializer for {@link #SEPARATORS}, * {@link #TOKEN_CHAR}, and {@link #UNSAFE_CHAR}. */ static { // rfc-2068 tspecial SEPARATORS.set('('); SEPARATORS.set(')'); SEPARATORS.set('<'); SEPARATORS.set('>'); SEPARATORS.set('@'); SEPARATORS.set(','); SEPARATORS.set(';'); SEPARATORS.set(':'); SEPARATORS.set('\\'); SEPARATORS.set('"'); SEPARATORS.set('/'); SEPARATORS.set('['); SEPARATORS.set(']'); SEPARATORS.set('?'); SEPARATORS.set('='); SEPARATORS.set('{'); SEPARATORS.set('}'); SEPARATORS.set(' '); SEPARATORS.set('\t'); // rfc-2068 token for (int ch = 32; ch < 127; ch++) { TOKEN_CHAR.set(ch); } TOKEN_CHAR.xor(SEPARATORS); // rfc-1738 unsafe characters, including CTL and SP, and excluding // "#" and "%" for (int ch = 0; ch < 32; ch++) { UNSAFE_CHAR.set(ch); } UNSAFE_CHAR.set(' '); UNSAFE_CHAR.set('<'); UNSAFE_CHAR.set('>'); UNSAFE_CHAR.set('"'); UNSAFE_CHAR.set('{'); UNSAFE_CHAR.set('}'); UNSAFE_CHAR.set('|'); UNSAFE_CHAR.set('\\'); UNSAFE_CHAR.set('^'); UNSAFE_CHAR.set('~'); UNSAFE_CHAR.set('['); UNSAFE_CHAR.set(']'); UNSAFE_CHAR.set('`'); UNSAFE_CHAR.set(127); } // ----------------------------------------------------- Instance Variables /** My parameters, if any. */ private NameValuePair[] parameters = null; // ------------------------------------------------------------- Properties /** * Get parameters, if any. * * @since 2.0 * @return parameters as an array of {@link NameValuePair}s */ public NameValuePair[] getParameters() { return this.parameters; } /** * * @param pairs The new parameters. May be null. */ protected void setParameters(final NameValuePair[] pairs) { parameters = pairs; } // --------------------------------------------------------- Public Methods /** * This parses the value part of a header. The result is an array of * HeaderElement objects. * * @param headerValue the string representation of the header value * (as received from the web server). * @return the header elements containing Header elements. * @throws HttpException if the above syntax rules are violated. */ public static final HeaderElement[] parse(String headerValue) throws HttpException { LOG.trace("enter HeaderElement.parse(String)"); if (headerValue == null) { return null; } Vector elements = new Vector(); StringTokenizer tokenizer = new StringTokenizer(headerValue.trim(), ","); while (tokenizer.countTokens() > 0) { String nextToken = tokenizer.nextToken(); // FIXME: refactor into private method named ? // careful... there may have been a comma in a quoted string try { while (HeaderElement.hasOddNumberOfQuotationMarks(nextToken)) { nextToken += "," + tokenizer.nextToken(); } } catch (NoSuchElementException exception) { throw new HttpException( "Bad header format: wrong number of quotation marks"); } // FIXME: Refactor out into a private method named ? try { /* * Following to RFC 2109 and 2965, in order not to conflict * with the next header element, make it sure to parse tokens. * the expires date format is "Wdy, DD-Mon-YY HH:MM:SS GMT". * Notice that there is always comma(',') sign. * For the general cases, rfc1123-date, rfc850-date. */ if (tokenizer.hasMoreTokens()) { String s = nextToken.toLowerCase(); if (s.endsWith("mon") || s.endsWith("tue") || s.endsWith("wed") || s.endsWith("thu") || s.endsWith("fri") || s.endsWith("sat") || s.endsWith("sun") || s.endsWith("monday") || s.endsWith("tuesday") || s.endsWith("wednesday") || s.endsWith("thursday") || s.endsWith("friday") || s.endsWith("saturday") || s.endsWith("sunday")) { nextToken += "," + tokenizer.nextToken(); } } } catch (NoSuchElementException exception) { throw new HttpException ("Bad header format: parsing with wrong header elements"); } String tmp = nextToken.trim(); if (!tmp.endsWith(";")) { tmp += ";"; } char[] header = tmp.toCharArray(); // FIXME: refactor into a private method named? parseElement? boolean inAString = false; int startPos = 0; HeaderElement element = new HeaderElement(); Vector paramlist = new Vector(); for (int i = 0 ; i < header.length ; i++) { if (header[i] == ';' && !inAString) { NameValuePair pair = parsePair(header, startPos, i); if (pair == null) { throw new HttpException( "Bad header format: empty name/value pair in" + nextToken); // the first name/value pair are handled differently } else if (startPos == 0) { element.setName(pair.getName()); element.setValue(pair.getValue()); } else { paramlist.addElement(pair); } startPos = i + 1; } else if (header[i] == '"' && !(inAString && i > 0 && header[i - 1] == '\\')) { inAString = !inAString; } } // now let's add all the parameters into the header element if (paramlist.size() > 0) { NameValuePair[] tmp2 = new NameValuePair[paramlist.size()]; paramlist.copyInto((NameValuePair[]) tmp2); element.setParameters (tmp2); paramlist.removeAllElements(); } // and save the header element into the list of header elements elements.addElement(element); } HeaderElement[] headerElements = new HeaderElement[elements.size()]; elements.copyInto((HeaderElement[]) headerElements); return headerElements; } /** * Return true if string has * an odd number of " characters. * * @param string the string to test * @return true if there are an odd number of quotation marks, false * otherwise */ private static final boolean hasOddNumberOfQuotationMarks(String string) { boolean odd = false; int start = -1; while ((start = string.indexOf('"', start + 1)) != -1) { odd = !odd; } return odd; } /** * Parse a header character array into a {@link NameValuePair} * * @param header the character array to parse * @param start the starting position of the text within the array * @param end the end position of the text within the array * @return a {@link NameValuePair} representing the header */ private static final NameValuePair parsePair(char[] header, int start, int end) { LOG.trace("enter HeaderElement.parsePair(char[], int, int)"); NameValuePair pair = null; String name = new String(header, start, end - start).trim(); String value = null; //TODO: This would certainly benefit from a StringBuffer int index = name.indexOf("="); if (index >= 0) { if ((index + 1) < name.length()) { value = name.substring(index + 1).trim(); // strip quotation marks if (value.startsWith("\"") && value.endsWith("\"")) { value = value.substring(1, value.length() - 1); } } name = name.substring(0, index).trim(); } pair = new NameValuePair(name, value); return pair; } /** * Returns parameter with the given name, if found. Otherwise null * is returned * * @param name The name to search by. * @return NameValuePair parameter with the given name */ public NameValuePair getParameterByName(String name) { if (name == null) { throw new NullPointerException("Name is null"); } NameValuePair found = null; NameValuePair parameters[] = getParameters(); if (parameters != null) { for (int i = 0; i < parameters.length; i++) { NameValuePair current = parameters[ i ]; if (current.getName().equalsIgnoreCase(name)) { found = current; break; } } } return found; } }
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.