KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > net > URLConnection


1 /*
2  * @(#)URLConnection.java 1.102 04/05/18
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.net;
9
10 import java.io.IOException JavaDoc;
11 import java.io.InputStream JavaDoc;
12 import java.io.OutputStream JavaDoc;
13 import java.util.Hashtable JavaDoc;
14 import java.util.Date JavaDoc;
15 import java.util.StringTokenizer JavaDoc;
16 import java.util.Collections JavaDoc;
17 import java.util.Map JavaDoc;
18 import java.util.List JavaDoc;
19 import java.security.Permission JavaDoc;
20 import java.security.AccessController JavaDoc;
21 import sun.security.util.SecurityConstants;
22
23 /**
24  * The abstract class <code>URLConnection</code> is the superclass
25  * of all classes that represent a communications link between the
26  * application and a URL. Instances of this class can be used both to
27  * read from and to write to the resource referenced by the URL. In
28  * general, creating a connection to a URL is a multistep process:
29  * <p>
30  * <center><table border=2 summary="Describes the process of creating a connection to a URL: openConnection() and connect() over time.">
31  * <tr><th><code>openConnection()</code></th>
32  * <th><code>connect()</code></th></tr>
33  * <tr><td>Manipulate parameters that affect the connection to the remote
34  * resource.</td>
35  * <td>Interact with the resource; query header fields and
36  * contents.</td></tr>
37  * </table>
38  * ----------------------------&gt;
39  * <br>time</center>
40  *
41  * <ol>
42  * <li>The connection object is created by invoking the
43  * <code>openConnection</code> method on a URL.
44  * <li>The setup parameters and general request properties are manipulated.
45  * <li>The actual connection to the remote object is made, using the
46  * <code>connect</code> method.
47  * <li>The remote object becomes available. The header fields and the contents
48  * of the remote object can be accessed.
49  * </ol>
50  * <p>
51  * The setup parameters are modified using the following methods:
52  * <ul>
53  * <li><code>setAllowUserInteraction</code>
54  * <li><code>setDoInput</code>
55  * <li><code>setDoOutput</code>
56  * <li><code>setIfModifiedSince</code>
57  * <li><code>setUseCaches</code>
58  * </ul>
59  * <p>
60  * and the general request properties are modified using the method:
61  * <ul>
62  * <li><code>setRequestProperty</code>
63  * </ul>
64  * <p>
65  * Default values for the <code>AllowUserInteraction</code> and
66  * <code>UseCaches</code> parameters can be set using the methods
67  * <code>setDefaultAllowUserInteraction</code> and
68  * <code>setDefaultUseCaches</code>.
69  * <p>
70  * Each of the above <code>set</code> methods has a corresponding
71  * <code>get</code> method to retrieve the value of the parameter or
72  * general request property. The specific parameters and general
73  * request properties that are applicable are protocol specific.
74  * <p>
75  * The following methods are used to access the header fields and
76  * the contents after the connection is made to the remote object:
77  * <ul>
78  * <li><code>getContent</code>
79  * <li><code>getHeaderField</code>
80  * <li><code>getInputStream</code>
81  * <li><code>getOutputStream</code>
82  * </ul>
83  * <p>
84  * Certain header fields are accessed frequently. The methods:
85  * <ul>
86  * <li><code>getContentEncoding</code>
87  * <li><code>getContentLength</code>
88  * <li><code>getContentType</code>
89  * <li><code>getDate</code>
90  * <li><code>getExpiration</code>
91  * <li><code>getLastModifed</code>
92  * </ul>
93  * <p>
94  * provide convenient access to these fields. The
95  * <code>getContentType</code> method is used by the
96  * <code>getContent</code> method to determine the type of the remote
97  * object; subclasses may find it convenient to override the
98  * <code>getContentType</code> method.
99  * <p>
100  * In the common case, all of the pre-connection parameters and
101  * general request properties can be ignored: the pre-connection
102  * parameters and request properties default to sensible values. For
103  * most clients of this interface, there are only two interesting
104  * methods: <code>getInputStream</code> and <code>getContent</code>,
105  * which are mirrored in the <code>URL</code> class by convenience methods.
106  * <p>
107  * More information on the request properties and header fields of
108  * an <code>http</code> connection can be found at:
109  * <blockquote><pre>
110  * <a HREF="http://www.ietf.org/rfc/rfc2068.txt">http://www.ietf.org/rfc/rfc2068.txt</a>
111  * </pre></blockquote>
112  *
113  * Note about <code>fileNameMap</code>: In versions prior to JDK 1.1.6,
114  * field <code>fileNameMap</code> of <code>URLConnection</code> was public.
115  * In JDK 1.1.6 and later, <code>fileNameMap</code> is private; accessor
116  * and mutator methods {@link #getFileNameMap() getFileNameMap} and
117  * {@link #setFileNameMap(java.net.FileNameMap) setFileNameMap} are added
118  * to access it. This change is also described on the <a HREF=
119  * "http://java.sun.com/products/jdk/1.2/compatibility.html#incompatibilities1.2">
120  * Compatibility</a> page.
121  *
122  * Invoking the <tt>close()</tt> methods on the <tt>InputStream</tt> or <tt>OutputStream</tt> of an
123  * <tt>URLConnection</tt> after a request may free network resources associated with this
124  * instance, unless particular protocol specifications specify different behaviours
125  * for it.
126  *
127  * @author James Gosling
128  * @version 1.102, 05/18/04
129  * @see java.net.URL#openConnection()
130  * @see java.net.URLConnection#connect()
131  * @see java.net.URLConnection#getContent()
132  * @see java.net.URLConnection#getContentEncoding()
133  * @see java.net.URLConnection#getContentLength()
134  * @see java.net.URLConnection#getContentType()
135  * @see java.net.URLConnection#getDate()
136  * @see java.net.URLConnection#getExpiration()
137  * @see java.net.URLConnection#getHeaderField(int)
138  * @see java.net.URLConnection#getHeaderField(java.lang.String)
139  * @see java.net.URLConnection#getInputStream()
140  * @see java.net.URLConnection#getLastModified()
141  * @see java.net.URLConnection#getOutputStream()
142  * @see java.net.URLConnection#setAllowUserInteraction(boolean)
143  * @see java.net.URLConnection#setDefaultUseCaches(boolean)
144  * @see java.net.URLConnection#setDoInput(boolean)
145  * @see java.net.URLConnection#setDoOutput(boolean)
146  * @see java.net.URLConnection#setIfModifiedSince(long)
147  * @see java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String)
148  * @see java.net.URLConnection#setUseCaches(boolean)
149  * @since JDK1.0
150  */

