HeaderElement.java
  1  /*
  2   * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/HeaderElement.java,v 1.23 2004/05/13 04:03:25 mbecke Exp $
  3   * $Revision: 480424 $
  4   * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
  5   *
  6   * ====================================================================
  7   *
  8   *  Licensed to the Apache Software Foundation (ASF) under one or more
  9   *  contributor license agreements.  See the NOTICE file distributed with
 10   *  this work for additional information regarding copyright ownership.
 11   *  The ASF licenses this file to You under the Apache License, Version 2.0
 12   *  (the "License"); you may not use this file except in compliance with
 13   *  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, software
 18   *  distributed under the License is distributed on an "AS IS" BASIS,
 19   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 20   *  See the License for the specific language governing permissions and
 21   *  limitations under the License.
 22   * ====================================================================
 23   *
 24   * This software consists of voluntary contributions made by many
 25   * individuals on behalf of the Apache Software Foundation.  For more
 26   * information on the Apache Software Foundation, please see
 27   * <http://www.apache.org/>.
 28   *
 29   */
 30  
 31  package org.apache.commons.httpclient;
 32  
 33  import java.util.ArrayList;
 34  import java.util.List;
 35  
 36  import org.apache.commons.httpclient.util.ParameterParser;
 37  import org.apache.commons.logging.Log;
 38  import org.apache.commons.logging.LogFactory;
 39  
 40  /**
 41   * <p>One element of an HTTP header's value.</p>
 42   * <p>
 43   * Some HTTP headers (such as the set-cookie header) have values that
 44   * can be decomposed into multiple elements.  Such headers must be in the
 45   * following form:
 46   * </p>
 47   * <pre>
 48   * header  = [ element ] *( "," [ element ] )
 49   * element = name [ "=" [ value ] ] *( ";" [ param ] )
 50   * param   = name [ "=" [ value ] ]
 51   *
 52   * name    = token
 53   * value   = ( token | quoted-string )
 54   *
 55   * token         = 1*&lt;any char except "=", ",", ";", &lt;"&gt; and
 56   *                       white space&gt;
 57   * quoted-string = &lt;"&gt; *( text | quoted-char ) &lt;"&gt;
 58   * text          = any char except &lt;"&gt;
 59   * quoted-char   = "\" char
 60   * </pre>
 61   * <p>
 62   * Any amount of white space is allowed between any part of the
 63   * header, element or param and is ignored. A missing value in any
 64   * element or param will be stored as the empty {@link String};
 65   * if the "=" is also missing <var>null</var> will be stored instead.
 66   * </p>
 67   * <p>
 68   * This class represents an individual header element, containing
 69   * both a name/value pair (value may be <tt>null</tt>) and optionally
 70   * a set of additional parameters.
 71   * </p>
 72   * <p>
 73   * This class also exposes a {@link #parse} method for parsing a
 74   * {@link Header} value into an array of elements.
 75   * </p>
 76   *
 77   * @see Header
 78   *
 79   * @author <a href="mailto:bcholmes@interlog.com">B.C. Holmes</a>
 80   * @author <a href="mailto:jericho@thinkfree.com">Park, Sung-Gu</a>
 81   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
 82   * @author <a href="mailto:oleg@ural.com">Oleg Kalnichevski</a>
 83   * 
 84   * @since 1.0
 85   * @version $Revision: 480424 $ $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
 86   */
 87  public class HeaderElement extends NameValuePair {
 88  
 89      // ----------------------------------------------------------- Constructors
 90  
 91      /**
 92       * Default constructor.
 93       */
 94      public HeaderElement() {
 95          this(null, null, null);
 96      }
 97  
 98      /**
 99        * Constructor.
100        * @param name my name
101        * @param value my (possibly <tt>null</tt>) value
102        */
103      public HeaderElement(String name, String value) {
104          this(name, value, null);
105      }
106  
107      /**
108       * Constructor with name, value and parameters.
109       *
110       * @param name my name
111       * @param value my (possibly <tt>null</tt>) value
112       * @param parameters my (possibly <tt>null</tt>) parameters
113       */
114      public HeaderElement(String name, String value,
115              NameValuePair[] parameters) {
116          super(name, value);
117          this.parameters = parameters;
118      }
119  
120      /**
121       * Constructor with array of characters.
122       *
123       * @param chars the array of characters
124       * @param offset - the initial offset.
125       * @param length - the length.
126       * 
127       * @since 3.0
128       */
129      public HeaderElement(char[] chars, int offset, int length) {
130          this();
131          if (chars == null) {
132              return;
133          }
134          ParameterParser parser = new ParameterParser();
135          List params = parser.parse(chars, offset, length, ';');
136          if (params.size() > 0) {
137              NameValuePair element = (NameValuePair) params.remove(0);
138              setName(element.getName());  
139              setValue(element.getValue());
140              if (params.size() > 0) {
141                  this.parameters = (NameValuePair[])
142                      params.toArray(new NameValuePair[params.size()]);    
143              }
144          }
145      }
146  
147      /**
148       * Constructor with array of characters.
149       *
150       * @param chars the array of characters
151       * 
152       * @since 3.0
153       */
154      public HeaderElement(char[] chars) {
155          this(chars, 0, chars.length);
156      }
157  
158      // -------------------------------------------------------- Constants
159  
160      /** Log object for this class. */
161      private static final Log LOG = LogFactory.getLog(HeaderElement.class);
162  
163      // ----------------------------------------------------- Instance Variables
164  
165      /** My parameters, if any. */
166      private NameValuePair[] parameters = null;
167  
168      // ------------------------------------------------------------- Properties
169  
170      /**
171       * Get parameters, if any.
172       *
173       * @since 2.0
174       * @return parameters as an array of {@link NameValuePair}s
175       */
176      public NameValuePair[] getParameters() {
177          return this.parameters;
178      }
179  
180      // --------------------------------------------------------- Public Methods
181  
182      /**
183       * This parses the value part of a header. The result is an array of
184       * HeaderElement objects.
185       *
186       * @param headerValue  the array of char representation of the header value
187       *                     (as received from the web server).
188       * @return array of {@link HeaderElement}s.
189       * 
190       * @since 3.0
191       */
192      public static final HeaderElement[] parseElements(char[] headerValue) {
193              
194          LOG.trace("enter HeaderElement.parseElements(char[])");
195  
196          if (headerValue == null) {
197              return new HeaderElement[] {};
198          }
199          List elements = new ArrayList(); 
200          
201          int i = 0;
202          int from = 0;
203          int len = headerValue.length;
204          boolean qouted = false;
205          while (i < len) {
206              char ch = headerValue[i];
207              if (ch == '"') {
208                  qouted = !qouted;
209              }
210              HeaderElement element = null;
211              if ((!qouted) && (ch == ',')) {
212                  element = new HeaderElement(headerValue, from, i);
213                  from = i + 1;
214              } else if (i == len - 1) {
215                  element = new HeaderElement(headerValue, from, len);
216              }
217              if ((element != null) && (element.getName() != null)) {
218                  elements.add(element);
219              }
220              i++;
221          }
222          return (HeaderElement[])
223              elements.toArray(new HeaderElement[elements.size()]);
224      }
225  
226      /**
227       * This parses the value part of a header. The result is an array of
228       * HeaderElement objects.
229       *
230       * @param headerValue  the string representation of the header value
231       *                     (as received from the web server).
232       * @return array of {@link HeaderElement}s.
233       * 
234       * @since 3.0
235       */
236      public static final HeaderElement[] parseElements(String headerValue) {
237              
238          LOG.trace("enter HeaderElement.parseElements(String)");
239  
240          if (headerValue == null) {
241              return new HeaderElement[] {};
242          }
243          return parseElements(headerValue.toCharArray());
244      }
245  
246      /**
247       * This parses the value part of a header. The result is an array of
248       * HeaderElement objects.
249       *
250       * @param headerValue  the string representation of the header value
251       *                     (as received from the web server).
252       * @return array of {@link HeaderElement}s.
253       * @throws HttpException if the above syntax rules are violated.
254       * 
255       * @deprecated Use #parseElements(String).
256       */
257      public static final HeaderElement[] parse(String headerValue)
258          throws HttpException {
259              
260          LOG.trace("enter HeaderElement.parse(String)");
261  
262          if (headerValue == null) {
263              return new HeaderElement[] {};
264          }
265          return parseElements(headerValue.toCharArray());
266      }
267           
268  
269      /**
270       * Returns parameter with the given name, if found. Otherwise null 
271       * is returned
272       *
273       * @param name The name to search by.
274       * @return NameValuePair parameter with the given name
275       */
276  
277      public NameValuePair getParameterByName(String name) {
278  
279          LOG.trace("enter HeaderElement.getParameterByName(String)");
280  
281          if (name == null) {
282              throw new IllegalArgumentException("Name may not be null");
283          } 
284          NameValuePair found = null;
285          NameValuePair parameters[] = getParameters();
286          if (parameters != null) {
287              for (int i = 0; i < parameters.length; i++) {
288                  NameValuePair current = parameters[ i ];
289                  if (current.getName().equalsIgnoreCase(name)) {
290                      found = current;
291                      break;
292                  }
293              }
294          }
295          return found;
296      }
297  
298  }
299