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.
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.
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).
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.
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
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;
40 import java.util.List;
41 import java.util.NoSuchElementException;
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:
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
55 * <td>Interact with the resource; query header fields and
58 * ---------------------------->
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.
71 * The setup parameters are modified using the following methods:
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>
80 * and the general request properties are modified using the method:
82 * <li><code>setRequestProperty</code>
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>.
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.
95 * The following methods are used to access the header fields and
96 * the contents after the connection is made to the remote object:
98 * <li><code>getContent</code>
99 * <li><code>getHeaderField</code>
100 * <li><code>getInputStream</code>
101 * <li><code>getOutputStream</code>
104 * Certain header fields are accessed frequently. The methods:
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>
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.
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.
127 * More information on the request properties and header fields of
128 * an <code>http</code> connection can be found at:
130 * <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a>
131 * </pre></blockquote>
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.
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
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)
170 public abstract class URLConnection {
173 * The URL represents the remote object on the World Wide Web to
174 * which this connection is opened.
176 * The value of this field can be accessed by the
177 * <code>getURL</code> method.
179 * The default value of this variable is the value of the URL
180 * argument in the <code>URLConnection</code> constructor.
182 * @see java.net.URLConnection#getURL()
183 * @see java.net.URLConnection#url
188 * This variable is set by the <code>setDoInput</code> method. Its
189 * value is returned by the <code>getDoInput</code> method.
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.
195 * The default value of this field is <code>true</code>.
197 * @see java.net.URLConnection#getDoInput()
198 * @see java.net.URLConnection#setDoInput(boolean)
200 protected boolean doInput = true;
203 * This variable is set by the <code>setDoOutput</code> method. Its
204 * value is returned by the <code>getDoOutput</code> method.
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.
210 * The default value of this field is <code>false</code>.
212 * @see java.net.URLConnection#getDoOutput()
213 * @see java.net.URLConnection#setDoOutput(boolean)
215 protected boolean doOutput = false;
217 private static boolean defaultAllowUserInteraction = false;
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.
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.
232 * @see java.net.URLConnection#getAllowUserInteraction()
233 * @see java.net.URLConnection#setAllowUserInteraction(boolean)
234 * @see java.net.URLConnection#setDefaultAllowUserInteraction(boolean)
236 protected boolean allowUserInteraction = defaultAllowUserInteraction;
238 private static boolean defaultUseCaches = true;
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.
245 * This field is set by the <code>setUseCaches</code> method. Its
246 * value is returned by the <code>getUseCaches</code> method.
248 * Its default value is the value given in the last invocation of the
249 * <code>setDefaultUseCaches</code> method.
251 * @see java.net.URLConnection#setUseCaches(boolean)
252 * @see java.net.URLConnection#getUseCaches()
253 * @see java.net.URLConnection#setDefaultUseCaches(boolean)
255 protected boolean useCaches = defaultUseCaches;
258 * Some protocols support skipping the fetching of the object unless
259 * the object has been modified more recently than a certain time.
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.
265 * This variable is set by the <code>setIfModifiedSince</code>
266 * method. Its value is returned by the
267 * <code>getIfModifiedSince</code> method.
269 * The default value of this field is <code>0</code>, indicating
270 * that the fetching must always occur.
272 * @see java.net.URLConnection#getIfModifiedSince()
273 * @see java.net.URLConnection#setIfModifiedSince(long)
275 protected long ifModifiedSince = 0;
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.
282 protected boolean connected = false;
287 private int connectTimeout;
288 private int readTimeout;
293 private MessageHeader requests;
298 private static FileNameMap fileNameMap;
303 private static boolean fileNameMapLoaded = false;
306 * Loads filename map (a mimetable) from a data file. It will
307 * first try to load the user-specific table, defined
308 * by "content.types.user.table" property. If that fails,
309 * it tries to load the default built-in table at
310 * lib/content-types.properties under java home.
312 * @return the FileNameMap
314 * @see #setFileNameMap(java.net.FileNameMap)
316 public static synchronized FileNameMap getFileNameMap() {
317 if ((fileNameMap == null) && !fileNameMapLoaded) {
318 fileNameMap = new FileNameMap() {
320 public String getContentTypeFor(String fileName) {
324 fileNameMapLoaded = true;
327 return new FileNameMap() {
328 private FileNameMap map = fileNameMap;
329 public String getContentTypeFor(String fileName) {
330 return map.getContentTypeFor(fileName);
336 * Sets the FileNameMap.
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.
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()
350 public static void setFileNameMap(FileNameMap map) {
351 throw new SecurityException();
355 * Opens a communications link to the resource referenced by this
356 * URL, if such a connection has not already been established.
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.
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.
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
374 * @see java.net.URLConnection#connected
375 * @see #getConnectTimeout()
376 * @see #setConnectTimeout(int)
378 abstract public void connect() throws IOException;
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.
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().
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
396 * @see #getConnectTimeout()
400 public void setConnectTimeout(int timeout) {
402 throw new IllegalArgumentException("timeout can not be negative");
404 connectTimeout = timeout;
408 * Returns setting for connect timeout.
410 * 0 return implies that the option is disabled
411 * (i.e., timeout of infinity).
413 * @return an <code>int</code> that indicates the connect timeout
414 * value in milliseconds
415 * @see #setConnectTimeout(int)
419 public int getConnectTimeout() {
420 return connectTimeout;
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.
431 *<p> Some non-standard implementation of this method ignores the
432 * specified timeout. To see the read timeout set, please call
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
439 * @see #getReadTimeout()
440 * @see InputStream#read()
443 public void setReadTimeout(int timeout) {
445 throw new IllegalArgumentException("timeout can not be negative");
447 readTimeout = timeout;
451 * Returns setting for read timeout. 0 return implies that the
452 * option is disabled (i.e., timeout of infinity).
454 * @return an <code>int</code> that indicates the read timeout
455 * value in milliseconds
457 * @see #setReadTimeout(int)
458 * @see InputStream#read()
461 public int getReadTimeout() {
466 * Constructs a URL connection to the specified URL. A connection to
467 * the object referenced by the URL is not created.
469 * @param url the specified URL.
471 protected URLConnection(URL url) {
476 * Returns the value of this <code>URLConnection</code>'s <code>URL</code>
479 * @return the value of this <code>URLConnection</code>'s <code>URL</code>
481 * @see java.net.URLConnection#url
483 public URL getURL() {
488 * Returns the value of the <code>content-length</code> header field.
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>
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.
498 public int getContentLength() {
499 long l = getContentLengthLong();
500 if (l > Integer.MAX_VALUE)
506 * Returns the value of the <code>content-length</code> header field as a
509 * @return the content length of the resource that this connection's URL
510 * references, or <code>-1</code> if the content length is
514 public long getContentLengthLong() {
515 return getHeaderFieldLong("content-length", -1);
519 * Returns the value of the <code>content-type</code> header field.
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)
525 public String getContentType() {
526 return getHeaderField("content-type");
530 * Returns the value of the <code>content-encoding</code> header field.
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)
536 public String getContentEncoding() {
537 return getHeaderField("content-encoding");
541 * Returns the value of the <code>expires</code> header field.
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)
548 public long getExpiration() {
549 return getHeaderFieldDate("expires", 0);
553 * Returns the value of the <code>date</code> header field.
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)
560 public long getDate() {
561 return getHeaderFieldDate("date", 0);
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.
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)
572 public long getLastModified() {
573 return getHeaderFieldDate("last-modified", 0);
577 * Returns the value of the named header field.
579 * If called on a connection that sets the same header multiple times
580 * with possibly different values, only the last value is returned.
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.
587 public String getHeaderField(String name) {
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.
598 * @return a Map of header fields
601 public Map<String,List<String>> getHeaderFields() {
602 return Collections.EMPTY_MAP;
606 * Returns the value of the named field parsed as a number.
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.
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.
619 public int getHeaderFieldInt(String name, int Default) {
620 String value = getHeaderField(name);
622 return Integer.parseInt(value);
623 } catch (Exception e) { }
628 * Returns the value of the named field parsed as a number.
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.
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.
642 public long getHeaderFieldLong(String name, long Default) {
643 String value = getHeaderField(name);
645 return Long.parseLong(value);
646 } catch (Exception e) { }
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.
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.
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.
666 public long getHeaderFieldDate(String name, long Default) {
667 String value = getHeaderField(name);
669 return Date.parse(value);
670 } catch (Exception e) { }
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.
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>
683 public String getHeaderFieldKey(int n) {
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.
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.
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)
701 public String getHeaderField(int n) {
706 * Retrieves the contents of this URL connection.
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:
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:
722 * sun.net.www.content.<<i>contentType</i>>
723 * </pre></blockquote>
724 * where <<i>contentType</i>> 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.
737 * @return the object fetched. The <code>instanceof</code> operator
738 * should be used to determine the specific kind of object
740 * @exception IOException if an I/O error occurs while
741 * getting the content.
742 * @exception UnknownServiceException if the protocol does not support
744 * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
745 * @see java.net.URLConnection#getContentType()
746 * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
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.
753 return getContentHandler().getContent(this);
757 * Retrieves the contents of this URL connection.
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
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)
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.
781 return getContentHandler().getContent(this, classes);
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.
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
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.
815 * @return the permission object representing the permission
816 * necessary to make the connection represented by this
819 * @exception IOException if the computation of the permission
820 * requires network or file I/O and an exception occurs while
823 // public Permission getPermission() throws IOException {
824 // return SecurityConstants.ALL_PERMISSION;
828 * Returns an input stream that reads from this open connection.
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.
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
839 * @see #setReadTimeout(int)
840 * @see #getReadTimeout()
842 public InputStream getInputStream() throws IOException {
843 throw new UnknownServiceException("protocol doesn't support input");
847 * Returns an output stream that writes to this connection.
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
855 public OutputStream getOutputStream() throws IOException {
856 throw new UnknownServiceException("protocol doesn't support output");
860 * Returns a <code>String</code> representation of this URL connection.
862 * @return a string representation of this <code>URLConnection</code>.
864 public String toString() {
865 return this.getClass().getName() + ":" + url;
869 * Sets the value of the <code>doInput</code> field for this
870 * <code>URLConnection</code> to the specified value.
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.
876 * @param doinput the new value.
877 * @throws IllegalStateException if already connected
878 * @see java.net.URLConnection#doInput
881 public void setDoInput(boolean doinput) {
883 throw new IllegalStateException("Already connected");
888 * Returns the value of this <code>URLConnection</code>'s
889 * <code>doInput</code> flag.
891 * @return the value of this <code>URLConnection</code>'s
892 * <code>doInput</code> flag.
893 * @see #setDoInput(boolean)
895 public boolean getDoInput() {
900 * Sets the value of the <code>doOutput</code> field for this
901 * <code>URLConnection</code> to the specified value.
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.
907 * @param dooutput the new value.
908 * @throws IllegalStateException if already connected
909 * @see #getDoOutput()
911 public void setDoOutput(boolean dooutput) {
913 throw new IllegalStateException("Already connected");
918 * Returns the value of this <code>URLConnection</code>'s
919 * <code>doOutput</code> flag.
921 * @return the value of this <code>URLConnection</code>'s
922 * <code>doOutput</code> flag.
923 * @see #setDoOutput(boolean)
925 public boolean getDoOutput() {
930 * Set the value of the <code>allowUserInteraction</code> field of
931 * this <code>URLConnection</code>.
933 * @param allowuserinteraction the new value.
934 * @throws IllegalStateException if already connected
935 * @see #getAllowUserInteraction()
937 public void setAllowUserInteraction(boolean allowuserinteraction) {
939 throw new IllegalStateException("Already connected");
940 allowUserInteraction = allowuserinteraction;
944 * Returns the value of the <code>allowUserInteraction</code> field for
947 * @return the value of the <code>allowUserInteraction</code> field for
949 * @see #setAllowUserInteraction(boolean)
951 public boolean getAllowUserInteraction() {
952 return allowUserInteraction;
956 * Sets the default value of the
957 * <code>allowUserInteraction</code> field for all future
958 * <code>URLConnection</code> objects to the specified value.
960 * @param defaultallowuserinteraction the new value.
961 * @see #getDefaultAllowUserInteraction()
963 public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {
964 defaultAllowUserInteraction = defaultallowuserinteraction;
968 * Returns the default value of the <code>allowUserInteraction</code>
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.
975 * @return the default value of the <code>allowUserInteraction</code>
977 * @see #setDefaultAllowUserInteraction(boolean)
979 public static boolean getDefaultAllowUserInteraction() {
980 return defaultAllowUserInteraction;
984 * Sets the value of the <code>useCaches</code> field of this
985 * <code>URLConnection</code> to the specified value.
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
995 * @param usecaches a <code>boolean</code> indicating whether
996 * or not to allow caching
997 * @throws IllegalStateException if already connected
998 * @see #getUseCaches()
1000 public void setUseCaches(boolean usecaches) {
1002 throw new IllegalStateException("Already connected");
1003 useCaches = usecaches;
1007 * Returns the value of this <code>URLConnection</code>'s
1008 * <code>useCaches</code> field.
1010 * @return the value of this <code>URLConnection</code>'s
1011 * <code>useCaches</code> field.
1012 * @see #setUseCaches(boolean)
1014 public boolean getUseCaches() {
1019 * Sets the value of the <code>ifModifiedSince</code> field of
1020 * this <code>URLConnection</code> to the specified value.
1022 * @param ifmodifiedsince the new value.
1023 * @throws IllegalStateException if already connected
1024 * @see #getIfModifiedSince()
1026 public void setIfModifiedSince(long ifmodifiedsince) {
1028 throw new IllegalStateException("Already connected");
1029 ifModifiedSince = ifmodifiedsince;
1033 * Returns the value of this object's <code>ifModifiedSince</code> field.
1035 * @return the value of this object's <code>ifModifiedSince</code> field.
1036 * @see #setIfModifiedSince(long)
1038 public long getIfModifiedSince() {
1039 return ifModifiedSince;
1043 * Returns the default value of a <code>URLConnection</code>'s
1044 * <code>useCaches</code> flag.
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.
1050 * @return the default value of a <code>URLConnection</code>'s
1051 * <code>useCaches</code> flag.
1052 * @see #setDefaultUseCaches(boolean)
1054 public boolean getDefaultUseCaches() {
1055 return defaultUseCaches;
1059 * Sets the default value of the <code>useCaches</code> field to the
1062 * @param defaultusecaches the new value.
1063 * @see #getDefaultUseCaches()
1065 public void setDefaultUseCaches(boolean defaultusecaches) {
1066 defaultUseCaches = defaultusecaches;
1070 * Sets the general request property. If a property with the key already
1071 * exists, overwrite its value with the new value.
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.
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)
1085 public void setRequestProperty(String key, String value) {
1087 throw new IllegalStateException("Already connected");
1089 throw new NullPointerException ("key is null");
1091 if (requests == null)
1092 requests = new MessageHeader();
1094 requests.set(key, value);
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.
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()
1110 public void addRequestProperty(String key, String value) {
1112 throw new IllegalStateException("Already connected");
1114 throw new NullPointerException ("key is null");
1116 if (requests == null)
1117 requests = new MessageHeader();
1119 requests.add(key, value);
1124 * Returns the value of the named general request property for this
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)
1133 public String getRequestProperty(String key) {
1135 throw new IllegalStateException("Already connected");
1137 if (requests == null)
1140 return requests.findValue(key);
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
1151 * @return a Map of the general request properties for this connection.
1152 * @throws IllegalStateException if already connected
1155 public Map<String,List<String>> getRequestProperties() {
1157 throw new IllegalStateException("Already connected");
1159 if (requests == null)
1160 return Collections.EMPTY_MAP;
1162 return requests.getHeaders(null);
1166 * Sets the default value of a general request property. When a
1167 * <code>URLConnection</code> is created, it is initialized with
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.
1174 * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String)
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.
1180 * @see #getDefaultRequestProperty(java.lang.String)
1183 public static void setDefaultRequestProperty(String key, String value) {
1187 * Returns the value of the default request property. Default request
1188 * properties are set for every connection.
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.
1194 * @see java.net.URLConnection#getRequestProperty(java.lang.String)
1196 * @deprecated The instance specific getRequestProperty method
1197 * should be used after an appropriate instance of URLConnection
1200 * @see #setDefaultRequestProperty(java.lang.String, java.lang.String)
1203 public static String getDefaultRequestProperty(String key) {
1208 * The ContentHandler factory.
1210 static ContentHandlerFactory factory;
1213 * Sets the <code>ContentHandlerFactory</code> of an
1214 * application. It can be called at most once by an application.
1216 * The <code>ContentHandlerFactory</code> instance is used to
1217 * construct a content handler from a content type
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.
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
1232 public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {
1233 throw new SecurityException();
1236 private static Hashtable handlers = new Hashtable();
1239 * Gets the Content Handler appropriate for this connection.
1240 * @param connection the connection to use.
1242 synchronized ContentHandler getContentHandler()
1243 throws UnknownServiceException
1245 String contentType = stripOffParameters(getContentType());
1246 ContentHandler handler = null;
1247 if (contentType == null)
1248 throw new UnknownServiceException("no content-type");
1250 handler = (ContentHandler) handlers.get(contentType);
1251 if (handler != null)
1253 } catch(Exception e) {
1256 if (factory != null)
1257 handler = factory.createContentHandler(contentType);
1258 if (handler == null) {
1260 handler = lookupContentHandlerClassFor(contentType);
1261 } catch(Exception e) {
1262 e.printStackTrace();
1263 handler = UnknownContentHandler.INSTANCE;
1265 handlers.put(contentType, handler);
1271 * Media types are in the format: type/subtype*(; parameter).
1272 * For looking up the content handler, we should ignore those
1275 private String stripOffParameters(String contentType)
1277 if (contentType == null)
1279 int index = contentType.indexOf(';');
1282 return contentType.substring(0, index);
1287 private static final String contentClassPrefix = "sun.net.www.content";
1288 private static final String contentPathProp = "java.content.handler.pkgs";
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:
1297 * {package-prefix}.{major}.{minor}
1299 * YoyoDyne.experimental.text.plain
1302 private ContentHandler lookupContentHandlerClassFor(String contentType)
1303 throws InstantiationException, IllegalAccessException, ClassNotFoundException {
1304 String contentHandlerClassName = typeToPackageName(contentType);
1306 String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes();
1308 StringTokenizer packagePrefixIter =
1309 new StringTokenizer(contentHandlerPkgPrefixes, "|");
1311 while (packagePrefixIter.hasMoreTokens()) {
1312 String packagePrefix = packagePrefixIter.nextToken().trim();
1315 String clsName = packagePrefix + "." + contentHandlerClassName;
1318 cls = Class.forName(clsName);
1319 } catch (ClassNotFoundException e) {
1320 ClassLoader cl = ClassLoader.getSystemClassLoader();
1322 cls = cl.loadClass(clsName);
1326 ContentHandler handler =
1327 (ContentHandler)cls.newInstance();
1330 } catch(Exception e) {
1334 return UnknownContentHandler.INSTANCE;
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"
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++) {
1352 } else if (!('A' <= c && c <= 'Z' ||
1353 'a' <= c && c <= 'z' ||
1354 '0' <= c && c <= '9')) {
1358 return new String(nm);
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.
1369 private String getContentHandlerPkgPrefixes() {
1370 String packagePrefixList = "";
1372 if (packagePrefixList != "") {
1373 packagePrefixList += "|";
1376 return packagePrefixList + contentClassPrefix;
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.
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()
1390 public static String guessContentTypeFromName(String fname) {
1391 return getFileNameMap().getContentTypeFor(fname);
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.
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.
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
1411 * @see java.io.InputStream#mark(int)
1412 * @see java.io.InputStream#markSupported()
1413 * @see java.net.URLConnection#getContentType()
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())
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();
1440 if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {
1441 return "application/java-vm";
1444 if (c1 == 0xAC && c2 == 0xED) {
1445 // next two bytes are version number, currently 0x00 0x05
1446 return "application/x-java-serialized-object";
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')))) {
1460 if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') {
1461 return "application/xml";
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";
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";
1480 if (c1 == 0xff && c2 == 0xfe) {
1481 if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 &&
1482 c7 == 'x' && c8 == 0) {
1483 return "application/xml";
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";
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";
1504 if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
1508 if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
1509 return "image/x-bitmap";
1512 if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
1513 c5 == 'M' && c6 == '2') {
1514 return "image/x-pixmap";
1517 if (c1 == 137 && c2 == 80 && c3 == 78 &&
1518 c4 == 71 && c5 == 13 && c6 == 10 &&
1519 c7 == 26 && c8 == 10) {
1523 if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {
1525 return "image/jpeg";
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
1535 (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' &&
1537 return "image/jpeg";
1545 if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 &&
1546 c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {
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.
1553 return "image/vnd.fpx";
1557 if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) {
1558 return "audio/basic"; // .au format, big endian
1561 if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) {
1562 return "audio/basic"; // .au format, little endian
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
1569 return "audio/x-wav";
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.
1580 static private boolean checkfpx(InputStream is) throws IOException {
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
1587 * Offset to Fpx ClsID from beginning of stream should be:
1589 * FpxClsidOffset = rootEntryOffset + clsidOffset
1591 * where: clsidOffset = 0x50.
1592 * rootEntryOffset = headerSize + sectorSize*sectDirStart
1593 * + 128*rootEntryDirectory
1595 * where: headerSize = 0x200 (always)
1596 * sectorSize = 2 raised to power of uSectorShift,
1597 * which is found in the header at
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)
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
1612 // Get the byte ordering located at 0x1E. 0xFE is Intel,
1614 long toSkip = (long)0x1C;
1617 if ((posn = skipForward(is, toSkip)) < toSkip) {
1622 int c[] = new int[16];
1623 if (readBytes(c, 2, is) < 0) {
1628 int byteOrder = c[0];
1632 if (readBytes(c, 2, is) < 0) {
1637 if(byteOrder == 0xFE) {
1638 uSectorShift = c[0];
1639 uSectorShift += c[1] << 8;
1642 uSectorShift = c[0] << 8;
1643 uSectorShift += c[1];
1647 toSkip = (long)0x30 - posn;
1649 if ((skipped = skipForward(is, toSkip)) < toSkip) {
1655 if (readBytes(c, 4, is) < 0) {
1661 if(byteOrder == 0xFE) {
1662 sectDirStart = c[0];
1663 sectDirStart += c[1] << 8;
1664 sectDirStart += c[2] << 16;
1665 sectDirStart += c[3] << 24;
1667 sectDirStart = c[0] << 24;
1668 sectDirStart += c[1] << 16;
1669 sectDirStart += c[2] << 8;
1670 sectDirStart += c[3];
1673 is.reset(); // Reset back to the beginning
1675 toSkip = 0x200L + (long)(1<<uSectorShift)*sectDirStart + 0x50L;
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
1688 is.mark((int)toSkip+0x30);
1690 if ((skipForward(is, toSkip)) < toSkip) {
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
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.
1703 * Test against this, ignoring second byte (Intel) since
1704 * this could change depending on part of Fpx file we have.
1707 if (readBytes(c, 16, is) < 0) {
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) {
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) {
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
1741 static private int readBytes(int c[], int len, InputStream is)
1742 throws IOException {
1744 byte buf[] = new byte[len];
1745 if (is.read(buf, 0, len) < len) {
1749 // fill the passed in int array
1750 for (int i = 0; i < len; i++) {
1751 c[i] = buf[i] & 0xff;
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
1762 static private long skipForward(InputStream is, long toSkip)
1763 throws IOException {
1768 while (skipped != toSkip) {
1769 eachSkip = is.skip(toSkip - skipped);
1771 // check if EOF is reached
1772 if (eachSkip <= 0) {
1773 if (is.read() == -1) {
1779 skipped += eachSkip;
1787 class UnknownContentHandler extends ContentHandler {
1788 static final ContentHandler INSTANCE = new UnknownContentHandler();
1790 public Object getContent(URLConnection uc) throws IOException {
1791 return uc.getInputStream();
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[];
1807 public MessageHeader () {
1811 public MessageHeader (InputStream is) throws java.io.IOException {
1816 * Reset a message header (all key/values removed)
1818 public synchronized void reset() {
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.
1831 public synchronized String findValue(String k) {
1833 for (int i = nkeys; --i >= 0;)
1834 if (keys[i] == null)
1837 for (int i = nkeys; --i >= 0;) {
1838 if (k.equalsIgnoreCase(keys[i]))
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])))
1853 public synchronized String getKey(int n) {
1854 if (n < 0 || n >= nkeys) return null;
1858 public synchronized String getValue(int n) {
1859 if (n < 0 || n >= nkeys) return null;
1863 /** Deprecated: Use multiValueIterator() instead.
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:
1869 * for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) {
1874 public synchronized String findNextValue(String k, String v) {
1875 boolean foundV = false;
1877 for (int i = nkeys; --i >= 0;)
1878 if (keys[i] == null)
1881 else if (values[i] == v)
1884 for (int i = nkeys; --i >= 0;)
1885 if (k.equalsIgnoreCase(keys[i]))
1888 else if (values[i] == v)
1893 class HeaderIterator implements Iterator<String> {
1897 boolean haveNext = false;
1900 public HeaderIterator (String k, Object lock) {
1904 public boolean hasNext () {
1905 synchronized (lock) {
1909 while (index < nkeys) {
1910 if (key.equalsIgnoreCase (keys[index])) {
1920 public String next() {
1921 synchronized (lock) {
1924 return values [next];
1929 throw new NoSuchElementException ("No more elements");
1933 public void remove () {
1934 throw new UnsupportedOperationException ("remove not allowed");
1939 * return an Iterator that returns all values of a particular
1942 public Iterator<String> multiValueIterator (String k) {
1943 return new HeaderIterator (k, this);
1946 public synchronized Map<String, List<String>> getHeaders() {
1947 return getHeaders(null);
1950 public synchronized Map<String, List<String>> getHeaders(String[] excludeList) {
1951 return filterAndAddHeaders(excludeList, null);
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]))) {
1970 List<String> l = m.get(keys[i]);
1972 l = new ArrayList<String>();
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());
1988 l = new ArrayList();
1989 m.put((String)entry.getKey(), l);
1991 l.add(entry.getValue());
1995 for (String key : m.keySet()) {
1996 m.put(key, Collections.unmodifiableList(m.get(key)));
1999 return Collections.unmodifiableMap(m);
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) {
2009 (values[i] != null ? ": "+values[i]: "") + "\r\n");
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) {
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) {
2028 for (int i = nkeys; i > 0; i--) {
2029 keys[i] = keys[i-1];
2030 values[i] = values[i-1];
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.
2042 public synchronized void set(int i, String k, String v) {
2046 } else if (i >= nkeys) {
2055 /** grow the key/value arrays as needed */
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];
2062 System.arraycopy(keys, 0, nk, 0, nkeys);
2064 System.arraycopy(values, 0, nv, 0, nkeys);
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
2077 public synchronized void remove(String k) {
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];
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];
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])) {
2114 /** Set's the value of a key only if there is no
2115 * key with that value already.
2118 public synchronized void setIfNotSet(String k, String v) {
2119 if (findValue(k) == null) {
2124 /** Convert a message-id string to canonical form (strips off
2125 leading and trailing <>s) */
2126 public static String canonicalID(String id) {
2130 int len = id.length();
2131 boolean substr = false;
2133 while (st < len && ((c = id.charAt(st)) == '<' ||
2138 while (st < len && ((c = id.charAt(len - 1)) == '>' ||
2143 return substr ? id.substring(st, len) : id;
2146 /** Parse a MIME header from an input stream. */
2147 public void parseHeader(InputStream is) throws java.io.IOException {
2148 synchronized (this) {
2154 /** Parse and merge a MIME header from an input stream. */
2155 public void mergeHeader(InputStream is) throws java.io.IOException {
2158 char s[] = new char[10];
2159 int firstc = is.read();
2160 while (firstc != '\n' && firstc != '\r' && firstc >= 0) {
2164 boolean inKey = firstc > ' ';
2165 s[len++] = (char) firstc;
2167 while ((c = is.read()) >= 0) {
2170 if (inKey && len > 0)
2182 if (c == '\r' && firstc == '\n') {
2187 if (firstc == '\n' || firstc == '\r' || firstc > ' ')
2193 if (len >= s.length) {
2194 char ns[] = new char[s.length * 2];
2195 System.arraycopy(s, 0, ns, 0, len);
2198 s[len++] = (char) c;
2202 while (len > 0 && s[len - 1] <= ' ')
2209 k = String.copyValueOf(s, 0, keyend);
2210 if (keyend < len && s[keyend] == ':')
2212 while (keyend < len && s[keyend] <= ' ')
2219 v = String.copyValueOf(s, keyend, len - keyend);
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]+"}";
2233 interface ContentHandlerFactory {
2235 public ContentHandler createContentHandler(String contentType);
2238 abstract class ContentHandler {
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.
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.
2248 abstract public Object getContent(URLConnection urlc) throws IOException;
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.
2255 * The default implementation of this method should call getContent()
2256 * and screen the return type for a match of the suggested types.
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.
2266 public Object getContent(URLConnection urlc, Class[] classes) throws IOException {
2267 Object obj = getContent(urlc);
2269 for (int i = 0; i < classes.length; i++) {
2270 if (classes[i].isInstance(obj)) {
2278 class UnknownServiceException extends IOException {
2279 private static final long serialVersionUID = -4169033248853639508L;
2282 * Constructs a new <code>UnknownServiceException</code> with no
2285 public UnknownServiceException() {
2289 * Constructs a new <code>UnknownServiceException</code> with the
2290 * specified detail message.
2292 * @param msg the detail message.
2294 public UnknownServiceException(String msg) {
2299 * A simple interface which provides a mechanism to map
2300 * between a file name and a MIME type string.
2302 * @author Steven B. Byrne
2305 interface FileNameMap {
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.
2313 public String getContentTypeFor(String fileName);