151 public abstract class URLConnection {
152
153    /**
154      * The URL represents the remote object on the World Wide Web to
155      * which this connection is opened.
156      * <p>
157      * The value of this field can be accessed by the
158      * <code>getURL</code> method.
159      * <p>
160      * The default value of this variable is the value of the URL
161      * argument in the <code>URLConnection</code> constructor.
162      *
163      * @see java.net.URLConnection#getURL()
164      * @see java.net.URLConnection#url
165      */

166     protected URL JavaDoc url;
167
168    /**
169      * This variable is set by the <code>setDoInput</code> method. Its
170      * value is returned by the <code>getDoInput</code> method.
171      * <p>
172      * A URL connection can be used for input and/or output. Setting the
173      * <code>doInput</code> flag to <code>true</code> indicates that
174      * the application intends to read data from the URL connection.
175      * <p>
176      * The default value of this field is <code>true</code>.
177      *
178      * @see java.net.URLConnection#getDoInput()
179      * @see java.net.URLConnection#setDoInput(boolean)
180      */

181     protected boolean doInput = true;
182
183    /**
184      * This variable is set by the <code>setDoOutput</code> method. Its
185      * value is returned by the <code>getDoOutput</code> method.
186      * <p>
187      * A URL connection can be used for input and/or output. Setting the
188      * <code>doOutput</code> flag to <code>true</code> indicates
189      * that the application intends to write data to the URL connection.
190      * <p>
191      * The default value of this field is <code>false</code>.
192      *
193      * @see java.net.URLConnection#getDoOutput()
194      * @see java.net.URLConnection#setDoOutput(boolean)
195      */

196     protected boolean doOutput = false;
197
198     private static boolean defaultAllowUserInteraction = false;
199
200    /**
201      * If <code>true</code>, this <code>URL</code> is being examined in
202      * a context in which it makes sense to allow user interactions such
203      * as popping up an authentication dialog. If <code>false</code>,
204      * then no user interaction is allowed.
205      * <p>
206      * The value of this field can be set by the
207      * <code>setAllowUserInteraction</code> method.
208      * Its value is returned by the
209      * <code>getAllowUserInteraction</code> method.
210      * Its default value is the value of the argument in the last invocation
211      * of the <code>setDefaultAllowUserInteraction</code> method.
212      *
213      * @see java.net.URLConnection#getAllowUserInteraction()
214      * @see java.net.URLConnection#setAllowUserInteraction(boolean)
215      * @see java.net.URLConnection#setDefaultAllowUserInteraction(boolean)
216      */

217     protected boolean allowUserInteraction = defaultAllowUserInteraction;
218
219     private static boolean defaultUseCaches = true;
220
221    /**
222      * If <code>true</code>, the protocol is allowed to use caching
223      * whenever it can. If <code>false</code>, the protocol must always
224      * try to get a fresh copy of the object.
225      * <p>
226      * This field is set by the <code>setUseCaches</code> method. Its
227      * value is returned by the <code>getUseCaches</code> method.
228      * <p>
229      * Its default value is the value given in the last invocation of the
230      * <code>setDefaultUseCaches</code> method.
231      *
232      * @see java.net.URLConnection#setUseCaches(boolean)
233      * @see java.net.URLConnection#getUseCaches()
234      * @see java.net.URLConnection#setDefaultUseCaches(boolean)
235      */

236     protected boolean useCaches = defaultUseCaches;
237
238    /**
239      * Some protocols support skipping the fetching of the object unless
240      * the object has been modified more recently than a certain time.
241      * <p>
242      * A nonzero value gives a time as the number of milliseconds since
243      * January 1, 1970, GMT. The object is fetched only if it has been
244      * modified more recently than that time.
245      * <p>
246      * This variable is set by the <code>setIfModifiedSince</code>
247      * method. Its value is returned by the
248      * <code>getIfModifiedSince</code> method.
249      * <p>
250      * The default value of this field is <code>0</code>, indicating
251      * that the fetching must always occur.
252      *
253      * @see java.net.URLConnection#getIfModifiedSince()
254      * @see java.net.URLConnection#setIfModifiedSince(long)
255      */

256     protected long ifModifiedSince = 0;
257
258    /**
259      * If <code>false</code>, this connection object has not created a
260      * communications link to the specified URL. If <code>true</code>,
261      * the communications link has been established.
262      */

263     protected boolean connected = false;
264
265     /**
266      * @since 1.5
267      */

268     private int connectTimeout;
269     private int readTimeout;
270
271    /**
272     * @since JDK1.1
273     */

274     private static FileNameMap JavaDoc fileNameMap;
275
276     /**
277      * @since 1.2.2
278      */

279     private static boolean fileNameMapLoaded = false;
280
281     /**
282      * Loads filename map (a mimetable) from a data file. It will
283      * first try to load the user-specific table, defined
284      * by &quot;content.types.user.table&quot; property. If that fails,
285      * it tries to load the default built-in table at
286      * lib/content-types.properties under java home.
287      *
288      * @return the FileNameMap
289      * @since 1.2
290      * @see #setFileNameMap(java.net.FileNameMap)
291      */

292     public static synchronized FileNameMap JavaDoc getFileNameMap() {
293     if ((fileNameMap == null) && !fileNameMapLoaded) {
294         fileNameMap = sun.net.www.MimeTable.loadTable();
295         fileNameMapLoaded = true;
296     }
297
298     return new FileNameMap JavaDoc() {
299         private FileNameMap JavaDoc map = fileNameMap;
300         public String JavaDoc getContentTypeFor(String JavaDoc fileName) {
301         return map.getContentTypeFor(fileName);
302         }
303     };
304     }
305
306     /**
307      * Sets the FileNameMap.
308      * <p>
309      * If there is a security manager, this method first calls
310      * the security manager's <code>checkSetFactory</code> method
311      * to ensure the operation is allowed.
312      * This could result in a SecurityException.
313      *
314      * @param map the FileNameMap to be set
315      * @exception SecurityException if a security manager exists and its
316      * <code>checkSetFactory</code> method doesn't allow the operation.
317      * @see SecurityManager#checkSetFactory
318      * @see #getFileNameMap()
319      * @since 1.2
320      */

321     public static void setFileNameMap(FileNameMap JavaDoc map) {
322     SecurityManager JavaDoc sm = System.getSecurityManager();
323     if (sm != null) sm.checkSetFactory();
324     fileNameMap = map;
325     }
326
327     /**
328      * Opens a communications link to the resource referenced by this
329      * URL, if such a connection has not already been established.
330      * <p>
331      * If the <code>connect</code> method is called when the connection
332      * has already been opened (indicated by the <code>connected</code>
333      * field having the value <code>true</code>), the call is ignored.
334      * <p>
335      * URLConnection objects go through two phases: first they are
336      * created, then they are connected. After being created, and
337      * before being connected, various options can be specified
338      * (e.g., doInput and UseCaches). After connecting, it is an
339      * error to try to set them. Operations that depend on being
340      * connected, like getContentLength, will implicitly perform the
341      * connection, if necessary.
342      *
343      * @throws SocketTimeoutException if the timeout expires before
344      * the connection can be established
345      * @exception IOException if an I/O error occurs while opening the
346      * connection.
347      * @see java.net.URLConnection#connected
348      * @see #getConnectTimeout()
349      * @see #setConnectTimeout(int)
350      */

351     abstract public void connect() throws IOException JavaDoc;
352
353     /**
354      * Sets a specified timeout value, in milliseconds, to be used
355      * when opening a communications link to the resource referenced
356      * by this URLConnection. If the timeout expires before the
357      * connection can be established, a
358      * java.net.SocketTimeoutException is raised. A timeout of zero is
359      * interpreted as an infinite timeout.
360
361      * <p> Some non-standard implmentation of this method may ignore
362      * the specified timeout. To see the connect timeout set, please
363      * call getConnectTimeout().
364      *
365      * @param timeout an <code>int</code> that specifies the connect
366      * timeout value in milliseconds
367      * @throws IllegalArgumentException if the timeout parameter is negative
368      *
369      * @see #getConnectTimeout()
370      * @see #connect()
371      * @since 1.5
372      */

373     public void setConnectTimeout(int timeout) {
374     if (timeout < 0) {
375         throw new IllegalArgumentException JavaDoc("timeout can not be negative");
376     }
377     connectTimeout = timeout;
378     }
379
380     /**
381      * Returns setting for connect timeout.
382      * <p>
383      * 0 return implies that the option is disabled
384      * (i.e., timeout of infinity).
385      *
386      * @return an <code>int</code> that indicates the connect timeout
387      * value in milliseconds
388      * @see #setConnectTimeout(int)
389      * @see #connect()
390      * @since 1.5
391      */

392     public int getConnectTimeout() {
393     return connectTimeout;
394     }
395
396     /**
397      * Sets the read timeout to a specified timeout, in
398      * milliseconds. A non-zero value specifies the timeout when
399      * reading from Input stream when a connection is established to a
400      * resource. If the timeout expires before there is data available
401      * for read, a java.net.SocketTimeoutException is raised. A
402      * timeout of zero is interpreted as an infinite timeout.
403      *
404      *<p> Some non-standard implementation of this method ignores the
405      * specified timeout. To see the read timeout set, please call
406      * getReadTimeout().
407      *
408      * @param timeout an <code>int</code> that specifies the timeout
409      * value to be used in milliseconds
410      * @throws IllegalArgumentException if the timeout parameter is negative
411      *
412      * @see #getReadTimeout()
413      * @see InputStream#read()
414      * @since 1.5
415      */

416     public void setReadTimeout(int timeout) {
417     if (timeout < 0) {
418         throw new IllegalArgumentException JavaDoc("timeout can not be negative");
419     }
420     readTimeout = timeout;
421     }
422
423     /**
424      * Returns setting for read timeout. 0 return implies that the
425      * option is disabled (i.e., timeout of infinity).
426      *
427      * @return an <code>int</code> that indicates the read timeout
428      * value in milliseconds
429      *
430      * @see #setReadTimeout(int)
431      * @see InputStream#read()
432      * @since 1.5
433      */

434     public int getReadTimeout() {
435     return readTimeout;
436     }
437
438     /**
439      * Constructs a URL connection to the specified URL. A connection to
440      * the object referenced by the URL is not created.
441      *
442      * @param url the specified URL.
443      */

444     protected URLConnection(URL JavaDoc url) {
445     this.url = url;
446     }
447
448     /**
449      * Returns the value of this <code>URLConnection</code>'s <code>URL</code>
450      * field.
451      *
452      * @return the value of this <code>URLConnection</code>'s <code>URL</code>
453      * field.
454      * @see java.net.URLConnection#url
455      */

456     public URL JavaDoc getURL() {
457     return url;
458     }
459
460     /**
461      * Returns the value of the <code>content-length</code> header field.
462      *
463      * @return the content length of the resource that this connection's URL
464      * references, or <code>-1</code> if the content length is
465      * not known.
466      */

467     public int getContentLength() {
468     return getHeaderFieldInt("content-length", -1);
469     }
470
471     /**
472      * Returns the value of the <code>content-type</code> header field.
473      *
474      * @return the content type of the resource that the URL references,
475      * or <code>null</code> if not known.
476      * @see java.net.URLConnection#getHeaderField(java.lang.String)
477      */

478     public String JavaDoc getContentType() {
479     return getHeaderField("content-type");
480     }
481
482     /**
483      * Returns the value of the <code>content-encoding</code> header field.
484      *
485      * @return the content encoding of the resource that the URL references,
486      * or <code>null</code> if not known.
487      * @see java.net.URLConnection#getHeaderField(java.lang.String)
488      */

489     public String JavaDoc getContentEncoding() {
490     return getHeaderField("content-encoding");
491     }
492
493     /**
494      * Returns the value of the <code>expires</code> header field.
495      *
496      * @return the expiration date of the resource that this URL references,
497      * or 0 if not known. The value is the number of milliseconds since
498      * January 1, 1970 GMT.
499      * @see java.net.URLConnection#getHeaderField(java.lang.String)
500      */

501     public long getExpiration() {
502     return getHeaderFieldDate("expires", 0);
503     }
504
505     /**
506      * Returns the value of the <code>date</code> header field.
507      *
508      * @return the sending date of the resource that the URL references,
509      * or <code>0</code> if not known. The value returned is the
510      * number of milliseconds since January 1, 1970 GMT.
511      * @see java.net.URLConnection#getHeaderField(java.lang.String)
512      */

513     public long getDate() {
514     return getHeaderFieldDate("date", 0);
515     }
516
517     /**
518      * Returns the value of the <code>last-modified</code> header field.
519      * The result is the number of milliseconds since January 1, 1970 GMT.
520      *
521      * @return the date the resource referenced by this
522      * <code>URLConnection</code> was last modified, or 0 if not known.
523      * @see java.net.URLConnection#getHeaderField(java.lang.String)
524      */

525     public long getLastModified() {
526     return getHeaderFieldDate("last-modified", 0);
527     }
528
529     /**
530      * Returns the value of the named header field.
531      * <p>
532      * If called on a connection that sets the same header multiple times
533      * with possibly different values, only the last value is returned.
534      *
535      *
536      * @param name the name of a header field.
537      * @return the value of the named header field, or <code>null</code>
538      * if there is no such field in the header.
539      */

540     public String JavaDoc getHeaderField(String JavaDoc name) {
541     return null;
542     }
543
544     /**
545      * Returns an unmodifiable Map of the header fields.
546      * The Map keys are Strings that represent the
547      * response-header field names. Each Map value is an
548      * unmodifiable List of Strings that represents
549      * the corresponding field values.
550      *
551      * @return a Map of header fields
552      * @since 1.4
553      */

554     public Map JavaDoc<String JavaDoc,List JavaDoc<String JavaDoc>> getHeaderFields() {
555         return Collections.EMPTY_MAP;
556     }
557
558     /**
559      * Returns the value of the named field parsed as a number.
560      * <p>
561      * This form of <code>getHeaderField</code> exists because some
562      * connection types (e.g., <code>http-ng</code>) have pre-parsed
563      * headers. Classes for that connection type can override this method
564      * and short-circuit the parsing.
565      *
566      * @param name the name of the header field.
567      * @param Default the default value.
568      * @return the value of the named field, parsed as an integer. The
569      * <code>Default</code> value is returned if the field is
570      * missing or malformed.
571      */

572     public int getHeaderFieldInt(String JavaDoc name, int Default) {
573     String JavaDoc value = getHeaderField(name);
574     try {
575         return Integer.parseInt(value);
576     } catch (Exception JavaDoc e) { }
577     return Default;
578     }
579
580     /**
581      * Returns the value of the named field parsed as date.
582      * The result is the number of milliseconds since January 1, 1970 GMT
583      * represented by the named field.
584      * <p>
585      * This form of <code>getHeaderField</code> exists because some
586      * connection types (e.g., <code>http-ng</code>) have pre-parsed
587      * headers. Classes for that connection type can override this method
588      * and short-circuit the parsing.
589      *
590      * @param name the name of the header field.
591      * @param Default a default value.
592      * @return the value of the field, parsed as a date. The value of the
593      * <code>Default</code> argument is returned if the field is
594      * missing or malformed.
595      */

596     public long getHeaderFieldDate(String JavaDoc name, long Default) {
597     String JavaDoc value = getHeaderField(name);
598     try {
599         return Date.parse(value);
600     } catch (Exception JavaDoc e) { }
601     return Default;
602     }
603
604     /**
605      * Returns the key for the <code>n</code><sup>th</sup> header field.
606      * It returns <code>null</code> if there are fewer than <code>n+1</code> fields.
607      *
608      * @param n an index, where n>=0
609      * @return the key for the <code>n</code><sup>th</sup> header field,
610      * or <code>null</code> if there are fewer than <code>n+1</code>
611      * fields.
612      */

613     public String JavaDoc getHeaderFieldKey(int n) {
614     return null;
615     }
616
617     /**
618      * Returns the value for the <code>n</code><sup>th</sup> header field.
619      * It returns <code>null</code> if there are fewer than
620      * <code>n+1</code>fields.
621      * <p>
622      * This method can be used in conjunction with the
623      * {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all
624      * the headers in the message.
625      *
626      * @param n an index, where n>=0
627      * @return the value of the <code>n</code><sup>th</sup> header field
628      * or <code>null</code> if there are fewer than <code>n+1</code> fields
629      * @see java.net.URLConnection#getHeaderFieldKey(int)
630      */

631     public String JavaDoc getHeaderField(int n) {
632     return null;
633     }
634
635     /**
636      * Retrieves the contents of this URL connection.
637      * <p>
638      * This method first determines the content type of the object by
639      * calling the <code>getContentType</code> method. If this is
640      * the first time that the application has seen that specific content
641      * type, a content handler for that content type is created:
642      * <ol>
643      * <li>If the application has set up a content handler factory instance
644      * using the <code>setContentHandlerFactory</code> method, the
645      * <code>createContentHandler</code> method of that instance is called
646      * with the content type as an argument; the result is a content
647      * handler for that content type.
648      * <li>If no content handler factory has yet been set up, or if the
649      * factory's <code>createContentHandler</code> method returns
650      * <code>null</code>, then the application loads the class named:
651      * <blockquote><pre>
652      * sun.net.www.content.&lt;<i>contentType</i>&gt;
653      * </pre></blockquote>
654      * where &lt;<i>contentType</i>&gt; is formed by taking the
655      * content-type string, replacing all slash characters with a
656      * <code>period</code> ('.'), and all other non-alphanumeric characters
657      * with the underscore character '<code>_</code>'. The alphanumeric
658      * characters are specifically the 26 uppercase ASCII letters
659      * '<code>A</code>' through '<code>Z</code>', the 26 lowercase ASCII
660      * letters '<code>a</code>' through '<code>z</code>', and the 10 ASCII
661      * digits '<code>0</code>' through '<code>9</code>'. If the specified
662      * class does not exist, or is not a subclass of
663      * <code>ContentHandler</code>, then an
664      * <code>UnknownServiceException</code> is thrown.
665      * </ol>
666      *
667      * @return the object fetched. The <code>instanceof</code> operator
668      * should be used to determine the specific kind of object
669      * returned.
670      * @exception IOException if an I/O error occurs while
671      * getting the content.
672      * @exception UnknownServiceException if the protocol does not support
673      * the content type.
674      * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
675      * @see java.net.URLConnection#getContentType()
676      * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
677      */

678     public Object JavaDoc getContent() throws IOException JavaDoc {
679         // Must call getInputStream before GetHeaderField gets called
680
// so that FileNotFoundException has a chance to be thrown up
681
// from here without being caught.
682
getInputStream();
683     return getContentHandler().getContent(this);
684     }
685
686     /**
687      * Retrieves the contents of this URL connection.
688      *
689      * @param classes the <code>Class</code> array
690      * indicating the requested types
691      * @return the object fetched that is the first match of the type
692      * specified in the classes array. null if none of
693      * the requested types are supported.
694      * The <code>instanceof</code> operator should be used to
695      * determine the specific kind of object returned.
696      * @exception IOException if an I/O error occurs while
697      * getting the content.
698      * @exception UnknownServiceException if the protocol does not support
699      * the content type.
700      * @see java.net.URLConnection#getContent()
701      * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
702      * @see java.net.URLConnection#getContent(java.lang.Class[])
703      * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
704      */

705     public Object JavaDoc getContent(Class JavaDoc[] classes) throws IOException JavaDoc {
706         // Must call getInputStream before GetHeaderField gets called
707
// so that FileNotFoundException has a chance to be thrown up
708
// from here without being caught.
709
getInputStream();
710     return getContentHandler().getContent(this, classes);
711     }
712
713     /**
714      * Returns a permission object representing the permission
715      * necessary to make the connection represented by this
716      * object. This method returns null if no permission is
717      * required to make the connection. By default, this method
718      * returns <code>java.security.AllPermission</code>. Subclasses
719      * should override this method and return the permission
720      * that best represents the permission required to make a
721      * a connection to the URL. For example, a <code>URLConnection</code>
722      * representing a <code>file:</code> URL would return a
723      * <code>java.io.FilePermission</code> object.
724      *
725      * <p>The permission returned may dependent upon the state of the
726      * connection. For example, the permission before connecting may be
727      * different from that after connecting. For example, an HTTP
728      * sever, say foo.com, may redirect the connection to a different
729      * host, say bar.com. Before connecting the permission returned by
730      * the connection will represent the permission needed to connect
731      * to foo.com, while the permission returned after connecting will
732      * be to bar.com.
733      *
734      * <p>Permissions are generally used for two purposes: to protect
735      * caches of objects obtained through URLConnections, and to check
736      * the right of a recipient to learn about a particular URL. In
737      * the first case, the permission should be obtained
738      * <em>after</em> the object has been obtained. For example, in an
739      * HTTP connection, this will represent the permission to connect
740      * to the host from which the data was ultimately fetched. In the
741      * second case, the permission should be obtained and tested
742      * <em>before</em> connecting.
743      *
744      * @return the permission object representing the permission
745      * necessary to make the connection represented by this
746      * URLConnection.
747      *
748      * @exception IOException if the computation of the permission
749      * requires network or file I/O and an exception occurs while
750      * computing it.
751      */

752     public Permission JavaDoc getPermission() throws IOException JavaDoc {
753     return SecurityConstants.ALL_PERMISSION;
754     }
755
756     /**
757      * Returns an input stream that reads from this open connection.
758      *
759      * A SocketTimeoutException can be thrown when reading from the
760      * returned input stream if the read timeout expires before data
761      * is available for read.
762      *
763      * @return an input stream that reads from this open connection.
764      * @exception IOException if an I/O error occurs while
765      * creating the input stream.
766      * @exception UnknownServiceException if the protocol does not support
767      * input.
768      * @see #setReadTimeout(int)
769      * @see #getReadTimeout()
770      */

771     public InputStream JavaDoc getInputStream() throws IOException JavaDoc {
772     throw new UnknownServiceException JavaDoc("protocol doesn't support input");
773     }
774
775     /**
776      * Returns an output stream that writes to this connection.
777      *
778      * @return an output stream that writes to this connection.
779      * @exception IOException if an I/O error occurs while
780      * creating the output stream.
781      * @exception UnknownServiceException if the protocol does not support
782      * output.
783      */

784     public OutputStream JavaDoc getOutputStream() throws IOException JavaDoc {
785     throw new UnknownServiceException JavaDoc("protocol doesn't support output");
786     }
787
788     /**
789      * Returns a <code>String</code> representation of this URL connection.
790      *
791      * @return a string representation of this <code>URLConnection</code>.
792      */

793     public String JavaDoc toString() {
794     return this.getClass().getName() + ":" + url;
795     }
796
797     /**
798      * Sets the value of the <code>doInput</code> field for this
799      * <code>URLConnection</code> to the specified value.
800      * <p>
801      * A URL connection can be used for input and/or output. Set the DoInput
802      * flag to true if you intend to use the URL connection for input,
803      * false if not. The default is true.
804      *
805      * @param doinput the new value.
806      * @throws IllegalStateException if already connected
807      * @see java.net.URLConnection#doInput
808      * @see #getDoInput()
809      */

810     public void setDoInput(boolean doinput) {
811     if (connected)
812         throw new IllegalStateException JavaDoc("Already connected");
813     doInput = doinput;
814     }
815
816     /**
817      * Returns the value of this <code>URLConnection</code>'s
818      * <code>doInput</code> flag.
819      *
820      * @return the value of this <code>URLConnection</code>'s
821      * <code>doInput</code> flag.
822      * @see #setDoInput(boolean)
823      */

824     public boolean getDoInput() {
825     return doInput;
826     }
827
828     /**
829      * Sets the value of the <code>doOutput</code> field for this
830      * <code>URLConnection</code> to the specified value.
831      * <p>
832      * A URL connection can be used for input and/or output. Set the DoOutput
833      * flag to true if you intend to use the URL connection for output,
834      * false if not. The default is false.
835      *
836      * @param dooutput the new value.
837      * @throws IllegalStateException if already connected
838      * @see #getDoOutput()
839      */

840     public void setDoOutput(boolean dooutput) {
841     if (connected)
842         throw new IllegalStateException JavaDoc("Already connected");
843     doOutput = dooutput;
844     }
845
846     /**
847      * Returns the value of this <code>URLConnection</code>'s
848      * <code>doOutput</code> flag.
849      *
850      * @return the value of this <code>URLConnection</code>'s
851      * <code>doOutput</code> flag.
852      * @see #setDoOutput(boolean)
853      */

854     public boolean getDoOutput() {
855     return doOutput;
856     }
857
858     /**
859      * Set the value of the <code>allowUserInteraction</code> field of
860      * this <code>URLConnection</code>.
861      *
862      * @param allowuserinteraction the new value.
863      * @throws IllegalStateException if already connected
864      * @see #getAllowUserInteraction()
865      */

866     public void setAllowUserInteraction(boolean allowuserinteraction) {
867     if (connected)
868         throw new IllegalStateException JavaDoc("Already connected");
869     allowUserInteraction = allowuserinteraction;
870     }
871
872     /**
873      * Returns the value of the <code>allowUserInteraction</code> field for
874      * this object.
875      *
876      * @return the value of the <code>allowUserInteraction</code> field for
877      * this object.
878      * @see #setAllowUserInteraction(boolean)
879      */

880     public boolean getAllowUserInteraction() {
881     return allowUserInteraction;
882     }
883
884     /**
885      * Sets the default value of the
886      * <code>allowUserInteraction</code> field for all future
887      * <code>URLConnection</code> objects to the specified value.
888      *
889      * @param defaultallowuserinteraction the new value.
890      * @see #getDefaultAllowUserInteraction()
891      */

892     public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {
893     defaultAllowUserInteraction = defaultallowuserinteraction;
894     }
895
896     /**
897      * Returns the default value of the <code>allowUserInteraction</code>
898      * field.
899      * <p>
900      * Ths default is "sticky", being a part of the static state of all
901      * URLConnections. This flag applies to the next, and all following
902      * URLConnections that are created.
903      *
904      * @return the default value of the <code>allowUserInteraction</code>
905      * field.
906      * @see #setDefaultAllowUserInteraction(boolean)
907      */

908     public static boolean getDefaultAllowUserInteraction() {
909     return defaultAllowUserInteraction;
910     }
911
912     /**
913      * Sets the value of the <code>useCaches</code> field of this
914      * <code>URLConnection</code> to the specified value.
915      * <p>
916      * Some protocols do caching of documents. Occasionally, it is important
917      * to be able to "tunnel through" and ignore the caches (e.g., the
918      * "reload" button in a browser). If the UseCaches flag on a connection
919      * is true, the connection is allowed to use whatever caches it can.
920      * If false, caches are to be ignored.
921      * The default value comes from DefaultUseCaches, which defaults to
922      * true.
923      *
924      * @param usecaches a <code>boolean</code> indicating whether
925      * or not to allow caching
926      * @throws IllegalStateException if already connected
927      * @see #getUseCaches()
928      */

929     public void setUseCaches(boolean usecaches) {
930     if (connected)
931         throw new IllegalStateException JavaDoc("Already connected");
932     useCaches = usecaches;
933     }
934
935     /**
936      * Returns the value of this <code>URLConnection</code>'s
937      * <code>useCaches</code> field.
938      *
939      * @return the value of this <code>URLConnection</code>'s
940      * <code>useCaches</code> field.
941      * @see #setUseCaches(boolean)
942      */

943     public boolean getUseCaches() {
944     return useCaches;
945     }
946
947     /**
948      * Sets the value of the <code>ifModifiedSince</code> field of
949      * this <code>URLConnection</code> to the specified value.
950      *
951      * @param ifmodifiedsince the new value.
952      * @throws IllegalStateException if already connected
953      * @see #getIfModifiedSince()
954      */

955     public void setIfModifiedSince(long ifmodifiedsince) {
956     if (connected)
957         throw new IllegalStateException JavaDoc("Already connected");
958     ifModifiedSince = ifmodifiedsince;
959     }
960
961     /**
962      * Returns the value of this object's <code>ifModifiedSince</code> field.
963      *
964      * @return the value of this object's <code>ifModifiedSince</code> field.
965      * @see #setIfModifiedSince(long)
966      */

967     public long getIfModifiedSince() {
968     return ifModifiedSince;
969     }
970
971    /**
972      * Returns the default value of a <code>URLConnection</code>'s
973      * <code>useCaches</code> flag.
974      * <p>
975      * Ths default is "sticky", being a part of the static state of all
976      * URLConnections. This flag applies to the next, and all following
977      * URLConnections that are created.
978      *
979      * @return the default value of a <code>URLConnection</code>'s
980      * <code>useCaches</code> flag.
981      * @see #setDefaultUseCaches(boolean)
982      */

983     public boolean getDefaultUseCaches() {
984     return defaultUseCaches;
985     }
986
987    /**
988      * Sets the default value of the <code>useCaches</code> field to the
989      * specified value.
990      *
991      * @param defaultusecaches the new value.
992      * @see #getDefaultUseCaches()
993      */

994     public void setDefaultUseCaches(boolean defaultusecaches) {
995     defaultUseCaches = defaultusecaches;
996     }
997
998     /**
999      * Sets the general request property. If a property with the key already
1000     * exists, overwrite its value with the new value.
1001     *
1002     * <p> NOTE: HTTP requires all request properties which can
1003     * legally have multiple instances with the same key
1004     * to use a comma-seperated list syntax which enables multiple
1005     * properties to be appended into a single property.
1006     *
1007     * @param key the keyword by which the request is known
1008     * (e.g., "<code>accept</code>").
1009     * @param value the value associated with it.
1010     * @throws IllegalStateException if already connected
1011     * @throws NullPointerException if key is <CODE>null</CODE>
1012     * @see #getRequestProperty(java.lang.String)
1013     */

1014    public void setRequestProperty(String JavaDoc key, String JavaDoc value) {
1015    if (connected)
1016        throw new IllegalStateException JavaDoc("Already connected");
1017    if (key == null)
1018        throw new NullPointerException JavaDoc ("key is null");
1019    }
1020
1021    /**
1022     * Adds a general request property specified by a
1023     * key-value pair. This method will not overwrite
1024     * existing values associated with the same key.
1025     *
1026     * @param key the keyword by which the request is known
1027     * (e.g., "<code>accept</code>").
1028     * @param value the value associated with it.
1029     * @throws IllegalStateException if already connected
1030     * @throws NullPointerException if key is null
1031     * @see #getRequestProperties()
1032     * @since 1.4
1033     */

1034    public void addRequestProperty(String JavaDoc key, String JavaDoc value) {
1035    if (connected)
1036        throw new IllegalStateException JavaDoc("Already connected");
1037    if (key == null)
1038        throw new NullPointerException JavaDoc ("key is null");
1039    }
1040
1041
1042    /**
1043     * Returns the value of the named general request property for this
1044     * connection.
1045     *
1046     * @param key the keyword by which the request is known (e.g., "accept").
1047     * @return the value of the named general request property for this
1048     * connection. If key is null, then null is returned.
1049     * @throws IllegalStateException if already connected
1050     * @see #setRequestProperty(java.lang.String, java.lang.String)
1051     */

1052    public String JavaDoc getRequestProperty(String JavaDoc key) {
1053    if (connected)
1054        throw new IllegalStateException JavaDoc("Already connected");
1055    return null;
1056    }
1057
1058    /**
1059     * Returns an unmodifiable Map of general request
1060     * properties for this connection. The Map keys
1061     * are Strings that represent the request-header
1062     * field names. Each Map value is a unmodifiable List
1063     * of Strings that represents the corresponding
1064     * field values.
1065     *
1066     * @return a Map of the general request properties for this connection.
1067     * @throws IllegalStateException if already connected
1068     * @since 1.4
1069     */

1070    public Map JavaDoc<String JavaDoc,List JavaDoc<String JavaDoc>> getRequestProperties() {
1071        if (connected)
1072            throw new IllegalStateException JavaDoc("Already connected");
1073    return Collections.EMPTY_MAP;
1074    }
1075
1076    /**
1077     * Sets the default value of a general request property. When a
1078     * <code>URLConnection</code> is created, it is initialized with
1079     * these properties.
1080     *
1081     * @param key the keyword by which the request is known
1082     * (e.g., "<code>accept</code>").
1083     * @param value the value associated with the key.
1084     *
1085     * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String)
1086     *
1087     * @deprecated The instance specific setRequestProperty method
1088     * should be used after an appropriate instance of URLConnection
1089     * is obtained. Invoking this method will have no effect.
1090     *
1091     * @see #getDefaultRequestProperty(java.lang.String)
1092     */

1093    @Deprecated JavaDoc
1094    public static void setDefaultRequestProperty(String JavaDoc key, String JavaDoc value) {
1095    }
1096
1097    /**
1098     * Returns the value of the default request property. Default request
1099     * properties are set for every connection.
1100     *
1101     * @param key the keyword by which the request is known (e.g., "accept").
1102     * @return the value of the default request property
1103     * for the specified key.
1104     *
1105     * @see java.net.URLConnection#getRequestProperty(java.lang.String)
1106     *
1107     * @deprecated The instance specific getRequestProperty method
1108     * should be used after an appropriate instance of URLConnection
1109     * is obtained.
1110     *
1111     * @see #setDefaultRequestProperty(java.lang.String, java.lang.String)
1112     */

1113    @Deprecated JavaDoc
1114    public static String JavaDoc getDefaultRequestProperty(String JavaDoc key) {
1115    return null;
1116    }
1117
1118    /**
1119     * The ContentHandler factory.
1120     */

1121    static ContentHandlerFactory JavaDoc factory;
1122
1123    /**
1124     * Sets the <code>ContentHandlerFactory</code> of an
1125     * application. It can be called at most once by an application.
1126     * <p>
1127     * The <code>ContentHandlerFactory</code> instance is used to
1128     * construct a content handler from a content type
1129     * <p>
1130     * If there is a security manager, this method first calls
1131     * the security manager's <code>checkSetFactory</code> method
1132     * to ensure the operation is allowed.
1133     * This could result in a SecurityException.
1134     *
1135     * @param fac the desired factory.
1136     * @exception Error if the factory has already been defined.
1137     * @exception SecurityException if a security manager exists and its
1138     * <code>checkSetFactory</code> method doesn't allow the operation.
1139     * @see java.net.ContentHandlerFactory
1140     * @see java.net.URLConnection#getContent()
1141     * @see SecurityManager#checkSetFactory
1142     */

1143    public static synchronized void setContentHandlerFactory(ContentHandlerFactory JavaDoc fac) {
1144    if (factory != null) {
1145        throw new Error JavaDoc("factory already defined");
1146    }
1147    SecurityManager JavaDoc security = System.getSecurityManager();
1148    if (security != null) {
1149        security.checkSetFactory();
1150    }
1151    factory = fac;
1152    }
1153
1154    private static Hashtable JavaDoc handlers = new Hashtable JavaDoc();
1155    private static final ContentHandler JavaDoc UnknownContentHandlerP = new UnknownContentHandler();
1156
1157    /**
1158     * Gets the Content Handler appropriate for this connection.
1159     * @param connection the connection to use.
1160     */

1161    synchronized ContentHandler JavaDoc getContentHandler()
1162    throws UnknownServiceException JavaDoc
1163    {
1164    String JavaDoc contentType = stripOffParameters(getContentType());
1165    ContentHandler JavaDoc handler = null;
1166    if (contentType == null)
1167        throw new UnknownServiceException JavaDoc("no content-type");
1168    try {
1169        handler = (ContentHandler JavaDoc) handlers.get(contentType);
1170        if (handler != null)
1171        return handler;
1172    } catch(Exception JavaDoc e) {
1173    }
1174
1175    if (factory != null)
1176        handler = factory.createContentHandler(contentType);
1177    if (handler == null) {
1178        try {
1179        handler = lookupContentHandlerClassFor(contentType);
1180        } catch(Exception JavaDoc e) {
1181        e.printStackTrace();
1182        handler = UnknownContentHandlerP;
1183        }
1184        handlers.put(contentType, handler);
1185    }
1186    return handler;
1187    }
1188
1189    /*
1190     * Media types are in the format: type/subtype*(; parameter).
1191     * For looking up the content handler, we should ignore those
1192     * parameters.
1193     */

1194    private String JavaDoc stripOffParameters(String JavaDoc contentType)
1195    {
1196    if (contentType == null)
1197        return null;
1198    int index = contentType.indexOf(';');
1199
1200    if (index > 0)
1201        return contentType.substring(0, index);
1202    else
1203        return contentType;
1204    }
1205
1206    private static final String JavaDoc contentClassPrefix = "sun.net.www.content";
1207    private static final String JavaDoc contentPathProp = "java.content.handler.pkgs";
1208
1209    /**
1210     * Looks for a content handler in a user-defineable set of places.
1211     * By default it looks in sun.net.www.content, but users can define a
1212     * vertical-bar delimited set of class prefixes to search through in
1213     * addition by defining the java.content.handler.pkgs property.
1214     * The class name must be of the form:
1215     * <pre>
1216     * {package-prefix}.{major}.{minor}
1217     * e.g.
1218     * YoyoDyne.experimental.text.plain
1219     * </pre>
1220     */

1221    private ContentHandler JavaDoc lookupContentHandlerClassFor(String JavaDoc contentType)
1222    throws InstantiationException JavaDoc, IllegalAccessException JavaDoc, ClassNotFoundException JavaDoc {
1223    String JavaDoc contentHandlerClassName = typeToPackageName(contentType);
1224
1225    String JavaDoc contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes();
1226
1227    StringTokenizer JavaDoc packagePrefixIter =
1228        new StringTokenizer JavaDoc(contentHandlerPkgPrefixes, "|");
1229    
1230    while (packagePrefixIter.hasMoreTokens()) {
1231        String JavaDoc packagePrefix = packagePrefixIter.nextToken().trim();
1232
1233        try {
1234        String JavaDoc clsName = packagePrefix + "." + contentHandlerClassName;
1235        Class JavaDoc cls = null;
1236        try {
1237            cls = Class.forName(clsName);
1238        } catch (ClassNotFoundException JavaDoc e) {
1239            ClassLoader JavaDoc cl = ClassLoader.getSystemClassLoader();
1240            if (cl != null) {
1241            cls = cl.loadClass(clsName);
1242            }
1243        }
1244        if (cls != null) {
1245            ContentHandler JavaDoc handler =
1246            (ContentHandler JavaDoc)cls.newInstance();
1247            return handler;
1248        }
1249        } catch(Exception JavaDoc e) {
1250        }
1251    }
1252    
1253    return UnknownContentHandlerP;
1254    }
1255
1256    /**
1257     * Utility function to map a MIME content type into an equivalent
1258     * pair of class name components. For example: "text/html" would
1259     * be returned as "text.html"
1260     */

1261    private String JavaDoc typeToPackageName(String JavaDoc contentType) {
1262    // make sure we canonicalize the class name: all lower case
1263
contentType = contentType.toLowerCase();
1264    int len = contentType.length();
1265    char nm[] = new char[len];
1266    contentType.getChars(0, len, nm, 0);
1267    for (int i = 0; i < len; i++) {
1268        char c = nm[i];
1269        if (c == '/') {
1270        nm[i] = '.';
1271        } else if (!('A' <= c && c <= 'Z' ||
1272               'a' <= c && c <= 'z' ||
1273               '0' <= c && c <= '9')) {
1274        nm[i] = '_';
1275        }
1276    }
1277    return new String JavaDoc(nm);
1278    }
1279
1280
1281    /**
1282     * Returns a vertical bar separated list of package prefixes for potential
1283     * content handlers. Tries to get the java.content.handler.pkgs property
1284     * to use as a set of package prefixes to search. Whether or not
1285     * that property has been defined, the sun.net.www.content is always
1286     * the last one on the returned package list.
1287     */

1288    private String JavaDoc getContentHandlerPkgPrefixes() {
1289    String JavaDoc packagePrefixList = (String JavaDoc) AccessController.doPrivileged(
1290            new sun.security.action.GetPropertyAction(contentPathProp, ""));
1291
1292    if (packagePrefixList != "") {
1293        packagePrefixList += "|";
1294    }
1295    
1296    return packagePrefixList + contentClassPrefix;
1297    }
1298
1299    /**
1300     * Tries to determine the content type of an object, based
1301     * on the specified "file" component of a URL.
1302     * This is a convenience method that can be used by
1303     * subclasses that override the <code>getContentType</code> method.
1304     *
1305     * @param fname a filename.
1306     * @return a guess as to what the content type of the object is,
1307     * based upon its file name.
1308     * @see java.net.URLConnection#getContentType()
1309     */

1310    public static String JavaDoc guessContentTypeFromName(String JavaDoc fname) {
1311    return getFileNameMap().getContentTypeFor(fname);
1312    }
1313
1314    /**
1315     * Tries to determine the type of an input stream based on the
1316     * characters at the beginning of the input stream. This method can
1317     * be used by subclasses that override the
1318     * <code>getContentType</code> method.
1319     * <p>
1320     * Ideally, this routine would not be needed. But many
1321     * <code>http</code> servers return the incorrect content type; in
1322     * addition, there are many nonstandard extensions. Direct inspection
1323     * of the bytes to determine the content type is often more accurate
1324     * than believing the content type claimed by the <code>http</code> server.
1325     *
1326     * @param is an input stream that supports marks.
1327     * @return a guess at the content type, or <code>null</code> if none
1328     * can be determined.
1329     * @exception IOException if an I/O error occurs while reading the
1330     * input stream.
1331     * @see java.io.InputStream#mark(int)
1332     * @see java.io.InputStream#markSupported()
1333     * @see java.net.URLConnection#getContentType()
1334     */

1335    static public String JavaDoc guessContentTypeFromStream(InputStream JavaDoc is)
1336            throws IOException JavaDoc {
1337    // If we can't read ahead safely, just give up on guessing
1338
if (!is.markSupported())
1339        return null;
1340
1341    is.mark(12);
1342    int c1 = is.read();
1343    int c2 = is.read();
1344    int c3 = is.read();
1345    int c4 = is.read();
1346    int c5 = is.read();
1347    int c6 = is.read();
1348    int c7 = is.read();
1349    int c8 = is.read();
1350    int c9 = is.read();
1351    int c10 = is.read();
1352    int c11 = is.read();
1353    is.reset();
1354
1355    if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {
1356        return "application/java-vm";
1357    }
1358
1359    if (c1 == 0xAC && c2 == 0xED) {
1360        // next two bytes are version number, currently 0x00 0x05
1361
return "application/x-java-serialized-object";
1362    }
1363
1364    if (c1 == '<') {
1365        if (c2 == '!'
1366        || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' ||
1367                   c3 == 'e' && c4 == 'a' && c5 == 'd') ||
1368        (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) ||
1369        ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' ||
1370                c3 == 'E' && c4 == 'A' && c5 == 'D') ||
1371        (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) {
1372        return "text/html";
1373        }
1374
1375        if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') {
1376        return "application/xml";
1377        }
1378    }
1379
1380    // big and little endian UTF-16 encodings, with byte order mark
1381
if (c1 == 0xfe && c2 == 0xff) {
1382        if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' &&
1383        c7 == 0 && c8 == 'x') {
1384        return "application/xml";
1385        }
1386    }
1387
1388    if (c1 == 0xff && c2 == 0xfe) {
1389        if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 &&
1390        c7 == 'x' && c8 == 0) {
1391        return "application/xml";
1392        }
1393    }
1394
1395    if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
1396        return "image/gif";
1397    }
1398
1399    if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
1400        return "image/x-bitmap";
1401    }
1402
1403    if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
1404            c5 == 'M' && c6 == '2') {
1405        return "image/x-pixmap";
1406    }
1407
1408    if (c1 == 137 && c2 == 80 && c3 == 78 &&
1409        c4 == 71 && c5 == 13 && c6 == 10 &&
1410        c7 == 26 && c8 == 10) {
1411        return "image/png";
1412    }
1413
1414    if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {
1415        if (c4 == 0xE0) {
1416            return "image/jpeg";
1417        }
1418
1419        /**
1420             * File format used by digital cameras to store images.
1421             * Exif Format can be read by any application supporting
1422             * JPEG. Exif Spec can be found at:
1423             * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
1424             */

1425            if ((c4 == 0xE1) &&
1426                (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' &&
1427                 c11 == 0)) {
1428                return "image/jpeg";
1429            }
1430
1431        if (c4 == 0xEE) {
1432        return "image/jpg";
1433        }
1434    }
1435
1436    if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 &&
1437        c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {
1438
1439        /* Above is signature of Microsoft Structured Storage.
1440         * Below this, could have tests for various SS entities.
1441         * For now, just test for FlashPix.
1442         */

1443        if (checkfpx(is)) {
1444        return "image/vnd.fpx";
1445        }
1446    }
1447
1448    if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) {
1449        return "audio/basic"; // .au format, big endian
1450
}
1451
1452    if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) {
1453        return "audio/basic"; // .au format, little endian
1454
}
1455
1456    if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') {
1457        /* I don't know if this is official but evidence
1458         * suggests that .wav files start with "RIFF" - brown
1459         */

