rt/emul/compact/src/main/java/java/net/URLConnection.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Thu, 31 Oct 2013 11:23:54 +0100
changeset 1398 9926996eca2d
parent 1396 1c64f76edaa7
permissions -rw-r--r--
Implementing URLConnection
     1 /*
     2  * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    25 
    26 package java.net;
    27 
    28 import java.io.IOException;
    29 import java.io.InputStream;
    30 import java.io.OutputStream;
    31 import java.io.PrintStream;
    32 import java.util.ArrayList;
    33 import java.util.Date;
    34 import java.util.StringTokenizer;
    35 import java.util.Collections;
    36 import java.util.HashMap;
    37 import java.util.Hashtable;
    38 import java.util.Iterator;
    39 import java.util.Map;
    40 import java.util.List;
    41 import java.util.NoSuchElementException;
    42 
    43 /**
    44  * The abstract class <code>URLConnection</code> is the superclass
    45  * of all classes that represent a communications link between the
    46  * application and a URL. Instances of this class can be used both to
    47  * read from and to write to the resource referenced by the URL. In
    48  * general, creating a connection to a URL is a multistep process:
    49  * <p>
    50  * <center><table border=2 summary="Describes the process of creating a connection to a URL: openConnection() and connect() over time.">
    51  * <tr><th><code>openConnection()</code></th>
    52  *     <th><code>connect()</code></th></tr>
    53  * <tr><td>Manipulate parameters that affect the connection to the remote
    54  *         resource.</td>
    55  *     <td>Interact with the resource; query header fields and
    56  *         contents.</td></tr>
    57  * </table>
    58  * ----------------------------&gt;
    59  * <br>time</center>
    60  *
    61  * <ol>
    62  * <li>The connection object is created by invoking the
    63  *     <code>openConnection</code> method on a URL.
    64  * <li>The setup parameters and general request properties are manipulated.
    65  * <li>The actual connection to the remote object is made, using the
    66  *    <code>connect</code> method.
    67  * <li>The remote object becomes available. The header fields and the contents
    68  *     of the remote object can be accessed.
    69  * </ol>
    70  * <p>
    71  * The setup parameters are modified using the following methods:
    72  * <ul>
    73  *   <li><code>setAllowUserInteraction</code>
    74  *   <li><code>setDoInput</code>
    75  *   <li><code>setDoOutput</code>
    76  *   <li><code>setIfModifiedSince</code>
    77  *   <li><code>setUseCaches</code>
    78  * </ul>
    79  * <p>
    80  * and the general request properties are modified using the method:
    81  * <ul>
    82  *   <li><code>setRequestProperty</code>
    83  * </ul>
    84  * <p>
    85  * Default values for the <code>AllowUserInteraction</code> and
    86  * <code>UseCaches</code> parameters can be set using the methods
    87  * <code>setDefaultAllowUserInteraction</code> and
    88  * <code>setDefaultUseCaches</code>.
    89  * <p>
    90  * Each of the above <code>set</code> methods has a corresponding
    91  * <code>get</code> method to retrieve the value of the parameter or
    92  * general request property. The specific parameters and general
    93  * request properties that are applicable are protocol specific.
    94  * <p>
    95  * The following methods are used to access the header fields and
    96  * the contents after the connection is made to the remote object:
    97  * <ul>
    98  *   <li><code>getContent</code>
    99  *   <li><code>getHeaderField</code>
   100  *   <li><code>getInputStream</code>
   101  *   <li><code>getOutputStream</code>
   102  * </ul>
   103  * <p>
   104  * Certain header fields are accessed frequently. The methods:
   105  * <ul>
   106  *   <li><code>getContentEncoding</code>
   107  *   <li><code>getContentLength</code>
   108  *   <li><code>getContentType</code>
   109  *   <li><code>getDate</code>
   110  *   <li><code>getExpiration</code>
   111  *   <li><code>getLastModifed</code>
   112  * </ul>
   113  * <p>
   114  * provide convenient access to these fields. The
   115  * <code>getContentType</code> method is used by the
   116  * <code>getContent</code> method to determine the type of the remote
   117  * object; subclasses may find it convenient to override the
   118  * <code>getContentType</code> method.
   119  * <p>
   120  * In the common case, all of the pre-connection parameters and
   121  * general request properties can be ignored: the pre-connection
   122  * parameters and request properties default to sensible values. For
   123  * most clients of this interface, there are only two interesting
   124  * methods: <code>getInputStream</code> and <code>getContent</code>,
   125  * which are mirrored in the <code>URL</code> class by convenience methods.
   126  * <p>
   127  * More information on the request properties and header fields of
   128  * an <code>http</code> connection can be found at:
   129  * <blockquote><pre>
   130  * <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a>
   131  * </pre></blockquote>
   132  *
   133  * Note about <code>fileNameMap</code>: In versions prior to JDK 1.1.6,
   134  * field <code>fileNameMap</code> of <code>URLConnection</code> was public.
   135  * In JDK 1.1.6 and later, <code>fileNameMap</code> is private; accessor
   136  * and mutator methods {@link #getFileNameMap() getFileNameMap} and
   137  * {@link #setFileNameMap(java.net.FileNameMap) setFileNameMap} are added
   138  * to access it.  This change is also described on the <a href=
   139  * "http://java.sun.com/products/jdk/1.2/compatibility.html">
   140  * Compatibility</a> page.
   141  *
   142  * Invoking the <tt>close()</tt> methods on the <tt>InputStream</tt> or <tt>OutputStream</tt> of an
   143  * <tt>URLConnection</tt> after a request may free network resources associated with this
   144  * instance, unless particular protocol specifications specify different behaviours
   145  * for it.
   146  *
   147  * @author  James Gosling
   148  * @see     java.net.URL#openConnection()
   149  * @see     java.net.URLConnection#connect()
   150  * @see     java.net.URLConnection#getContent()
   151  * @see     java.net.URLConnection#getContentEncoding()
   152  * @see     java.net.URLConnection#getContentLength()
   153  * @see     java.net.URLConnection#getContentType()
   154  * @see     java.net.URLConnection#getDate()
   155  * @see     java.net.URLConnection#getExpiration()
   156  * @see     java.net.URLConnection#getHeaderField(int)
   157  * @see     java.net.URLConnection#getHeaderField(java.lang.String)
   158  * @see     java.net.URLConnection#getInputStream()
   159  * @see     java.net.URLConnection#getLastModified()
   160  * @see     java.net.URLConnection#getOutputStream()
   161  * @see     java.net.URLConnection#setAllowUserInteraction(boolean)
   162  * @see     java.net.URLConnection#setDefaultUseCaches(boolean)
   163  * @see     java.net.URLConnection#setDoInput(boolean)
   164  * @see     java.net.URLConnection#setDoOutput(boolean)
   165  * @see     java.net.URLConnection#setIfModifiedSince(long)
   166  * @see     java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String)
   167  * @see     java.net.URLConnection#setUseCaches(boolean)
   168  * @since   JDK1.0
   169  */
   170 public abstract class URLConnection {
   171 
   172    /**
   173      * The URL represents the remote object on the World Wide Web to
   174      * which this connection is opened.
   175      * <p>
   176      * The value of this field can be accessed by the
   177      * <code>getURL</code> method.
   178      * <p>
   179      * The default value of this variable is the value of the URL
   180      * argument in the <code>URLConnection</code> constructor.
   181      *
   182      * @see     java.net.URLConnection#getURL()
   183      * @see     java.net.URLConnection#url
   184      */
   185     protected URL url;
   186 
   187    /**
   188      * This variable is set by the <code>setDoInput</code> method. Its
   189      * value is returned by the <code>getDoInput</code> method.
   190      * <p>
   191      * A URL connection can be used for input and/or output. Setting the
   192      * <code>doInput</code> flag to <code>true</code> indicates that
   193      * the application intends to read data from the URL connection.
   194      * <p>
   195      * The default value of this field is <code>true</code>.
   196      *
   197      * @see     java.net.URLConnection#getDoInput()
   198      * @see     java.net.URLConnection#setDoInput(boolean)
   199      */
   200     protected boolean doInput = true;
   201 
   202    /**
   203      * This variable is set by the <code>setDoOutput</code> method. Its
   204      * value is returned by the <code>getDoOutput</code> method.
   205      * <p>
   206      * A URL connection can be used for input and/or output. Setting the
   207      * <code>doOutput</code> flag to <code>true</code> indicates
   208      * that the application intends to write data to the URL connection.
   209      * <p>
   210      * The default value of this field is <code>false</code>.
   211      *
   212      * @see     java.net.URLConnection#getDoOutput()
   213      * @see     java.net.URLConnection#setDoOutput(boolean)
   214      */
   215     protected boolean doOutput = false;
   216 
   217     private static boolean defaultAllowUserInteraction = false;
   218 
   219    /**
   220      * If <code>true</code>, this <code>URL</code> is being examined in
   221      * a context in which it makes sense to allow user interactions such
   222      * as popping up an authentication dialog. If <code>false</code>,
   223      * then no user interaction is allowed.
   224      * <p>
   225      * The value of this field can be set by the
   226      * <code>setAllowUserInteraction</code> method.
   227      * Its value is returned by the
   228      * <code>getAllowUserInteraction</code> method.
   229      * Its default value is the value of the argument in the last invocation
   230      * of the <code>setDefaultAllowUserInteraction</code> method.
   231      *
   232      * @see     java.net.URLConnection#getAllowUserInteraction()
   233      * @see     java.net.URLConnection#setAllowUserInteraction(boolean)
   234      * @see     java.net.URLConnection#setDefaultAllowUserInteraction(boolean)
   235      */
   236     protected boolean allowUserInteraction = defaultAllowUserInteraction;
   237 
   238     private static boolean defaultUseCaches = true;
   239 
   240    /**
   241      * If <code>true</code>, the protocol is allowed to use caching
   242      * whenever it can. If <code>false</code>, the protocol must always
   243      * try to get a fresh copy of the object.
   244      * <p>
   245      * This field is set by the <code>setUseCaches</code> method. Its
   246      * value is returned by the <code>getUseCaches</code> method.
   247      * <p>
   248      * Its default value is the value given in the last invocation of the
   249      * <code>setDefaultUseCaches</code> method.
   250      *
   251      * @see     java.net.URLConnection#setUseCaches(boolean)
   252      * @see     java.net.URLConnection#getUseCaches()
   253      * @see     java.net.URLConnection#setDefaultUseCaches(boolean)
   254      */
   255     protected boolean useCaches = defaultUseCaches;
   256 
   257    /**
   258      * Some protocols support skipping the fetching of the object unless
   259      * the object has been modified more recently than a certain time.
   260      * <p>
   261      * A nonzero value gives a time as the number of milliseconds since
   262      * January 1, 1970, GMT. The object is fetched only if it has been
   263      * modified more recently than that time.
   264      * <p>
   265      * This variable is set by the <code>setIfModifiedSince</code>
   266      * method. Its value is returned by the
   267      * <code>getIfModifiedSince</code> method.
   268      * <p>
   269      * The default value of this field is <code>0</code>, indicating
   270      * that the fetching must always occur.
   271      *
   272      * @see     java.net.URLConnection#getIfModifiedSince()
   273      * @see     java.net.URLConnection#setIfModifiedSince(long)
   274      */
   275     protected long ifModifiedSince = 0;
   276 
   277    /**
   278      * If <code>false</code>, this connection object has not created a
   279      * communications link to the specified URL. If <code>true</code>,
   280      * the communications link has been established.
   281      */
   282     protected boolean connected = false;
   283 
   284     /**
   285      * @since 1.5
   286      */
   287     private int connectTimeout;
   288     private int readTimeout;
   289 
   290     /**
   291      * @since 1.6
   292      */
   293     private MessageHeader requests;
   294 
   295    /**
   296     * @since   JDK1.1
   297     */
   298     private static FileNameMap fileNameMap;
   299 
   300     /**
   301      * @since 1.2.2
   302      */
   303     private static boolean fileNameMapLoaded = false;
   304 
   305     /**
   306      * Loads filename map (a mimetable) from a data file. It will
   307      * first try to load the user-specific table, defined
   308      * by &quot;content.types.user.table&quot; property. If that fails,
   309      * it tries to load the default built-in table at
   310      * lib/content-types.properties under java home.
   311      *
   312      * @return the FileNameMap
   313      * @since 1.2
   314      * @see #setFileNameMap(java.net.FileNameMap)
   315      */
   316     public static synchronized FileNameMap getFileNameMap() {
   317         if ((fileNameMap == null) && !fileNameMapLoaded) {
   318             fileNameMap = new FileNameMap() {
   319                 @Override
   320                 public String getContentTypeFor(String fileName) {
   321                     return "text/plain";
   322                 }
   323             };
   324             fileNameMapLoaded = true;
   325         }
   326 
   327         return new FileNameMap() {
   328             private FileNameMap map = fileNameMap;
   329             public String getContentTypeFor(String fileName) {
   330                 return map.getContentTypeFor(fileName);
   331             }
   332         };
   333     }
   334 
   335     /**
   336      * Sets the FileNameMap.
   337      * <p>
   338      * If there is a security manager, this method first calls
   339      * the security manager's <code>checkSetFactory</code> method
   340      * to ensure the operation is allowed.
   341      * This could result in a SecurityException.
   342      *
   343      * @param map the FileNameMap to be set
   344      * @exception  SecurityException  if a security manager exists and its
   345      *             <code>checkSetFactory</code> method doesn't allow the operation.
   346      * @see        SecurityManager#checkSetFactory
   347      * @see #getFileNameMap()
   348      * @since 1.2
   349      */
   350     public static void setFileNameMap(FileNameMap map) {
   351         throw new SecurityException();
   352     }
   353 
   354     /**
   355      * Opens a communications link to the resource referenced by this
   356      * URL, if such a connection has not already been established.
   357      * <p>
   358      * If the <code>connect</code> method is called when the connection
   359      * has already been opened (indicated by the <code>connected</code>
   360      * field having the value <code>true</code>), the call is ignored.
   361      * <p>
   362      * URLConnection objects go through two phases: first they are
   363      * created, then they are connected.  After being created, and
   364      * before being connected, various options can be specified
   365      * (e.g., doInput and UseCaches).  After connecting, it is an
   366      * error to try to set them.  Operations that depend on being
   367      * connected, like getContentLength, will implicitly perform the
   368      * connection, if necessary.
   369      *
   370      * @throws SocketTimeoutException if the timeout expires before
   371      *               the connection can be established
   372      * @exception  IOException  if an I/O error occurs while opening the
   373      *               connection.
   374      * @see java.net.URLConnection#connected
   375      * @see #getConnectTimeout()
   376      * @see #setConnectTimeout(int)
   377      */
   378     abstract public void connect() throws IOException;
   379 
   380     /**
   381      * Sets a specified timeout value, in milliseconds, to be used
   382      * when opening a communications link to the resource referenced
   383      * by this URLConnection.  If the timeout expires before the
   384      * connection can be established, a
   385      * java.net.SocketTimeoutException is raised. A timeout of zero is
   386      * interpreted as an infinite timeout.
   387 
   388      * <p> Some non-standard implmentation of this method may ignore
   389      * the specified timeout. To see the connect timeout set, please
   390      * call getConnectTimeout().
   391      *
   392      * @param timeout an <code>int</code> that specifies the connect
   393      *               timeout value in milliseconds
   394      * @throws IllegalArgumentException if the timeout parameter is negative
   395      *
   396      * @see #getConnectTimeout()
   397      * @see #connect()
   398      * @since 1.5
   399      */
   400     public void setConnectTimeout(int timeout) {
   401         if (timeout < 0) {
   402             throw new IllegalArgumentException("timeout can not be negative");
   403         }
   404         connectTimeout = timeout;
   405     }
   406 
   407     /**
   408      * Returns setting for connect timeout.
   409      * <p>
   410      * 0 return implies that the option is disabled
   411      * (i.e., timeout of infinity).
   412      *
   413      * @return an <code>int</code> that indicates the connect timeout
   414      *         value in milliseconds
   415      * @see #setConnectTimeout(int)
   416      * @see #connect()
   417      * @since 1.5
   418      */
   419     public int getConnectTimeout() {
   420         return connectTimeout;
   421     }
   422 
   423     /**
   424      * Sets the read timeout to a specified timeout, in
   425      * milliseconds. A non-zero value specifies the timeout when
   426      * reading from Input stream when a connection is established to a
   427      * resource. If the timeout expires before there is data available
   428      * for read, a java.net.SocketTimeoutException is raised. A
   429      * timeout of zero is interpreted as an infinite timeout.
   430      *
   431      *<p> Some non-standard implementation of this method ignores the
   432      * specified timeout. To see the read timeout set, please call
   433      * getReadTimeout().
   434      *
   435      * @param timeout an <code>int</code> that specifies the timeout
   436      * value to be used in milliseconds
   437      * @throws IllegalArgumentException if the timeout parameter is negative
   438      *
   439      * @see #getReadTimeout()
   440      * @see InputStream#read()
   441      * @since 1.5
   442      */
   443     public void setReadTimeout(int timeout) {
   444         if (timeout < 0) {
   445             throw new IllegalArgumentException("timeout can not be negative");
   446         }
   447         readTimeout = timeout;
   448     }
   449 
   450     /**
   451      * Returns setting for read timeout. 0 return implies that the
   452      * option is disabled (i.e., timeout of infinity).
   453      *
   454      * @return an <code>int</code> that indicates the read timeout
   455      *         value in milliseconds
   456      *
   457      * @see #setReadTimeout(int)
   458      * @see InputStream#read()
   459      * @since 1.5
   460      */
   461     public int getReadTimeout() {
   462         return readTimeout;
   463     }
   464 
   465     /**
   466      * Constructs a URL connection to the specified URL. A connection to
   467      * the object referenced by the URL is not created.
   468      *
   469      * @param   url   the specified URL.
   470      */
   471     protected URLConnection(URL url) {
   472         this.url = url;
   473     }
   474 
   475     /**
   476      * Returns the value of this <code>URLConnection</code>'s <code>URL</code>
   477      * field.
   478      *
   479      * @return  the value of this <code>URLConnection</code>'s <code>URL</code>
   480      *          field.
   481      * @see     java.net.URLConnection#url
   482      */
   483     public URL getURL() {
   484         return url;
   485     }
   486 
   487     /**
   488      * Returns the value of the <code>content-length</code> header field.
   489      * <P>
   490      * <B>Note</B>: {@link #getContentLengthLong() getContentLengthLong()}
   491      * should be preferred over this method, since it returns a {@code long}
   492      * instead and is therefore more portable.</P>
   493      *
   494      * @return  the content length of the resource that this connection's URL
   495      *          references, {@code -1} if the content length is not known,
   496      *          or if the content length is greater than Integer.MAX_VALUE.
   497      */
   498     public int getContentLength() {
   499         long l = getContentLengthLong();
   500         if (l > Integer.MAX_VALUE)
   501             return -1;
   502         return (int) l;
   503     }
   504 
   505     /**
   506      * Returns the value of the <code>content-length</code> header field as a
   507      * long.
   508      *
   509      * @return  the content length of the resource that this connection's URL
   510      *          references, or <code>-1</code> if the content length is
   511      *          not known.
   512      * @since 7.0
   513      */
   514     public long getContentLengthLong() {
   515         return getHeaderFieldLong("content-length", -1);
   516     }
   517 
   518     /**
   519      * Returns the value of the <code>content-type</code> header field.
   520      *
   521      * @return  the content type of the resource that the URL references,
   522      *          or <code>null</code> if not known.
   523      * @see     java.net.URLConnection#getHeaderField(java.lang.String)
   524      */
   525     public String getContentType() {
   526         return getHeaderField("content-type");
   527     }
   528 
   529     /**
   530      * Returns the value of the <code>content-encoding</code> header field.
   531      *
   532      * @return  the content encoding of the resource that the URL references,
   533      *          or <code>null</code> if not known.
   534      * @see     java.net.URLConnection#getHeaderField(java.lang.String)
   535      */
   536     public String getContentEncoding() {
   537         return getHeaderField("content-encoding");
   538     }
   539 
   540     /**
   541      * Returns the value of the <code>expires</code> header field.
   542      *
   543      * @return  the expiration date of the resource that this URL references,
   544      *          or 0 if not known. The value is the number of milliseconds since
   545      *          January 1, 1970 GMT.
   546      * @see     java.net.URLConnection#getHeaderField(java.lang.String)
   547      */
   548     public long getExpiration() {
   549         return getHeaderFieldDate("expires", 0);
   550     }
   551 
   552     /**
   553      * Returns the value of the <code>date</code> header field.
   554      *
   555      * @return  the sending date of the resource that the URL references,
   556      *          or <code>0</code> if not known. The value returned is the
   557      *          number of milliseconds since January 1, 1970 GMT.
   558      * @see     java.net.URLConnection#getHeaderField(java.lang.String)
   559      */
   560     public long getDate() {
   561         return getHeaderFieldDate("date", 0);
   562     }
   563 
   564     /**
   565      * Returns the value of the <code>last-modified</code> header field.
   566      * The result is the number of milliseconds since January 1, 1970 GMT.
   567      *
   568      * @return  the date the resource referenced by this
   569      *          <code>URLConnection</code> was last modified, or 0 if not known.
   570      * @see     java.net.URLConnection#getHeaderField(java.lang.String)
   571      */
   572     public long getLastModified() {
   573         return getHeaderFieldDate("last-modified", 0);
   574     }
   575 
   576     /**
   577      * Returns the value of the named header field.
   578      * <p>
   579      * If called on a connection that sets the same header multiple times
   580      * with possibly different values, only the last value is returned.
   581      *
   582      *
   583      * @param   name   the name of a header field.
   584      * @return  the value of the named header field, or <code>null</code>
   585      *          if there is no such field in the header.
   586      */
   587     public String getHeaderField(String name) {
   588         return null;
   589     }
   590 
   591     /**
   592      * Returns an unmodifiable Map of the header fields.
   593      * The Map keys are Strings that represent the
   594      * response-header field names. Each Map value is an
   595      * unmodifiable List of Strings that represents
   596      * the corresponding field values.
   597      *
   598      * @return a Map of header fields
   599      * @since 1.4
   600      */
   601     public Map<String,List<String>> getHeaderFields() {
   602         return Collections.EMPTY_MAP;
   603     }
   604 
   605     /**
   606      * Returns the value of the named field parsed as a number.
   607      * <p>
   608      * This form of <code>getHeaderField</code> exists because some
   609      * connection types (e.g., <code>http-ng</code>) have pre-parsed
   610      * headers. Classes for that connection type can override this method
   611      * and short-circuit the parsing.
   612      *
   613      * @param   name      the name of the header field.
   614      * @param   Default   the default value.
   615      * @return  the value of the named field, parsed as an integer. The
   616      *          <code>Default</code> value is returned if the field is
   617      *          missing or malformed.
   618      */
   619     public int getHeaderFieldInt(String name, int Default) {
   620         String value = getHeaderField(name);
   621         try {
   622             return Integer.parseInt(value);
   623         } catch (Exception e) { }
   624         return Default;
   625     }
   626 
   627     /**
   628      * Returns the value of the named field parsed as a number.
   629      * <p>
   630      * This form of <code>getHeaderField</code> exists because some
   631      * connection types (e.g., <code>http-ng</code>) have pre-parsed
   632      * headers. Classes for that connection type can override this method
   633      * and short-circuit the parsing.
   634      *
   635      * @param   name      the name of the header field.
   636      * @param   Default   the default value.
   637      * @return  the value of the named field, parsed as a long. The
   638      *          <code>Default</code> value is returned if the field is
   639      *          missing or malformed.
   640      * @since 7.0
   641      */
   642     public long getHeaderFieldLong(String name, long Default) {
   643         String value = getHeaderField(name);
   644         try {
   645             return Long.parseLong(value);
   646         } catch (Exception e) { }
   647         return Default;
   648     }
   649 
   650     /**
   651      * Returns the value of the named field parsed as date.
   652      * The result is the number of milliseconds since January 1, 1970 GMT
   653      * represented by the named field.
   654      * <p>
   655      * This form of <code>getHeaderField</code> exists because some
   656      * connection types (e.g., <code>http-ng</code>) have pre-parsed
   657      * headers. Classes for that connection type can override this method
   658      * and short-circuit the parsing.
   659      *
   660      * @param   name     the name of the header field.
   661      * @param   Default   a default value.
   662      * @return  the value of the field, parsed as a date. The value of the
   663      *          <code>Default</code> argument is returned if the field is
   664      *          missing or malformed.
   665      */
   666     public long getHeaderFieldDate(String name, long Default) {
   667         String value = getHeaderField(name);
   668         try {
   669             return Date.parse(value);
   670         } catch (Exception e) { }
   671         return Default;
   672     }
   673 
   674     /**
   675      * Returns the key for the <code>n</code><sup>th</sup> header field.
   676      * It returns <code>null</code> if there are fewer than <code>n+1</code> fields.
   677      *
   678      * @param   n   an index, where n>=0
   679      * @return  the key for the <code>n</code><sup>th</sup> header field,
   680      *          or <code>null</code> if there are fewer than <code>n+1</code>
   681      *          fields.
   682      */
   683     public String getHeaderFieldKey(int n) {
   684         return null;
   685     }
   686 
   687     /**
   688      * Returns the value for the <code>n</code><sup>th</sup> header field.
   689      * It returns <code>null</code> if there are fewer than
   690      * <code>n+1</code>fields.
   691      * <p>
   692      * This method can be used in conjunction with the
   693      * {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all
   694      * the headers in the message.
   695      *
   696      * @param   n   an index, where n>=0
   697      * @return  the value of the <code>n</code><sup>th</sup> header field
   698      *          or <code>null</code> if there are fewer than <code>n+1</code> fields
   699      * @see     java.net.URLConnection#getHeaderFieldKey(int)
   700      */
   701     public String getHeaderField(int n) {
   702         return null;
   703     }
   704 
   705     /**
   706      * Retrieves the contents of this URL connection.
   707      * <p>
   708      * This method first determines the content type of the object by
   709      * calling the <code>getContentType</code> method. If this is
   710      * the first time that the application has seen that specific content
   711      * type, a content handler for that content type is created:
   712      * <ol>
   713      * <li>If the application has set up a content handler factory instance
   714      *     using the <code>setContentHandlerFactory</code> method, the
   715      *     <code>createContentHandler</code> method of that instance is called
   716      *     with the content type as an argument; the result is a content
   717      *     handler for that content type.
   718      * <li>If no content handler factory has yet been set up, or if the
   719      *     factory's <code>createContentHandler</code> method returns
   720      *     <code>null</code>, then the application loads the class named:
   721      *     <blockquote><pre>
   722      *         sun.net.www.content.&lt;<i>contentType</i>&gt;
   723      *     </pre></blockquote>
   724      *     where &lt;<i>contentType</i>&gt; is formed by taking the
   725      *     content-type string, replacing all slash characters with a
   726      *     <code>period</code> ('.'), and all other non-alphanumeric characters
   727      *     with the underscore character '<code>_</code>'. The alphanumeric
   728      *     characters are specifically the 26 uppercase ASCII letters
   729      *     '<code>A</code>' through '<code>Z</code>', the 26 lowercase ASCII
   730      *     letters '<code>a</code>' through '<code>z</code>', and the 10 ASCII
   731      *     digits '<code>0</code>' through '<code>9</code>'. If the specified
   732      *     class does not exist, or is not a subclass of
   733      *     <code>ContentHandler</code>, then an
   734      *     <code>UnknownServiceException</code> is thrown.
   735      * </ol>
   736      *
   737      * @return     the object fetched. The <code>instanceof</code> operator
   738      *               should be used to determine the specific kind of object
   739      *               returned.
   740      * @exception  IOException              if an I/O error occurs while
   741      *               getting the content.
   742      * @exception  UnknownServiceException  if the protocol does not support
   743      *               the content type.
   744      * @see        java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
   745      * @see        java.net.URLConnection#getContentType()
   746      * @see        java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
   747      */
   748     public Object getContent() throws IOException {
   749         // Must call getInputStream before GetHeaderField gets called
   750         // so that FileNotFoundException has a chance to be thrown up
   751         // from here without being caught.
   752         getInputStream();
   753         return getContentHandler().getContent(this);
   754     }
   755 
   756     /**
   757      * Retrieves the contents of this URL connection.
   758      *
   759      * @param classes the <code>Class</code> array
   760      * indicating the requested types
   761      * @return     the object fetched that is the first match of the type
   762      *               specified in the classes array. null if none of
   763      *               the requested types are supported.
   764      *               The <code>instanceof</code> operator should be used to
   765      *               determine the specific kind of object returned.
   766      * @exception  IOException              if an I/O error occurs while
   767      *               getting the content.
   768      * @exception  UnknownServiceException  if the protocol does not support
   769      *               the content type.
   770      * @see        java.net.URLConnection#getContent()
   771      * @see        java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
   772      * @see        java.net.URLConnection#getContent(java.lang.Class[])
   773      * @see        java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
   774      * @since 1.3
   775      */
   776     public Object getContent(Class[] classes) throws IOException {
   777         // Must call getInputStream before GetHeaderField gets called
   778         // so that FileNotFoundException has a chance to be thrown up
   779         // from here without being caught.
   780         getInputStream();
   781         return getContentHandler().getContent(this, classes);
   782     }
   783 
   784     /**
   785      * Returns a permission object representing the permission
   786      * necessary to make the connection represented by this
   787      * object. This method returns null if no permission is
   788      * required to make the connection. By default, this method
   789      * returns <code>java.security.AllPermission</code>. Subclasses
   790      * should override this method and return the permission
   791      * that best represents the permission required to make a
   792      * a connection to the URL. For example, a <code>URLConnection</code>
   793      * representing a <code>file:</code> URL would return a
   794      * <code>java.io.FilePermission</code> object.
   795      *
   796      * <p>The permission returned may dependent upon the state of the
   797      * connection. For example, the permission before connecting may be
   798      * different from that after connecting. For example, an HTTP
   799      * sever, say foo.com, may redirect the connection to a different
   800      * host, say bar.com. Before connecting the permission returned by
   801      * the connection will represent the permission needed to connect
   802      * to foo.com, while the permission returned after connecting will
   803      * be to bar.com.
   804      *
   805      * <p>Permissions are generally used for two purposes: to protect
   806      * caches of objects obtained through URLConnections, and to check
   807      * the right of a recipient to learn about a particular URL. In
   808      * the first case, the permission should be obtained
   809      * <em>after</em> the object has been obtained. For example, in an
   810      * HTTP connection, this will represent the permission to connect
   811      * to the host from which the data was ultimately fetched. In the
   812      * second case, the permission should be obtained and tested
   813      * <em>before</em> connecting.
   814      *
   815      * @return the permission object representing the permission
   816      * necessary to make the connection represented by this
   817      * URLConnection.
   818      *
   819      * @exception IOException if the computation of the permission
   820      * requires network or file I/O and an exception occurs while
   821      * computing it.
   822      */
   823 //    public Permission getPermission() throws IOException {
   824 //        return SecurityConstants.ALL_PERMISSION;
   825 //    }
   826 
   827     /**
   828      * Returns an input stream that reads from this open connection.
   829      *
   830      * A SocketTimeoutException can be thrown when reading from the
   831      * returned input stream if the read timeout expires before data
   832      * is available for read.
   833      *
   834      * @return     an input stream that reads from this open connection.
   835      * @exception  IOException              if an I/O error occurs while
   836      *               creating the input stream.
   837      * @exception  UnknownServiceException  if the protocol does not support
   838      *               input.
   839      * @see #setReadTimeout(int)
   840      * @see #getReadTimeout()
   841      */
   842     public InputStream getInputStream() throws IOException {
   843         throw new UnknownServiceException("protocol doesn't support input");
   844     }
   845 
   846     /**
   847      * Returns an output stream that writes to this connection.
   848      *
   849      * @return     an output stream that writes to this connection.
   850      * @exception  IOException              if an I/O error occurs while
   851      *               creating the output stream.
   852      * @exception  UnknownServiceException  if the protocol does not support
   853      *               output.
   854      */
   855     public OutputStream getOutputStream() throws IOException {
   856         throw new UnknownServiceException("protocol doesn't support output");
   857     }
   858 
   859     /**
   860      * Returns a <code>String</code> representation of this URL connection.
   861      *
   862      * @return  a string representation of this <code>URLConnection</code>.
   863      */
   864     public String toString() {
   865         return this.getClass().getName() + ":" + url;
   866     }
   867 
   868     /**
   869      * Sets the value of the <code>doInput</code> field for this
   870      * <code>URLConnection</code> to the specified value.
   871      * <p>
   872      * A URL connection can be used for input and/or output.  Set the DoInput
   873      * flag to true if you intend to use the URL connection for input,
   874      * false if not.  The default is true.
   875      *
   876      * @param   doinput   the new value.
   877      * @throws IllegalStateException if already connected
   878      * @see     java.net.URLConnection#doInput
   879      * @see #getDoInput()
   880      */
   881     public void setDoInput(boolean doinput) {
   882         if (connected)
   883             throw new IllegalStateException("Already connected");
   884         doInput = doinput;
   885     }
   886 
   887     /**
   888      * Returns the value of this <code>URLConnection</code>'s
   889      * <code>doInput</code> flag.
   890      *
   891      * @return  the value of this <code>URLConnection</code>'s
   892      *          <code>doInput</code> flag.
   893      * @see     #setDoInput(boolean)
   894      */
   895     public boolean getDoInput() {
   896         return doInput;
   897     }
   898 
   899     /**
   900      * Sets the value of the <code>doOutput</code> field for this
   901      * <code>URLConnection</code> to the specified value.
   902      * <p>
   903      * A URL connection can be used for input and/or output.  Set the DoOutput
   904      * flag to true if you intend to use the URL connection for output,
   905      * false if not.  The default is false.
   906      *
   907      * @param   dooutput   the new value.
   908      * @throws IllegalStateException if already connected
   909      * @see #getDoOutput()
   910      */
   911     public void setDoOutput(boolean dooutput) {
   912         if (connected)
   913             throw new IllegalStateException("Already connected");
   914         doOutput = dooutput;
   915     }
   916 
   917     /**
   918      * Returns the value of this <code>URLConnection</code>'s
   919      * <code>doOutput</code> flag.
   920      *
   921      * @return  the value of this <code>URLConnection</code>'s
   922      *          <code>doOutput</code> flag.
   923      * @see     #setDoOutput(boolean)
   924      */
   925     public boolean getDoOutput() {
   926         return doOutput;
   927     }
   928 
   929     /**
   930      * Set the value of the <code>allowUserInteraction</code> field of
   931      * this <code>URLConnection</code>.
   932      *
   933      * @param   allowuserinteraction   the new value.
   934      * @throws IllegalStateException if already connected
   935      * @see     #getAllowUserInteraction()
   936      */
   937     public void setAllowUserInteraction(boolean allowuserinteraction) {
   938         if (connected)
   939             throw new IllegalStateException("Already connected");
   940         allowUserInteraction = allowuserinteraction;
   941     }
   942 
   943     /**
   944      * Returns the value of the <code>allowUserInteraction</code> field for
   945      * this object.
   946      *
   947      * @return  the value of the <code>allowUserInteraction</code> field for
   948      *          this object.
   949      * @see     #setAllowUserInteraction(boolean)
   950      */
   951     public boolean getAllowUserInteraction() {
   952         return allowUserInteraction;
   953     }
   954 
   955     /**
   956      * Sets the default value of the
   957      * <code>allowUserInteraction</code> field for all future
   958      * <code>URLConnection</code> objects to the specified value.
   959      *
   960      * @param   defaultallowuserinteraction   the new value.
   961      * @see     #getDefaultAllowUserInteraction()
   962      */
   963     public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {
   964         defaultAllowUserInteraction = defaultallowuserinteraction;
   965     }
   966 
   967     /**
   968      * Returns the default value of the <code>allowUserInteraction</code>
   969      * field.
   970      * <p>
   971      * Ths default is "sticky", being a part of the static state of all
   972      * URLConnections.  This flag applies to the next, and all following
   973      * URLConnections that are created.
   974      *
   975      * @return  the default value of the <code>allowUserInteraction</code>
   976      *          field.
   977      * @see     #setDefaultAllowUserInteraction(boolean)
   978      */
   979     public static boolean getDefaultAllowUserInteraction() {
   980         return defaultAllowUserInteraction;
   981     }
   982 
   983     /**
   984      * Sets the value of the <code>useCaches</code> field of this
   985      * <code>URLConnection</code> to the specified value.
   986      * <p>
   987      * Some protocols do caching of documents.  Occasionally, it is important
   988      * to be able to "tunnel through" and ignore the caches (e.g., the
   989      * "reload" button in a browser).  If the UseCaches flag on a connection
   990      * is true, the connection is allowed to use whatever caches it can.
   991      *  If false, caches are to be ignored.
   992      *  The default value comes from DefaultUseCaches, which defaults to
   993      * true.
   994      *
   995      * @param usecaches a <code>boolean</code> indicating whether
   996      * or not to allow caching
   997      * @throws IllegalStateException if already connected
   998      * @see #getUseCaches()
   999      */
  1000     public void setUseCaches(boolean usecaches) {
  1001         if (connected)
  1002             throw new IllegalStateException("Already connected");
  1003         useCaches = usecaches;
  1004     }
  1005 
  1006     /**
  1007      * Returns the value of this <code>URLConnection</code>'s
  1008      * <code>useCaches</code> field.
  1009      *
  1010      * @return  the value of this <code>URLConnection</code>'s
  1011      *          <code>useCaches</code> field.
  1012      * @see #setUseCaches(boolean)
  1013      */
  1014     public boolean getUseCaches() {
  1015         return useCaches;
  1016     }
  1017 
  1018     /**
  1019      * Sets the value of the <code>ifModifiedSince</code> field of
  1020      * this <code>URLConnection</code> to the specified value.
  1021      *
  1022      * @param   ifmodifiedsince   the new value.
  1023      * @throws IllegalStateException if already connected
  1024      * @see     #getIfModifiedSince()
  1025      */
  1026     public void setIfModifiedSince(long ifmodifiedsince) {
  1027         if (connected)
  1028             throw new IllegalStateException("Already connected");
  1029         ifModifiedSince = ifmodifiedsince;
  1030     }
  1031 
  1032     /**
  1033      * Returns the value of this object's <code>ifModifiedSince</code> field.
  1034      *
  1035      * @return  the value of this object's <code>ifModifiedSince</code> field.
  1036      * @see #setIfModifiedSince(long)
  1037      */
  1038     public long getIfModifiedSince() {
  1039         return ifModifiedSince;
  1040     }
  1041 
  1042    /**
  1043      * Returns the default value of a <code>URLConnection</code>'s
  1044      * <code>useCaches</code> flag.
  1045      * <p>
  1046      * Ths default is "sticky", being a part of the static state of all
  1047      * URLConnections.  This flag applies to the next, and all following
  1048      * URLConnections that are created.
  1049      *
  1050      * @return  the default value of a <code>URLConnection</code>'s
  1051      *          <code>useCaches</code> flag.
  1052      * @see     #setDefaultUseCaches(boolean)
  1053      */
  1054     public boolean getDefaultUseCaches() {
  1055         return defaultUseCaches;
  1056     }
  1057 
  1058    /**
  1059      * Sets the default value of the <code>useCaches</code> field to the
  1060      * specified value.
  1061      *
  1062      * @param   defaultusecaches   the new value.
  1063      * @see     #getDefaultUseCaches()
  1064      */
  1065     public void setDefaultUseCaches(boolean defaultusecaches) {
  1066         defaultUseCaches = defaultusecaches;
  1067     }
  1068 
  1069     /**
  1070      * Sets the general request property. If a property with the key already
  1071      * exists, overwrite its value with the new value.
  1072      *
  1073      * <p> NOTE: HTTP requires all request properties which can
  1074      * legally have multiple instances with the same key
  1075      * to use a comma-seperated list syntax which enables multiple
  1076      * properties to be appended into a single property.
  1077      *
  1078      * @param   key     the keyword by which the request is known
  1079      *                  (e.g., "<code>Accept</code>").
  1080      * @param   value   the value associated with it.
  1081      * @throws IllegalStateException if already connected
  1082      * @throws NullPointerException if key is <CODE>null</CODE>
  1083      * @see #getRequestProperty(java.lang.String)
  1084      */
  1085     public void setRequestProperty(String key, String value) {
  1086         if (connected)
  1087             throw new IllegalStateException("Already connected");
  1088         if (key == null)
  1089             throw new NullPointerException ("key is null");
  1090 
  1091         if (requests == null)
  1092             requests = new MessageHeader();
  1093 
  1094         requests.set(key, value);
  1095     }
  1096 
  1097     /**
  1098      * Adds a general request property specified by a
  1099      * key-value pair.  This method will not overwrite
  1100      * existing values associated with the same key.
  1101      *
  1102      * @param   key     the keyword by which the request is known
  1103      *                  (e.g., "<code>Accept</code>").
  1104      * @param   value  the value associated with it.
  1105      * @throws IllegalStateException if already connected
  1106      * @throws NullPointerException if key is null
  1107      * @see #getRequestProperties()
  1108      * @since 1.4
  1109      */
  1110     public void addRequestProperty(String key, String value) {
  1111         if (connected)
  1112             throw new IllegalStateException("Already connected");
  1113         if (key == null)
  1114             throw new NullPointerException ("key is null");
  1115 
  1116         if (requests == null)
  1117             requests = new MessageHeader();
  1118 
  1119         requests.add(key, value);
  1120     }
  1121 
  1122 
  1123     /**
  1124      * Returns the value of the named general request property for this
  1125      * connection.
  1126      *
  1127      * @param key the keyword by which the request is known (e.g., "Accept").
  1128      * @return  the value of the named general request property for this
  1129      *           connection. If key is null, then null is returned.
  1130      * @throws IllegalStateException if already connected
  1131      * @see #setRequestProperty(java.lang.String, java.lang.String)
  1132      */
  1133     public String getRequestProperty(String key) {
  1134         if (connected)
  1135             throw new IllegalStateException("Already connected");
  1136 
  1137         if (requests == null)
  1138             return null;
  1139 
  1140         return requests.findValue(key);
  1141     }
  1142 
  1143     /**
  1144      * Returns an unmodifiable Map of general request
  1145      * properties for this connection. The Map keys
  1146      * are Strings that represent the request-header
  1147      * field names. Each Map value is a unmodifiable List
  1148      * of Strings that represents the corresponding
  1149      * field values.
  1150      *
  1151      * @return  a Map of the general request properties for this connection.
  1152      * @throws IllegalStateException if already connected
  1153      * @since 1.4
  1154      */
  1155     public Map<String,List<String>> getRequestProperties() {
  1156         if (connected)
  1157             throw new IllegalStateException("Already connected");
  1158 
  1159         if (requests == null)
  1160             return Collections.EMPTY_MAP;
  1161 
  1162         return requests.getHeaders(null);
  1163     }
  1164 
  1165     /**
  1166      * Sets the default value of a general request property. When a
  1167      * <code>URLConnection</code> is created, it is initialized with
  1168      * these properties.
  1169      *
  1170      * @param   key     the keyword by which the request is known
  1171      *                  (e.g., "<code>Accept</code>").
  1172      * @param   value   the value associated with the key.
  1173      *
  1174      * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String)
  1175      *
  1176      * @deprecated The instance specific setRequestProperty method
  1177      * should be used after an appropriate instance of URLConnection
  1178      * is obtained. Invoking this method will have no effect.
  1179      *
  1180      * @see #getDefaultRequestProperty(java.lang.String)
  1181      */
  1182     @Deprecated
  1183     public static void setDefaultRequestProperty(String key, String value) {
  1184     }
  1185 
  1186     /**
  1187      * Returns the value of the default request property. Default request
  1188      * properties are set for every connection.
  1189      *
  1190      * @param key the keyword by which the request is known (e.g., "Accept").
  1191      * @return  the value of the default request property
  1192      * for the specified key.
  1193      *
  1194      * @see java.net.URLConnection#getRequestProperty(java.lang.String)
  1195      *
  1196      * @deprecated The instance specific getRequestProperty method
  1197      * should be used after an appropriate instance of URLConnection
  1198      * is obtained.
  1199      *
  1200      * @see #setDefaultRequestProperty(java.lang.String, java.lang.String)
  1201      */
  1202     @Deprecated
  1203     public static String getDefaultRequestProperty(String key) {
  1204         return null;
  1205     }
  1206 
  1207     /**
  1208      * The ContentHandler factory.
  1209      */
  1210     static ContentHandlerFactory factory;
  1211 
  1212     /**
  1213      * Sets the <code>ContentHandlerFactory</code> of an
  1214      * application. It can be called at most once by an application.
  1215      * <p>
  1216      * The <code>ContentHandlerFactory</code> instance is used to
  1217      * construct a content handler from a content type
  1218      * <p>
  1219      * If there is a security manager, this method first calls
  1220      * the security manager's <code>checkSetFactory</code> method
  1221      * to ensure the operation is allowed.
  1222      * This could result in a SecurityException.
  1223      *
  1224      * @param      fac   the desired factory.
  1225      * @exception  Error  if the factory has already been defined.
  1226      * @exception  SecurityException  if a security manager exists and its
  1227      *             <code>checkSetFactory</code> method doesn't allow the operation.
  1228      * @see        java.net.ContentHandlerFactory
  1229      * @see        java.net.URLConnection#getContent()
  1230      * @see        SecurityManager#checkSetFactory
  1231      */
  1232     public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {
  1233         throw new SecurityException();
  1234     }
  1235 
  1236     private static Hashtable handlers = new Hashtable();
  1237 
  1238     /**
  1239      * Gets the Content Handler appropriate for this connection.
  1240      * @param connection the connection to use.
  1241      */
  1242     synchronized ContentHandler getContentHandler()
  1243     throws UnknownServiceException
  1244     {
  1245         String contentType = stripOffParameters(getContentType());
  1246         ContentHandler handler = null;
  1247         if (contentType == null)
  1248             throw new UnknownServiceException("no content-type");
  1249         try {
  1250             handler = (ContentHandler) handlers.get(contentType);
  1251             if (handler != null)
  1252                 return handler;
  1253         } catch(Exception e) {
  1254         }
  1255 
  1256         if (factory != null)
  1257             handler = factory.createContentHandler(contentType);
  1258         if (handler == null) {
  1259             try {
  1260                 handler = lookupContentHandlerClassFor(contentType);
  1261             } catch(Exception e) {
  1262                 e.printStackTrace();
  1263                 handler = UnknownContentHandler.INSTANCE;
  1264             }
  1265             handlers.put(contentType, handler);
  1266         }
  1267         return handler;
  1268     }
  1269 
  1270     /*
  1271      * Media types are in the format: type/subtype*(; parameter).
  1272      * For looking up the content handler, we should ignore those
  1273      * parameters.
  1274      */
  1275     private String stripOffParameters(String contentType)
  1276     {
  1277         if (contentType == null)
  1278             return null;
  1279         int index = contentType.indexOf(';');
  1280 
  1281         if (index > 0)
  1282             return contentType.substring(0, index);
  1283         else
  1284             return contentType;
  1285     }
  1286 
  1287     private static final String contentClassPrefix = "sun.net.www.content";
  1288     private static final String contentPathProp = "java.content.handler.pkgs";
  1289 
  1290     /**
  1291      * Looks for a content handler in a user-defineable set of places.
  1292      * By default it looks in sun.net.www.content, but users can define a
  1293      * vertical-bar delimited set of class prefixes to search through in
  1294      * addition by defining the java.content.handler.pkgs property.
  1295      * The class name must be of the form:
  1296      * <pre>
  1297      *     {package-prefix}.{major}.{minor}
  1298      * e.g.
  1299      *     YoyoDyne.experimental.text.plain
  1300      * </pre>
  1301      */
  1302     private ContentHandler lookupContentHandlerClassFor(String contentType)
  1303         throws InstantiationException, IllegalAccessException, ClassNotFoundException {
  1304         String contentHandlerClassName = typeToPackageName(contentType);
  1305 
  1306         String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes();
  1307 
  1308         StringTokenizer packagePrefixIter =
  1309             new StringTokenizer(contentHandlerPkgPrefixes, "|");
  1310 
  1311         while (packagePrefixIter.hasMoreTokens()) {
  1312             String packagePrefix = packagePrefixIter.nextToken().trim();
  1313 
  1314             try {
  1315                 String clsName = packagePrefix + "." + contentHandlerClassName;
  1316                 Class cls = null;
  1317                 try {
  1318                     cls = Class.forName(clsName);
  1319                 } catch (ClassNotFoundException e) {
  1320                     ClassLoader cl = ClassLoader.getSystemClassLoader();
  1321                     if (cl != null) {
  1322                         cls = cl.loadClass(clsName);
  1323                     }
  1324                 }
  1325                 if (cls != null) {
  1326                     ContentHandler handler =
  1327                         (ContentHandler)cls.newInstance();
  1328                     return handler;
  1329                 }
  1330             } catch(Exception e) {
  1331             }
  1332         }
  1333 
  1334         return UnknownContentHandler.INSTANCE;
  1335     }
  1336 
  1337     /**
  1338      * Utility function to map a MIME content type into an equivalent
  1339      * pair of class name components.  For example: "text/html" would
  1340      * be returned as "text.html"
  1341      */
  1342     private String typeToPackageName(String contentType) {
  1343         // make sure we canonicalize the class name: all lower case
  1344         contentType = contentType.toLowerCase();
  1345         int len = contentType.length();
  1346         char nm[] = new char[len];
  1347         contentType.getChars(0, len, nm, 0);
  1348         for (int i = 0; i < len; i++) {
  1349             char c = nm[i];
  1350             if (c == '/') {
  1351                 nm[i] = '.';
  1352             } else if (!('A' <= c && c <= 'Z' ||
  1353                        'a' <= c && c <= 'z' ||
  1354                        '0' <= c && c <= '9')) {
  1355                 nm[i] = '_';
  1356             }
  1357         }
  1358         return new String(nm);
  1359     }
  1360 
  1361 
  1362     /**
  1363      * Returns a vertical bar separated list of package prefixes for potential
  1364      * content handlers.  Tries to get the java.content.handler.pkgs property
  1365      * to use as a set of package prefixes to search.  Whether or not
  1366      * that property has been defined, the sun.net.www.content is always
  1367      * the last one on the returned package list.
  1368      */
  1369     private String getContentHandlerPkgPrefixes() {
  1370         String packagePrefixList = "";
  1371         
  1372         if (packagePrefixList != "") {
  1373             packagePrefixList += "|";
  1374         }
  1375 
  1376         return packagePrefixList + contentClassPrefix;
  1377     }
  1378 
  1379     /**
  1380      * Tries to determine the content type of an object, based
  1381      * on the specified "file" component of a URL.
  1382      * This is a convenience method that can be used by
  1383      * subclasses that override the <code>getContentType</code> method.
  1384      *
  1385      * @param   fname   a filename.
  1386      * @return  a guess as to what the content type of the object is,
  1387      *          based upon its file name.
  1388      * @see     java.net.URLConnection#getContentType()
  1389      */
  1390     public static String guessContentTypeFromName(String fname) {
  1391         return getFileNameMap().getContentTypeFor(fname);
  1392     }
  1393 
  1394     /**
  1395      * Tries to determine the type of an input stream based on the
  1396      * characters at the beginning of the input stream. This method can
  1397      * be used by subclasses that override the
  1398      * <code>getContentType</code> method.
  1399      * <p>
  1400      * Ideally, this routine would not be needed. But many
  1401      * <code>http</code> servers return the incorrect content type; in
  1402      * addition, there are many nonstandard extensions. Direct inspection
  1403      * of the bytes to determine the content type is often more accurate
  1404      * than believing the content type claimed by the <code>http</code> server.
  1405      *
  1406      * @param      is   an input stream that supports marks.
  1407      * @return     a guess at the content type, or <code>null</code> if none
  1408      *             can be determined.
  1409      * @exception  IOException  if an I/O error occurs while reading the
  1410      *               input stream.
  1411      * @see        java.io.InputStream#mark(int)
  1412      * @see        java.io.InputStream#markSupported()
  1413      * @see        java.net.URLConnection#getContentType()
  1414      */
  1415     static public String guessContentTypeFromStream(InputStream is)
  1416                         throws IOException {
  1417         // If we can't read ahead safely, just give up on guessing
  1418         if (!is.markSupported())
  1419             return null;
  1420 
  1421         is.mark(16);
  1422         int c1 = is.read();
  1423         int c2 = is.read();
  1424         int c3 = is.read();
  1425         int c4 = is.read();
  1426         int c5 = is.read();
  1427         int c6 = is.read();
  1428         int c7 = is.read();
  1429         int c8 = is.read();
  1430         int c9 = is.read();
  1431         int c10 = is.read();
  1432         int c11 = is.read();
  1433         int c12 = is.read();
  1434         int c13 = is.read();
  1435         int c14 = is.read();
  1436         int c15 = is.read();
  1437         int c16 = is.read();
  1438         is.reset();
  1439 
  1440         if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {
  1441             return "application/java-vm";
  1442         }
  1443 
  1444         if (c1 == 0xAC && c2 == 0xED) {
  1445             // next two bytes are version number, currently 0x00 0x05
  1446             return "application/x-java-serialized-object";
  1447         }
  1448 
  1449         if (c1 == '<') {
  1450             if (c2 == '!'
  1451                 || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' ||
  1452                                    c3 == 'e' && c4 == 'a' && c5 == 'd') ||
  1453                 (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) ||
  1454                 ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' ||
  1455                                 c3 == 'E' && c4 == 'A' && c5 == 'D') ||
  1456                 (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) {
  1457                 return "text/html";
  1458             }
  1459 
  1460             if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') {
  1461                 return "application/xml";
  1462             }
  1463         }
  1464 
  1465         // big and little (identical) endian UTF-8 encodings, with BOM
  1466         if (c1 == 0xef &&  c2 == 0xbb &&  c3 == 0xbf) {
  1467             if (c4 == '<' &&  c5 == '?' &&  c6 == 'x') {
  1468                 return "application/xml";
  1469             }
  1470         }
  1471 
  1472         // big and little endian UTF-16 encodings, with byte order mark
  1473         if (c1 == 0xfe && c2 == 0xff) {
  1474             if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' &&
  1475                 c7 == 0 && c8 == 'x') {
  1476                 return "application/xml";
  1477             }
  1478         }
  1479 
  1480         if (c1 == 0xff && c2 == 0xfe) {
  1481             if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 &&
  1482                 c7 == 'x' && c8 == 0) {
  1483                 return "application/xml";
  1484             }
  1485         }
  1486 
  1487         // big and little endian UTF-32 encodings, with BOM
  1488         if (c1 == 0x00 &&  c2 == 0x00 &&  c3 == 0xfe &&  c4 == 0xff) {
  1489             if (c5  == 0 && c6  == 0 && c7  == 0 && c8  == '<' &&
  1490                 c9  == 0 && c10 == 0 && c11 == 0 && c12 == '?' &&
  1491                 c13 == 0 && c14 == 0 && c15 == 0 && c16 == 'x') {
  1492                 return "application/xml";
  1493             }
  1494         }
  1495 
  1496         if (c1 == 0xff &&  c2 == 0xfe &&  c3 == 0x00 &&  c4 == 0x00) {
  1497             if (c5  == '<' && c6  == 0 && c7  == 0 && c8  == 0 &&
  1498                 c9  == '?' && c10 == 0 && c11 == 0 && c12 == 0 &&
  1499                 c13 == 'x' && c14 == 0 && c15 == 0 && c16 == 0) {
  1500                 return "application/xml";
  1501             }
  1502         }
  1503 
  1504         if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
  1505             return "image/gif";
  1506         }
  1507 
  1508         if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
  1509             return "image/x-bitmap";
  1510         }
  1511 
  1512         if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
  1513                         c5 == 'M' && c6 == '2') {
  1514             return "image/x-pixmap";
  1515         }
  1516 
  1517         if (c1 == 137 && c2 == 80 && c3 == 78 &&
  1518                 c4 == 71 && c5 == 13 && c6 == 10 &&
  1519                 c7 == 26 && c8 == 10) {
  1520             return "image/png";
  1521         }
  1522 
  1523         if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {
  1524             if (c4 == 0xE0) {
  1525                 return "image/jpeg";
  1526             }
  1527 
  1528             /**
  1529              * File format used by digital cameras to store images.
  1530              * Exif Format can be read by any application supporting
  1531              * JPEG. Exif Spec can be found at:
  1532              * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
  1533              */
  1534             if ((c4 == 0xE1) &&
  1535                 (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' &&
  1536                  c11 == 0)) {
  1537                 return "image/jpeg";
  1538             }
  1539 
  1540             if (c4 == 0xEE) {
  1541                 return "image/jpg";
  1542             }
  1543         }
  1544 
  1545         if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 &&
  1546             c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {
  1547 
  1548             /* Above is signature of Microsoft Structured Storage.
  1549              * Below this, could have tests for various SS entities.
  1550              * For now, just test for FlashPix.
  1551              */
  1552             if (checkfpx(is)) {
  1553                 return "image/vnd.fpx";
  1554             }
  1555         }
  1556 
  1557         if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) {
  1558             return "audio/basic";  // .au format, big endian
  1559         }
  1560 
  1561         if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) {
  1562             return "audio/basic";  // .au format, little endian
  1563         }
  1564 
  1565         if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') {
  1566             /* I don't know if this is official but evidence
  1567              * suggests that .wav files start with "RIFF" - brown
  1568              */
  1569             return "audio/x-wav";
  1570         }
  1571         return null;
  1572     }
  1573 
  1574     /**
  1575      * Check for FlashPix image data in InputStream is.  Return true if
  1576      * the stream has FlashPix data, false otherwise.  Before calling this
  1577      * method, the stream should have already been checked to be sure it
  1578      * contains Microsoft Structured Storage data.
  1579      */
  1580     static private boolean checkfpx(InputStream is) throws IOException {
  1581 
  1582         /* Test for FlashPix image data in Microsoft Structured Storage format.
  1583          * In general, should do this with calls to an SS implementation.
  1584          * Lacking that, need to dig via offsets to get to the FlashPix
  1585          * ClassID.  Details:
  1586          *
  1587          * Offset to Fpx ClsID from beginning of stream should be:
  1588          *
  1589          * FpxClsidOffset = rootEntryOffset + clsidOffset
  1590          *
  1591          * where: clsidOffset = 0x50.
  1592          *        rootEntryOffset = headerSize + sectorSize*sectDirStart
  1593          *                          + 128*rootEntryDirectory
  1594          *
  1595          *        where:  headerSize = 0x200 (always)
  1596          *                sectorSize = 2 raised to power of uSectorShift,
  1597          *                             which is found in the header at
  1598          *                             offset 0x1E.
  1599          *                sectDirStart = found in the header at offset 0x30.
  1600          *                rootEntryDirectory = in general, should search for
  1601          *                                     directory labelled as root.
  1602          *                                     We will assume value of 0 (i.e.,
  1603          *                                     rootEntry is in first directory)
  1604          */
  1605 
  1606         // Mark the stream so we can reset it. 0x100 is enough for the first
  1607         // few reads, but the mark will have to be reset and set again once
  1608         // the offset to the root directory entry is computed. That offset
  1609         // can be very large and isn't know until the stream has been read from
  1610         is.mark(0x100);
  1611 
  1612         // Get the byte ordering located at 0x1E. 0xFE is Intel,
  1613         // 0xFF is other
  1614         long toSkip = (long)0x1C;
  1615         long posn;
  1616 
  1617         if ((posn = skipForward(is, toSkip)) < toSkip) {
  1618           is.reset();
  1619           return false;
  1620         }
  1621 
  1622         int c[] = new int[16];
  1623         if (readBytes(c, 2, is) < 0) {
  1624             is.reset();
  1625             return false;
  1626         }
  1627 
  1628         int byteOrder = c[0];
  1629 
  1630         posn+=2;
  1631         int uSectorShift;
  1632         if (readBytes(c, 2, is) < 0) {
  1633             is.reset();
  1634             return false;
  1635         }
  1636 
  1637         if(byteOrder == 0xFE) {
  1638             uSectorShift = c[0];
  1639             uSectorShift += c[1] << 8;
  1640         }
  1641         else {
  1642             uSectorShift = c[0] << 8;
  1643             uSectorShift += c[1];
  1644         }
  1645 
  1646         posn += 2;
  1647         toSkip = (long)0x30 - posn;
  1648         long skipped = 0;
  1649         if ((skipped = skipForward(is, toSkip)) < toSkip) {
  1650           is.reset();
  1651           return false;
  1652         }
  1653         posn += skipped;
  1654 
  1655         if (readBytes(c, 4, is) < 0) {
  1656             is.reset();
  1657             return false;
  1658         }
  1659 
  1660         int sectDirStart;
  1661         if(byteOrder == 0xFE) {
  1662             sectDirStart = c[0];
  1663             sectDirStart += c[1] << 8;
  1664             sectDirStart += c[2] << 16;
  1665             sectDirStart += c[3] << 24;
  1666         } else {
  1667             sectDirStart =  c[0] << 24;
  1668             sectDirStart += c[1] << 16;
  1669             sectDirStart += c[2] << 8;
  1670             sectDirStart += c[3];
  1671         }
  1672         posn += 4;
  1673         is.reset(); // Reset back to the beginning
  1674 
  1675         toSkip = 0x200L + (long)(1<<uSectorShift)*sectDirStart + 0x50L;
  1676 
  1677         // Sanity check!
  1678         if (toSkip < 0) {
  1679             return false;
  1680         }
  1681 
  1682         /*
  1683          * How far can we skip? Is there any performance problem here?
  1684          * This skip can be fairly long, at least 0x4c650 in at least
  1685          * one case. Have to assume that the skip will fit in an int.
  1686          * Leave room to read whole root dir
  1687          */
  1688         is.mark((int)toSkip+0x30);
  1689 
  1690         if ((skipForward(is, toSkip)) < toSkip) {
  1691             is.reset();
  1692             return false;
  1693         }
  1694 
  1695         /* should be at beginning of ClassID, which is as follows
  1696          * (in Intel byte order):
  1697          *    00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B
  1698          *
  1699          * This is stored from Windows as long,short,short,char[8]
  1700          * so for byte order changes, the order only changes for
  1701          * the first 8 bytes in the ClassID.
  1702          *
  1703          * Test against this, ignoring second byte (Intel) since
  1704          * this could change depending on part of Fpx file we have.
  1705          */
  1706 
  1707         if (readBytes(c, 16, is) < 0) {
  1708             is.reset();
  1709             return false;
  1710         }
  1711 
  1712         // intel byte order
  1713         if (byteOrder == 0xFE &&
  1714             c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 &&
  1715             c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE &&
  1716             c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
  1717             c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
  1718             c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
  1719             is.reset();
  1720             return true;
  1721         }
  1722 
  1723         // non-intel byte order
  1724         else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 &&
  1725             c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE &&
  1726             c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
  1727             c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
  1728             c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
  1729             is.reset();
  1730             return true;
  1731         }
  1732         is.reset();
  1733         return false;
  1734     }
  1735 
  1736     /**
  1737      * Tries to read the specified number of bytes from the stream
  1738      * Returns -1, If EOF is reached before len bytes are read, returns 0
  1739      * otherwise
  1740      */
  1741     static private int readBytes(int c[], int len, InputStream is)
  1742                 throws IOException {
  1743 
  1744         byte buf[] = new byte[len];
  1745         if (is.read(buf, 0, len) < len) {
  1746             return -1;
  1747         }
  1748 
  1749         // fill the passed in int array
  1750         for (int i = 0; i < len; i++) {
  1751              c[i] = buf[i] & 0xff;
  1752         }
  1753         return 0;
  1754     }
  1755 
  1756 
  1757     /**
  1758      * Skips through the specified number of bytes from the stream
  1759      * until either EOF is reached, or the specified
  1760      * number of bytes have been skipped
  1761      */
  1762     static private long skipForward(InputStream is, long toSkip)
  1763                 throws IOException {
  1764 
  1765         long eachSkip = 0;
  1766         long skipped = 0;
  1767 
  1768         while (skipped != toSkip) {
  1769             eachSkip = is.skip(toSkip - skipped);
  1770 
  1771             // check if EOF is reached
  1772             if (eachSkip <= 0) {
  1773                 if (is.read() == -1) {
  1774                     return skipped ;
  1775                 } else {
  1776                     skipped++;
  1777                 }
  1778             }
  1779             skipped += eachSkip;
  1780         }
  1781         return skipped;
  1782     }
  1783 
  1784 }
  1785 
  1786 
  1787 class UnknownContentHandler extends ContentHandler {
  1788     static final ContentHandler INSTANCE = new UnknownContentHandler();
  1789 
  1790     public Object getContent(URLConnection uc) throws IOException {
  1791         return uc.getInputStream();
  1792     }
  1793 }
  1794 
  1795 /** An RFC 844 or MIME message header.  Includes methods
  1796     for parsing headers from incoming streams, fetching
  1797     values, setting values, and printing headers.
  1798     Key values of null are legal: they indicate lines in
  1799     the header that don't have a valid key, but do have
  1800     a value (this isn't legal according to the standard,
  1801     but lines like this are everywhere). */
  1802 class MessageHeader {
  1803     private String keys[];
  1804     private String values[];
  1805     private int nkeys;
  1806 
  1807     public MessageHeader () {
  1808         grow();
  1809     }
  1810 
  1811     public MessageHeader (InputStream is) throws java.io.IOException {
  1812         parseHeader(is);
  1813     }
  1814 
  1815     /**
  1816      * Reset a message header (all key/values removed)
  1817      */
  1818     public synchronized void reset() {
  1819         keys = null;
  1820         values = null;
  1821         nkeys = 0;
  1822         grow();
  1823     }
  1824 
  1825     /**
  1826      * Find the value that corresponds to this key.
  1827      * It finds only the first occurrence of the key.
  1828      * @param k the key to find.
  1829      * @return null if not found.
  1830      */
  1831     public synchronized String findValue(String k) {
  1832         if (k == null) {
  1833             for (int i = nkeys; --i >= 0;)
  1834                 if (keys[i] == null)
  1835                     return values[i];
  1836         } else
  1837             for (int i = nkeys; --i >= 0;) {
  1838                 if (k.equalsIgnoreCase(keys[i]))
  1839                     return values[i];
  1840             }
  1841         return null;
  1842     }
  1843 
  1844     // return the location of the key
  1845     public synchronized int getKey(String k) {
  1846         for (int i = nkeys; --i >= 0;)
  1847             if ((keys[i] == k) ||
  1848                 (k != null && k.equalsIgnoreCase(keys[i])))
  1849                 return i;
  1850         return -1;
  1851     }
  1852 
  1853     public synchronized String getKey(int n) {
  1854         if (n < 0 || n >= nkeys) return null;
  1855         return keys[n];
  1856     }
  1857 
  1858     public synchronized String getValue(int n) {
  1859         if (n < 0 || n >= nkeys) return null;
  1860         return values[n];
  1861     }
  1862 
  1863     /** Deprecated: Use multiValueIterator() instead.
  1864      *
  1865      *  Find the next value that corresponds to this key.
  1866      *  It finds the first value that follows v. To iterate
  1867      *  over all the values of a key use:
  1868      *  <pre>
  1869      *          for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) {
  1870      *              ...
  1871      *          }
  1872      *  </pre>
  1873      */
  1874     public synchronized String findNextValue(String k, String v) {
  1875         boolean foundV = false;
  1876         if (k == null) {
  1877             for (int i = nkeys; --i >= 0;)
  1878                 if (keys[i] == null)
  1879                     if (foundV)
  1880                         return values[i];
  1881                     else if (values[i] == v)
  1882                         foundV = true;
  1883         } else
  1884             for (int i = nkeys; --i >= 0;)
  1885                 if (k.equalsIgnoreCase(keys[i]))
  1886                     if (foundV)
  1887                         return values[i];
  1888                     else if (values[i] == v)
  1889                         foundV = true;
  1890         return null;
  1891     }
  1892 
  1893     class HeaderIterator implements Iterator<String> {
  1894         int index = 0;
  1895         int next = -1;
  1896         String key;
  1897         boolean haveNext = false;
  1898         Object lock;
  1899 
  1900         public HeaderIterator (String k, Object lock) {
  1901             key = k;
  1902             this.lock = lock;
  1903         }
  1904         public boolean hasNext () {
  1905             synchronized (lock) {
  1906                 if (haveNext) {
  1907                     return true;
  1908                 }
  1909                 while (index < nkeys) {
  1910                     if (key.equalsIgnoreCase (keys[index])) {
  1911                         haveNext = true;
  1912                         next = index++;
  1913                         return true;
  1914                     }
  1915                     index ++;
  1916                 }
  1917                 return false;
  1918             }
  1919         }
  1920         public String next() {
  1921             synchronized (lock) {
  1922                 if (haveNext) {
  1923                     haveNext = false;
  1924                     return values [next];
  1925                 }
  1926                 if (hasNext()) {
  1927                     return next();
  1928                 } else {
  1929                     throw new NoSuchElementException ("No more elements");
  1930                 }
  1931             }
  1932         }
  1933         public void remove () {
  1934             throw new UnsupportedOperationException ("remove not allowed");
  1935         }
  1936     }
  1937 
  1938     /**
  1939      * return an Iterator that returns all values of a particular
  1940      * key in sequence
  1941      */
  1942     public Iterator<String> multiValueIterator (String k) {
  1943         return new HeaderIterator (k, this);
  1944     }
  1945 
  1946     public synchronized Map<String, List<String>> getHeaders() {
  1947         return getHeaders(null);
  1948     }
  1949 
  1950     public synchronized Map<String, List<String>> getHeaders(String[] excludeList) {
  1951         return filterAndAddHeaders(excludeList, null);
  1952     }
  1953 
  1954     public synchronized Map<String, List<String>> filterAndAddHeaders(String[] excludeList, Map<String, List<String>>  include) {
  1955         boolean skipIt = false;
  1956         Map<String, List<String>> m = new HashMap<String, List<String>>();
  1957         for (int i = nkeys; --i >= 0;) {
  1958             if (excludeList != null) {
  1959                 // check if the key is in the excludeList.
  1960                 // if so, don't include it in the Map.
  1961                 for (int j = 0; j < excludeList.length; j++) {
  1962                     if ((excludeList[j] != null) &&
  1963                         (excludeList[j].equalsIgnoreCase(keys[i]))) {
  1964                         skipIt = true;
  1965                         break;
  1966                     }
  1967                 }
  1968             }
  1969             if (!skipIt) {
  1970                 List<String> l = m.get(keys[i]);
  1971                 if (l == null) {
  1972                     l = new ArrayList<String>();
  1973                     m.put(keys[i], l);
  1974                 }
  1975                 l.add(values[i]);
  1976             } else {
  1977                 // reset the flag
  1978                 skipIt = false;
  1979             }
  1980         }
  1981 
  1982         if (include != null) {
  1983             Iterator entries = include.entrySet().iterator();
  1984             while (entries.hasNext()) {
  1985                 Map.Entry entry = (Map.Entry)entries.next();
  1986                 List l = (List)m.get(entry.getKey());
  1987                 if (l == null) {
  1988                     l = new ArrayList();
  1989                     m.put((String)entry.getKey(), l);
  1990                 }
  1991                 l.add(entry.getValue());
  1992             }
  1993         }
  1994 
  1995         for (String key : m.keySet()) {
  1996             m.put(key, Collections.unmodifiableList(m.get(key)));
  1997         }
  1998 
  1999         return Collections.unmodifiableMap(m);
  2000     }
  2001 
  2002     /** Prints the key-value pairs represented by this
  2003         header.  Also prints the RFC required blank line
  2004         at the end. Omits pairs with a null key. */
  2005     public synchronized void print(PrintStream p) {
  2006         for (int i = 0; i < nkeys; i++)
  2007             if (keys[i] != null) {
  2008                 p.print(keys[i] +
  2009                     (values[i] != null ? ": "+values[i]: "") + "\r\n");
  2010             }
  2011         p.print("\r\n");
  2012         p.flush();
  2013     }
  2014 
  2015     /** Adds a key value pair to the end of the
  2016         header.  Duplicates are allowed */
  2017     public synchronized void add(String k, String v) {
  2018         grow();
  2019         keys[nkeys] = k;
  2020         values[nkeys] = v;
  2021         nkeys++;
  2022     }
  2023 
  2024     /** Prepends a key value pair to the beginning of the
  2025         header.  Duplicates are allowed */
  2026     public synchronized void prepend(String k, String v) {
  2027         grow();
  2028         for (int i = nkeys; i > 0; i--) {
  2029             keys[i] = keys[i-1];
  2030             values[i] = values[i-1];
  2031         }
  2032         keys[0] = k;
  2033         values[0] = v;
  2034         nkeys++;
  2035     }
  2036 
  2037     /** Overwrite the previous key/val pair at location 'i'
  2038      * with the new k/v.  If the index didn't exist before
  2039      * the key/val is simply tacked onto the end.
  2040      */
  2041 
  2042     public synchronized void set(int i, String k, String v) {
  2043         grow();
  2044         if (i < 0) {
  2045             return;
  2046         } else if (i >= nkeys) {
  2047             add(k, v);
  2048         } else {
  2049             keys[i] = k;
  2050             values[i] = v;
  2051         }
  2052     }
  2053 
  2054 
  2055     /** grow the key/value arrays as needed */
  2056 
  2057     private void grow() {
  2058         if (keys == null || nkeys >= keys.length) {
  2059             String[] nk = new String[nkeys + 4];
  2060             String[] nv = new String[nkeys + 4];
  2061             if (keys != null)
  2062                 System.arraycopy(keys, 0, nk, 0, nkeys);
  2063             if (values != null)
  2064                 System.arraycopy(values, 0, nv, 0, nkeys);
  2065             keys = nk;
  2066             values = nv;
  2067         }
  2068     }
  2069 
  2070     /**
  2071      * Remove the key from the header. If there are multiple values under
  2072      * the same key, they are all removed.
  2073      * Nothing is done if the key doesn't exist.
  2074      * After a remove, the other pairs' order are not changed.
  2075      * @param k the key to remove
  2076      */
  2077     public synchronized void remove(String k) {
  2078         if(k == null) {
  2079             for (int i = 0; i < nkeys; i++) {
  2080                 while (keys[i] == null && i < nkeys) {
  2081                     for(int j=i; j<nkeys-1; j++) {
  2082                         keys[j] = keys[j+1];
  2083                         values[j] = values[j+1];
  2084                     }
  2085                     nkeys--;
  2086                 }
  2087             }
  2088         } else {
  2089             for (int i = 0; i < nkeys; i++) {
  2090                 while (k.equalsIgnoreCase(keys[i]) && i < nkeys) {
  2091                     for(int j=i; j<nkeys-1; j++) {
  2092                         keys[j] = keys[j+1];
  2093                         values[j] = values[j+1];
  2094                     }
  2095                     nkeys--;
  2096                 }
  2097             }
  2098         }
  2099     }
  2100 
  2101     /** Sets the value of a key.  If the key already
  2102         exists in the header, it's value will be
  2103         changed.  Otherwise a new key/value pair will
  2104         be added to the end of the header. */
  2105     public synchronized void set(String k, String v) {
  2106         for (int i = nkeys; --i >= 0;)
  2107             if (k.equalsIgnoreCase(keys[i])) {
  2108                 values[i] = v;
  2109                 return;
  2110             }
  2111         add(k, v);
  2112     }
  2113 
  2114     /** Set's the value of a key only if there is no
  2115      *  key with that value already.
  2116      */
  2117 
  2118     public synchronized void setIfNotSet(String k, String v) {
  2119         if (findValue(k) == null) {
  2120             add(k, v);
  2121         }
  2122     }
  2123 
  2124     /** Convert a message-id string to canonical form (strips off
  2125         leading and trailing <>s) */
  2126     public static String canonicalID(String id) {
  2127         if (id == null)
  2128             return "";
  2129         int st = 0;
  2130         int len = id.length();
  2131         boolean substr = false;
  2132         int c;
  2133         while (st < len && ((c = id.charAt(st)) == '<' ||
  2134                             c <= ' ')) {
  2135             st++;
  2136             substr = true;
  2137         }
  2138         while (st < len && ((c = id.charAt(len - 1)) == '>' ||
  2139                             c <= ' ')) {
  2140             len--;
  2141             substr = true;
  2142         }
  2143         return substr ? id.substring(st, len) : id;
  2144     }
  2145 
  2146     /** Parse a MIME header from an input stream. */
  2147     public void parseHeader(InputStream is) throws java.io.IOException {
  2148         synchronized (this) {
  2149             nkeys = 0;
  2150         }
  2151         mergeHeader(is);
  2152     }
  2153 
  2154     /** Parse and merge a MIME header from an input stream. */
  2155     public void mergeHeader(InputStream is) throws java.io.IOException {
  2156         if (is == null)
  2157             return;
  2158         char s[] = new char[10];
  2159         int firstc = is.read();
  2160         while (firstc != '\n' && firstc != '\r' && firstc >= 0) {
  2161             int len = 0;
  2162             int keyend = -1;
  2163             int c;
  2164             boolean inKey = firstc > ' ';
  2165             s[len++] = (char) firstc;
  2166     parseloop:{
  2167                 while ((c = is.read()) >= 0) {
  2168                     switch (c) {
  2169                       case ':':
  2170                         if (inKey && len > 0)
  2171                             keyend = len;
  2172                         inKey = false;
  2173                         break;
  2174                       case '\t':
  2175                         c = ' ';
  2176                       case ' ':
  2177                         inKey = false;
  2178                         break;
  2179                       case '\r':
  2180                       case '\n':
  2181                         firstc = is.read();
  2182                         if (c == '\r' && firstc == '\n') {
  2183                             firstc = is.read();
  2184                             if (firstc == '\r')
  2185                                 firstc = is.read();
  2186                         }
  2187                         if (firstc == '\n' || firstc == '\r' || firstc > ' ')
  2188                             break parseloop;
  2189                         /* continuation */
  2190                         c = ' ';
  2191                         break;
  2192                     }
  2193                     if (len >= s.length) {
  2194                         char ns[] = new char[s.length * 2];
  2195                         System.arraycopy(s, 0, ns, 0, len);
  2196                         s = ns;
  2197                     }
  2198                     s[len++] = (char) c;
  2199                 }
  2200                 firstc = -1;
  2201             }
  2202             while (len > 0 && s[len - 1] <= ' ')
  2203                 len--;
  2204             String k;
  2205             if (keyend <= 0) {
  2206                 k = null;
  2207                 keyend = 0;
  2208             } else {
  2209                 k = String.copyValueOf(s, 0, keyend);
  2210                 if (keyend < len && s[keyend] == ':')
  2211                     keyend++;
  2212                 while (keyend < len && s[keyend] <= ' ')
  2213                     keyend++;
  2214             }
  2215             String v;
  2216             if (keyend >= len)
  2217                 v = new String();
  2218             else
  2219                 v = String.copyValueOf(s, keyend, len - keyend);
  2220             add(k, v);
  2221         }
  2222     }
  2223 
  2224     public synchronized String toString() {
  2225         String result = super.toString() + nkeys + " pairs: ";
  2226         for (int i = 0; i < keys.length && i < nkeys; i++) {
  2227             result += "{"+keys[i]+": "+values[i]+"}";
  2228         }
  2229         return result;
  2230     }
  2231 }
  2232 
  2233 interface ContentHandlerFactory {
  2234 
  2235     public ContentHandler createContentHandler(String contentType);
  2236 }
  2237 
  2238 abstract class ContentHandler {
  2239     /**
  2240      * Given a URL connect stream positioned at the beginning of the
  2241      * representation of an object, this method reads that stream and
  2242      * creates an object from it.
  2243      *
  2244      * @param      urlc   a URL connection.
  2245      * @return     the object read by the <code>ContentHandler</code>.
  2246      * @exception  IOException  if an I/O error occurs while reading the object.
  2247      */
  2248     abstract public Object getContent(URLConnection urlc) throws IOException;
  2249 
  2250     /**
  2251      * Given a URL connect stream positioned at the beginning of the
  2252      * representation of an object, this method reads that stream and
  2253      * creates an object that matches one of the types specified.
  2254      *
  2255      * The default implementation of this method should call getContent()
  2256      * and screen the return type for a match of the suggested types.
  2257      *
  2258      * @param      urlc   a URL connection.
  2259      * @param      classes      an array of types requested
  2260      * @return     the object read by the <code>ContentHandler</code> that is
  2261      *                 the first match of the suggested types.
  2262      *                 null if none of the requested  are supported.
  2263      * @exception  IOException  if an I/O error occurs while reading the object.
  2264      * @since 1.3
  2265      */
  2266     public Object getContent(URLConnection urlc, Class[] classes) throws IOException {
  2267         Object obj = getContent(urlc);
  2268 
  2269         for (int i = 0; i < classes.length; i++) {
  2270           if (classes[i].isInstance(obj)) {
  2271                 return obj;
  2272           }
  2273         }
  2274         return null;
  2275     }
  2276 
  2277 }
  2278 class UnknownServiceException extends IOException {
  2279     private static final long serialVersionUID = -4169033248853639508L;
  2280 
  2281     /**
  2282      * Constructs a new <code>UnknownServiceException</code> with no
  2283      * detail message.
  2284      */
  2285     public UnknownServiceException() {
  2286     }
  2287 
  2288     /**
  2289      * Constructs a new <code>UnknownServiceException</code> with the
  2290      * specified detail message.
  2291      *
  2292      * @param   msg   the detail message.
  2293      */
  2294     public UnknownServiceException(String msg) {
  2295         super(msg);
  2296     }
  2297 }
  2298 /**
  2299  * A simple interface which provides a mechanism to map
  2300  * between a file name and a MIME type string.
  2301  *
  2302  * @author  Steven B. Byrne
  2303  * @since   JDK1.1
  2304  */
  2305 interface FileNameMap {
  2306 
  2307     /**
  2308      * Gets the MIME type for the specified file name.
  2309      * @param fileName the specified file name
  2310      * @return a <code>String</code> indicating the MIME
  2311      * type for the specified file name.
  2312      */
  2313     public String getContentTypeFor(String fileName);
  2314 }