Home » apache-tomcat-6.0.26-src » org.apache » tomcat » util » [javadoc | source]

    1   /*
    2    * The Apache Software License, Version 1.1
    3    *
    4    * Copyright (c) 1999 The Apache Software Foundation.  All rights
    5    * reserved.
    6    *
    7    * Redistribution and use in source and binary forms, with or without
    8    * modification, are permitted provided that the following conditions
    9    * are met:
   10    *
   11    * 1. Redistributions of source code must retain the above copyright
   12    *    notice, this list of conditions and the following disclaimer.
   13    *
   14    * 2. Redistributions in binary form must reproduce the above copyright
   15    *    notice, this list of conditions and the following disclaimer in
   16    *    the documentation and/or other materials provided with the
   17    *    distribution.
   18    *
   19    * 3. The end-user documentation included with the redistribution, if
   20    *    any, must include the following acknowlegement:
   21    *       "This product includes software developed by the
   22    *        Apache Software Foundation (http://www.apache.org/)."
   23    *    Alternately, this acknowlegement may appear in the software itself,
   24    *    if and wherever such third-party acknowlegements normally appear.
   25    *
   26    * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   27    *    Foundation" must not be used to endorse or promote products derived
   28    *    from this software without prior written permission. For written
   29    *    permission, please contact apache@apache.org.
   30    *
   31    * 5. Products derived from this software may not be called "Apache"
   32    *    nor may "Apache" appear in their names without prior written
   33    *    permission of the Apache Group.
   34    *
   35    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   36    * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   37    * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   38    * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   39    * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   40    * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   41    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   42    * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   43    * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   44    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   45    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   46    * SUCH DAMAGE.
   47    * ====================================================================
   48    *
   49    * This software consists of voluntary contributions made by many
   50    * individuals on behalf of the Apache Software Foundation.  For more
   51    * information on the Apache Software Foundation, please see
   52    * <http://www.apache.org/>.
   53    *
   54    * [Additional notices, if required by prior licensing conditions]
   55    *
   56    */
   57   
   58   
   59   package org.apache.tomcat.util;
   60   
   61   import javax.servlet;
   62   import java.io.IOException;
   63   import java.io.OutputStream;
   64   import java.io.PrintStream;
   65   import java.util.Enumeration;
   66   import java.util.Hashtable;
   67   import java.util.Vector;
   68   import java.util.NoSuchElementException;
   69   
   70   /**
   71    * This class is used to contain standard internet message headers,
   72    * used for SMTP (RFC822) and HTTP (RFC2068) messages as well as for
   73    * MIME (RFC 2045) applications such as transferring typed data and
   74    * grouping related items in multipart message bodies.
   75    *
   76    * <P> Message headers, as specified in RFC822, include a field name
   77    * and a field body.  Order has no semantic significance, and several
   78    * fields with the same name may exist.  However, most fields do not
   79    * (and should not) exist more than once in a header.
   80    *
   81    * <P> Many kinds of field body must conform to a specified syntax,
   82    * including the standard parenthesized comment syntax.  This class
   83    * supports only two simple syntaxes, for dates and integers.
   84    *
   85    * <P> When processing headers, care must be taken to handle the case of
   86    * multiple same-name fields correctly.  The values of such fields are
   87    * only available as strings.  They may be accessed by index (treating
   88    * the header as an array of fields), or by name (returning an array
   89    * of string values).
   90    *
   91    * @author dac@eng.sun.com
   92    * @author James Todd [gonzo@eng.sun.com]
   93    */
   94   
   95   public class MimeHeaders {
   96   
   97       private StringManager sm = null;
   98   //        StringManager.getManager(Constants.Package);
   99   
  100       private StringManager getStringManager() {
  101           if (sm == null) {
  102               sm = StringManager.getManager(Constants.Package);
  103           }
  104           return sm;
  105       }
  106   
  107       /**
  108        * The header fields.
  109        */
  110   
  111       private MimeHeaderField[] headers = new MimeHeaderField[8];
  112   
  113       /**
  114        * The current number of header fields.
  115        */
  116   
  117       private int count;
  118   
  119       /**
  120        * A buffer used when parsing headers.
  121        */
  122   
  123       private byte[] buf;
  124   
  125       /**
  126        * Creates a new MimeHeaders object using the specified buffer size.
  127        * @param len the buffer size initially used for parsing headers
  128        */
  129   
  130       public MimeHeaders(int len) {
  131   	buf = new byte[len];
  132       }
  133   
  134       /**
  135        * Creates a new MimeHeaders object using a default buffer size.
  136        */
  137   
  138       public MimeHeaders() {
  139   	this(512);
  140       }
  141   
  142       /**
  143        * Clears all header fields.
  144        */
  145   
  146       public void clear() {
  147   	for (int i = 0; i < count; i++) {
  148   	    headers[i].reset();
  149   	}
  150   
  151   	count = 0;
  152       }
  153   
  154       /**
  155        * Returns the current number of header fields.
  156        */
  157   
  158       public int size() {
  159   	return count;
  160       }
  161   
  162       /**
  163        * Returns an enumeration of strings representing the header field names.
  164        * Field names may appear multiple times in this enumeration, indicating
  165        * that multiple fields with that name exist in this header.
  166        */
  167   
  168       public Enumeration names() {
  169   	return new MimeHeadersEnumerator(this);
  170       }
  171   
  172       // NOTE:  All of these put/get "Header" calls should
  173       // be renamed to put/get "field" !!!  This object is
  174       // the header, and its components are called fields.
  175   
  176       /**
  177        * Creates a new header field whose value is the specified string.
  178        * @param name the header name
  179        * @param s the header field string value
  180        */
  181   
  182       public void putHeader(String name, String s) {
  183   	putHeader(name).setValue(s);
  184       }
  185   
  186       public void addHeader(String name, String s) {
  187           addHeader(name).setValue(s);
  188       }
  189   
  190       /**
  191        * Creates a new header field whose value is the specified integer.
  192        * @param name the header name
  193        * @param i the header field integer value
  194        */
  195   
  196       public void putIntHeader(String name, int i) {
  197   	putHeader(name).setIntValue(i);
  198       }
  199   
  200       public void addIntHeader(String name, int i) {
  201           addHeader(name).setIntValue(i);
  202       }
  203   
  204       /**
  205        * Creates a new header field whose value is the specified time.
  206        * The encoding uses RFC 822 date format, as updated by RFC 1123.
  207        * @param name the header name
  208        * @param t the time in number of milliseconds since the epoch
  209        */
  210   
  211       public void putDateHeader(String name, long t) {
  212   	putHeader(name).setDateValue(t);
  213       }
  214   
  215       public void addDateHeader(String name, long t) {
  216           addHeader(name).setDateValue(t);
  217       }
  218   
  219       /**
  220        * Creates a new header field whose value is the current date and time.
  221        * @param name the header name
  222        */
  223   
  224       public void putDateHeader(String name) {
  225   	putHeader(name).setDateValue();
  226       }
  227   
  228       public void addDateHeader(String name) {
  229           addHeader(name).setDateValue();
  230       }
  231   
  232       /**
  233        * Returns the string value of one of the headers with the
  234        * specified name.
  235        * @see getHeaders
  236        * @param name the header field name
  237        * @return the string value of the field, or null if none found
  238        */
  239   
  240       public String getHeader(String name) {
  241   	MimeHeaderField mh = find(name);
  242   
  243   	return mh != null ? mh.getValue() : null;
  244       }
  245   
  246       /**
  247        * Returns the string value of all of the headers with the
  248        * specified name.
  249        * @see getHeader
  250        * @param name the header field name
  251        * @return array values of the fields, or null if none found
  252        */
  253   
  254       public String[] getHeaders(String name) {
  255   	Vector values = getHeadersVector(name);
  256   
  257   	if (values.size() > 0) {
  258   	    String retval[] = new String[values.size()];
  259   
  260   	    for (int i = 0; i < retval.length; i++)
  261   		retval[i] = (String)values.elementAt(i);
  262   	    return retval;
  263   	}
  264   	return null;
  265       }
  266   
  267       /** Same as getHeaders, return a Vector - avoid Vector-[]-Vector conversion
  268        */
  269       public Vector getHeadersVector(String name) {
  270   	Vector values = new Vector();
  271   
  272   	for (int i = 0; i < count; i++) {
  273   	    if (headers[i].nameEquals(name))
  274   		values.addElement(headers[i].getValue());
  275   	}
  276   
  277   	return values;
  278       }
  279   
  280       /**
  281        * Returns the integer value of a header with the specified name.
  282        * @param name the header field name
  283        * @return the integer value of the header field, or -1 if the header
  284        *	       was not found
  285        * @exception NumberFormatException if the integer format was invalid
  286        */
  287   
  288       public int getIntHeader(String name) throws NumberFormatException {
  289   	MimeHeaderField mh = find(name);
  290   
  291   	return mh != null ? mh.getIntValue() : -1;
  292       }
  293   
  294       /**
  295        * Returns the date value of a header with the specified name.
  296        * @param name the header field name
  297        * @return the date value of the header field in number of milliseconds
  298        *	       since the epoch, or -1 if the header was not found
  299        * @exception IllegalArgumentException if the date format was invalid
  300        */
  301   
  302       public long getDateHeader(String name) throws IllegalArgumentException {
  303   	MimeHeaderField mh = find(name);
  304   
  305   	return mh != null ? mh.getDateValue() : -1;
  306       }
  307   
  308       /**
  309        * Returns the name of the nth header field where n >= 0. Returns null
  310        * if there were fewer than (n + 1) fields. This can be used to iterate
  311        * through all the fields in the header.
  312        */
  313   
  314       public String getHeaderName(int n) {
  315   	return n >= 0 && n < count ? headers[n].getName() : null;
  316       }
  317   
  318       /**
  319        * Returns the body of the nth header field where n >= 0. Returns null
  320        * if there were fewer than (n + 1) fields. This can be used along
  321        * with getHeaderName to iterate through all the fields in the header.
  322        */
  323   
  324       public String getHeader(int n) {
  325   	return n >= 0 && n < count ? headers[n].getValue() : null;
  326       }
  327   
  328       /**
  329        * Returns the Nth header field, or null if there is no such header.
  330        * This may be used to iterate through all header fields.
  331        */
  332   
  333       public MimeHeaderField getField(int n) {
  334   	return n >= 0 && n < count ? headers[n] : null;
  335       }
  336   
  337       /**
  338        * Returns the number of fields using a given field name.
  339        */
  340   
  341       public int getFieldCount (String name) {
  342   	int retval = 0;
  343   
  344   	for (int i = 0; i < count; i++)
  345   	    if (headers [i].nameEquals (name))
  346   		retval++;
  347   
  348   	return retval;
  349       }
  350   
  351       /**
  352        * Finds and returns a header field with the given name.  If no such
  353        * field exists, null is returned.  If more than one such field is
  354        * in the header, an arbitrary one is returned.
  355        */
  356   
  357       protected MimeHeaderField find(String name) {
  358           for (int i = 0; i < count; i++) {
  359   	    if (headers[i].nameEquals(name)) {
  360                   return headers[i];
  361               }
  362           }
  363   
  364           return null;
  365       }
  366   
  367       /**
  368        * Removes a header field with the specified name.  Does nothing
  369        * if such a field could not be found.
  370        * @param name the name of the header field to be removed
  371        */
  372   
  373       public void removeHeader(String name) {
  374           // XXX
  375           // warning: rather sticky code; heavily tuned
  376   
  377           for (int i = 0; i < count; i++) {
  378   	    if (headers[i].nameEquals(name)) {
  379   	        // reset and swap with last header
  380   	        MimeHeaderField mh = headers[i];
  381   
  382   		mh.reset();
  383   		headers[i] = headers[count - 1];
  384   		headers[count - 1] = mh;
  385   
  386   		count--;
  387   		i--;
  388   	    }
  389   	}
  390       }
  391   
  392       /**
  393        * Returns true if the specified field is contained in the header,
  394        * otherwise returns false.
  395        * @param name the field name
  396        */
  397   
  398       public boolean containsHeader(String name) {
  399   	return find(name) != null;
  400       }
  401   
  402       /**
  403        * Reads header fields from the specified servlet input stream until
  404        * a blank line is encountered.
  405        * @param in the servlet input stream
  406        * @exception IllegalArgumentException if the header format was invalid
  407        * @exception IOException if an I/O error has occurred
  408        */
  409   
  410       public void read(ServletInputStream in) throws IOException {
  411   	// use pre-allocated buffer if possible
  412   	byte[] b;
  413   
  414   	if (count == 0) {
  415   	    b = buf;
  416   	} else {
  417   	    b = new byte[buf.length];
  418   	}
  419   
  420   	int off = 0;
  421   
  422   	while (true) {
  423   	    int start = off;
  424   
  425   	    while (true) {
  426   		int len = b.length - off;
  427   
  428   		if (len > 0) {
  429   		    len = in.readLine(b, off, len);
  430   
  431   		    if (len == -1) {
  432                           StringManager sm = getStringManager();
  433                           String msg = sm.getString("mimeHeader.connection.ioe");
  434   			throw new IOException (msg);
  435   		    }
  436   		}
  437   
  438   		off += len;
  439   
  440   		if (len == 0 || b[off-1] == '\n') {
  441   		    break;
  442   		}
  443   
  444   		// overflowed buffer, so temporarily expand and continue
  445   		byte[] tmp = new byte[b.length * 2];
  446   
  447   		System.arraycopy(b, 0, tmp, 0, b.length);
  448   		b = tmp;
  449   	    }
  450   
  451   	    // strip off trailing "\r\n"
  452   	    if (--off > start && b[off-1] == '\r') {
  453   		--off;
  454   	    }
  455   
  456   	    if (off == start) {
  457   		break;
  458   	    }
  459   
  460   	    // XXX this does not currently handle headers which
  461   	    // are folded to take more than one line.
  462   
  463   	    putHeader().parse(b, start, off - start);
  464   	}
  465       }
  466   
  467       /**
  468        * Writes out header fields to the specified servlet output stream.
  469        * @param out the servlet output stream
  470        * @exception IOException if an I/O error has occurred
  471        */
  472   
  473       public void write(ServletOutputStream out) throws IOException {
  474   	for (int i = 0; i < count; i++) {
  475   	    headers[i].write(out);
  476   	}
  477   
  478   	out.println();
  479       }
  480   
  481       /**
  482        * Finds a header field given name.  If the header doesn't exist,
  483        * it will create a new one.
  484        * @param name the header field name
  485        * @return the new field
  486        */
  487   
  488       protected MimeHeaderField putHeader(String name) {
  489           if (containsHeader(name)) {
  490   	    removeHeader(name);
  491   	}
  492   
  493   	return addHeader(name);
  494       }
  495   
  496       protected MimeHeaderField addHeader(String name) {
  497    	MimeHeaderField mh = putHeader();
  498   
  499   	mh.setName(name);
  500   
  501   	return mh;
  502       }
  503   
  504       /**
  505        * Creates a new header with given name, and add it to the headers.
  506        * @param name the header field name
  507        * @param s the header value
  508        * @return the new field
  509        */
  510   
  511       public void appendHeader(String name, String s) {
  512   	MimeHeaderField mh = putHeader();
  513   
  514   	mh.setName(name);
  515   	mh.setValue(s);
  516       }
  517   
  518       /**
  519        * Adds a partially constructed field to the header.  This
  520        * field has not had its name or value initialized.
  521        */
  522   
  523       protected MimeHeaderField putHeader() {
  524   	MimeHeaderField mh;
  525   	int len = headers.length;
  526   
  527   	if (count >= len) {
  528   	    // expand header list array
  529   	    MimeHeaderField tmp[] = new MimeHeaderField[count * 2];
  530   
  531   	    System.arraycopy(headers, 0, tmp, 0, len);
  532   	    headers = tmp;
  533   	}
  534   
  535   	if ((mh = headers[count]) == null) {
  536   	    headers[count] = mh = new MimeHeaderField();
  537   	}
  538   
  539   	count++;
  540   
  541   	return mh;
  542       }
  543   
  544       /**
  545        * Get the current header fields in the byte array buf.  The headers
  546        * fields are placed starting at offset buf_offset.
  547        * @return the number of bytes written into buf.
  548        */
  549   
  550       public int getAll(byte buf[], int buf_offset) {
  551   	int start_pt = buf_offset;
  552   
  553   	for (int i = 0; i < count; i++) {
  554   	    buf_offset += headers[i].getBytes(buf, buf_offset);
  555   	}
  556   
  557   	return buf_offset - start_pt;
  558       }
  559   
  560       /**
  561        * Returns a lengthly string representation of the current header fields.
  562        */
  563   
  564       public String toString() {
  565   	StringBuffer sb = new StringBuffer();
  566   
  567   	sb.append("{");
  568   
  569   	for (int i = 0; i < count; i++) {
  570   	    sb.append("{");
  571   	    sb.append(headers[i].toString());
  572   	    sb.append("}");
  573   
  574   	    if (i < count - 1) {
  575   		sb.append(",");
  576   	    }
  577   	}
  578   
  579   	sb.append("}");
  580   
  581   	return sb.toString();
  582       }
  583   
  584       /**
  585        * Dumps current headers to specified PrintStream for debugging.
  586        */
  587   
  588       public void dump(PrintStream out) {
  589   	for (int i = 0; i < count; i++) {
  590   	    out.println(headers[i]);
  591   	}
  592       }
  593   }
  594   
  595   class MimeHeadersEnumerator implements Enumeration {
  596   //    private StringManager sm =
  597   //        StringManager.getManager(Constants.Package);
  598       private Hashtable hash;
  599       private Enumeration delegate;
  600   
  601       MimeHeadersEnumerator(MimeHeaders headers) {
  602           // Store header names in a Hashtable to guarantee uniqueness
  603           // This has the side benefit of letting us use Hashtable's enumerator
  604           hash = new Hashtable();
  605           int size = headers.size();
  606           for (int i = 0; i < size; i++) {
  607               hash.put(headers.getHeaderName(i), "");
  608           }
  609           delegate = hash.keys();
  610       }
  611   
  612       public boolean hasMoreElements() {
  613   	return delegate.hasMoreElements();
  614       }
  615   
  616       public Object nextElement() {
  617           try {
  618               return delegate.nextElement();
  619           }
  620           catch (NoSuchElementException e) {
  621               StringManager sm =
  622                   StringManager.getManager(Constants.Package);
  623   
  624               String msg = sm.getString("mimeHeaderEnumerator.next.nse");
  625   	    throw new NoSuchElementException(msg);
  626   	}
  627       }
  628   }

Home » apache-tomcat-6.0.26-src » org.apache » tomcat » util » [javadoc | source]