1460        return "audio/x-wav";
1461    }
1462    return null;
1463    }
1464
1465    /**
1466     * Check for FlashPix image data in InputStream is. Return true if
1467     * the stream has FlashPix data, false otherwise. Before calling this
1468     * method, the stream should have already been checked to be sure it
1469     * contains Microsoft Structured Storage data.
1470     */

1471    static private boolean checkfpx(InputStream JavaDoc is) throws IOException JavaDoc {
1472
1473        /* Test for FlashPix image data in Microsoft Structured Storage format.
1474         * In general, should do this with calls to an SS implementation.
1475         * Lacking that, need to dig via offsets to get to the FlashPix
1476         * ClassID. Details:
1477         *
1478         * Offset to Fpx ClsID from beginning of stream should be:
1479         *
1480         * FpxClsidOffset = rootEntryOffset + clsidOffset
1481         *
1482         * where: clsidOffset = 0x50.
1483         * rootEntryOffset = headerSize + sectorSize*sectDirStart
1484         * + 128*rootEntryDirectory
1485         *
1486         * where: headerSize = 0x200 (always)
1487         * sectorSize = 2 raised to power of uSectorShift,
1488         * which is found in the header at
1489         * offset 0x1E.
1490         * sectDirStart = found in the header at offset 0x30.
1491         * rootEntryDirectory = in general, should search for
1492         * directory labelled as root.
1493         * We will assume value of 0 (i.e.,
1494         * rootEntry is in first directory)
1495         */

1496
1497    // Mark the stream so we can reset it. 0x100 is enough for the first
1498
// few reads, but the mark will have to be reset and set again once
1499
// the offset to the root directory entry is computed. That offset
1500
// can be very large and isn't know until the stream has been read from
1501
is.mark(0x100);
1502
1503    // Get the byte ordering located at 0x1E. 0xFE is Intel,
1504
// 0xFF is other
1505
long toSkip = (long)0x1C;
1506    long posn;
1507
1508        if ((posn = skipForward(is, toSkip)) < toSkip) {
1509      is.reset();
1510      return false;
1511    }
1512    
1513    int c[] = new int[16];
1514    if (readBytes(c, 2, is) < 0) {
1515        is.reset();
1516        return false;
1517    }
1518
1519    int byteOrder = c[0];
1520
1521    posn+=2;
1522    int uSectorShift;
1523    if (readBytes(c, 2, is) < 0) {
1524        is.reset();
1525        return false;
1526    }
1527
1528    if(byteOrder == 0xFE) {
1529        uSectorShift = c[0];
1530        uSectorShift += c[1] << 8;
1531    }
1532    else {
1533        uSectorShift = c[0] << 8;
1534        uSectorShift += c[1];
1535    }
1536
1537    posn += 2;
1538    toSkip = (long)0x30 - posn;
1539    long skipped = 0;
1540    if ((skipped = skipForward(is, toSkip)) < toSkip) {
1541      is.reset();
1542      return false;
1543    }
1544    posn += skipped;
1545
1546    if (readBytes(c, 4, is) < 0) {
1547        is.reset();
1548        return false;
1549    }
1550
1551    int sectDirStart;
1552    if(byteOrder == 0xFE) {
1553        sectDirStart = c[0];
1554        sectDirStart += c[1] << 8;
1555        sectDirStart += c[2] << 16;
1556        sectDirStart += c[3] << 24;
1557    } else {
1558        sectDirStart = c[0] << 24;
1559        sectDirStart += c[1] << 16;
1560        sectDirStart += c[2] << 8;
1561        sectDirStart += c[3];
1562    }
1563    posn += 4;
1564    is.reset(); // Reset back to the beginning
1565

1566    toSkip = (long)0x200 +
1567        (long)((int)1<<uSectorShift)*sectDirStart + (long)0x50;
1568
1569    // Sanity check!
1570
if (toSkip < 0) {
1571        return false;
1572    }
1573
1574    /*
1575     * How far can we skip? Is there any performance problem here?
1576     * This skip can be fairly long, at least 0x4c650 in at least
1577     * one case. Have to assume that the skip will fit in an int.
1578         * Leave room to read whole root dir
1579     */

1580    is.mark((int)toSkip+0x30);
1581
1582    if ((skipForward(is, toSkip)) < toSkip) {
1583        is.reset();
1584        return false;
1585    }
1586
1587    /* should be at beginning of ClassID, which is as follows
1588     * (in Intel byte order):
1589     * 00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B
1590     *
1591     * This is stored from Windows as long,short,short,char[8]
1592     * so for byte order changes, the order only changes for
1593     * the first 8 bytes in the ClassID.
1594     *
1595     * Test against this, ignoring second byte (Intel) since
1596     * this could change depending on part of Fpx file we have.
1597     */

1598
1599    if (readBytes(c, 16, is) < 0) {
1600        is.reset();
1601        return false;
1602    }
1603
1604    // intel byte order
1605
if (byteOrder == 0xFE &&
1606        c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 &&
1607        c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE &&
1608        c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
1609        c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
1610        c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
1611        is.reset();
1612        return true;
1613    }
1614
1615    // non-intel byte order
1616
else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 &&
1617        c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE &&
1618        c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
1619        c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
1620        c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
1621        is.reset();
1622        return true;
1623    }
1624        is.reset();
1625        return false;
1626    }
1627
1628    /**
1629     * Tries to read the specified number of bytes from the stream
1630     * Returns -1, If EOF is reached before len bytes are read, returns 0
1631     * otherwise
1632     */

1633    static private int readBytes(int c[], int len, InputStream JavaDoc is)
1634        throws IOException JavaDoc {
1635
1636    byte buf[] = new byte[len];
1637    if (is.read(buf, 0, len) < len) {
1638        return -1;
1639    }
1640    
1641    // fill the passed in int array
1642
for (int i = 0; i < len; i++) {
1643         c[i] = buf[i] & 0xff;
1644    }
1645    return 0;
1646    }
1647
1648
1649    /**
1650     * Skips through the specified number of bytes from the stream
1651     * until either EOF is reached, or the specified
1652     * number of bytes have been skipped
1653     */

1654    static private long skipForward(InputStream JavaDoc is, long toSkip)
1655        throws IOException JavaDoc {
1656
1657    long eachSkip = 0;
1658    long skipped = 0;
1659
1660        while (skipped != toSkip) {
1661            eachSkip = is.skip(toSkip - skipped);
1662
1663            // check if EOF is reached
1664
if (eachSkip <= 0) {
1665                if (is.read() == -1) {
1666                    return skipped ;
1667                } else {
1668                    skipped++;
1669                }
1670            }
1671            skipped += eachSkip;
1672        }
1673    return skipped;
1674    }
1675
1676}
1677
1678
1679class UnknownContentHandler extends ContentHandler JavaDoc {
1680    public Object JavaDoc getContent(URLConnection JavaDoc uc) throws IOException JavaDoc {
1681    return uc.getInputStream();
1682    }
1683}
1684
Popular Tags