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.util.Hashtable;
32 import java.util.Date;
33 import java.util.StringTokenizer;
34 import java.util.Collections;
36 import java.util.List;
37 import java.security.Permission;
38 import java.security.AccessController;
39 import sun.security.util.SecurityConstants;
40 import sun.net.www.MessageHeader;
43 * The abstract class <code>URLConnection</code> is the superclass
44 * of all classes that represent a communications link between the
45 * application and a URL. Instances of this class can be used both to
46 * read from and to write to the resource referenced by the URL. In
47 * general, creating a connection to a URL is a multistep process:
49 * <center><table border=2 summary="Describes the process of creating a connection to a URL: openConnection() and connect() over time.">
50 * <tr><th><code>openConnection()</code></th>
51 * <th><code>connect()</code></th></tr>
52 * <tr><td>Manipulate parameters that affect the connection to the remote
54 * <td>Interact with the resource; query header fields and
57 * ---------------------------->
61 * <li>The connection object is created by invoking the
62 * <code>openConnection</code> method on a URL.
63 * <li>The setup parameters and general request properties are manipulated.
64 * <li>The actual connection to the remote object is made, using the
65 * <code>connect</code> method.
66 * <li>The remote object becomes available. The header fields and the contents
67 * of the remote object can be accessed.
70 * The setup parameters are modified using the following methods:
72 * <li><code>setAllowUserInteraction</code>
73 * <li><code>setDoInput</code>
74 * <li><code>setDoOutput</code>
75 * <li><code>setIfModifiedSince</code>
76 * <li><code>setUseCaches</code>
79 * and the general request properties are modified using the method:
81 * <li><code>setRequestProperty</code>
84 * Default values for the <code>AllowUserInteraction</code> and
85 * <code>UseCaches</code> parameters can be set using the methods
86 * <code>setDefaultAllowUserInteraction</code> and
87 * <code>setDefaultUseCaches</code>.
89 * Each of the above <code>set</code> methods has a corresponding
90 * <code>get</code> method to retrieve the value of the parameter or
91 * general request property. The specific parameters and general
92 * request properties that are applicable are protocol specific.
94 * The following methods are used to access the header fields and
95 * the contents after the connection is made to the remote object:
97 * <li><code>getContent</code>
98 * <li><code>getHeaderField</code>
99 * <li><code>getInputStream</code>
100 * <li><code>getOutputStream</code>
103 * Certain header fields are accessed frequently. The methods:
105 * <li><code>getContentEncoding</code>
106 * <li><code>getContentLength</code>
107 * <li><code>getContentType</code>
108 * <li><code>getDate</code>
109 * <li><code>getExpiration</code>
110 * <li><code>getLastModifed</code>
113 * provide convenient access to these fields. The
114 * <code>getContentType</code> method is used by the
115 * <code>getContent</code> method to determine the type of the remote
116 * object; subclasses may find it convenient to override the
117 * <code>getContentType</code> method.
119 * In the common case, all of the pre-connection parameters and
120 * general request properties can be ignored: the pre-connection
121 * parameters and request properties default to sensible values. For
122 * most clients of this interface, there are only two interesting
123 * methods: <code>getInputStream</code> and <code>getContent</code>,
124 * which are mirrored in the <code>URL</code> class by convenience methods.
126 * More information on the request properties and header fields of
127 * an <code>http</code> connection can be found at:
129 * <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a>
130 * </pre></blockquote>
132 * Note about <code>fileNameMap</code>: In versions prior to JDK 1.1.6,
133 * field <code>fileNameMap</code> of <code>URLConnection</code> was public.
134 * In JDK 1.1.6 and later, <code>fileNameMap</code> is private; accessor
135 * and mutator methods {@link #getFileNameMap() getFileNameMap} and
136 * {@link #setFileNameMap(java.net.FileNameMap) setFileNameMap} are added
137 * to access it. This change is also described on the <a href=
138 * "http://java.sun.com/products/jdk/1.2/compatibility.html">
139 * Compatibility</a> page.
141 * Invoking the <tt>close()</tt> methods on the <tt>InputStream</tt> or <tt>OutputStream</tt> of an
142 * <tt>URLConnection</tt> after a request may free network resources associated with this
143 * instance, unless particular protocol specifications specify different behaviours
146 * @author James Gosling
147 * @see java.net.URL#openConnection()
148 * @see java.net.URLConnection#connect()
149 * @see java.net.URLConnection#getContent()
150 * @see java.net.URLConnection#getContentEncoding()
151 * @see java.net.URLConnection#getContentLength()
152 * @see java.net.URLConnection#getContentType()
153 * @see java.net.URLConnection#getDate()
154 * @see java.net.URLConnection#getExpiration()
155 * @see java.net.URLConnection#getHeaderField(int)
156 * @see java.net.URLConnection#getHeaderField(java.lang.String)
157 * @see java.net.URLConnection#getInputStream()
158 * @see java.net.URLConnection#getLastModified()
159 * @see java.net.URLConnection#getOutputStream()
160 * @see java.net.URLConnection#setAllowUserInteraction(boolean)
161 * @see java.net.URLConnection#setDefaultUseCaches(boolean)
162 * @see java.net.URLConnection#setDoInput(boolean)
163 * @see java.net.URLConnection#setDoOutput(boolean)
164 * @see java.net.URLConnection#setIfModifiedSince(long)
165 * @see java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String)
166 * @see java.net.URLConnection#setUseCaches(boolean)
169 public abstract class URLConnection {
172 * The URL represents the remote object on the World Wide Web to
173 * which this connection is opened.
175 * The value of this field can be accessed by the
176 * <code>getURL</code> method.
178 * The default value of this variable is the value of the URL
179 * argument in the <code>URLConnection</code> constructor.
181 * @see java.net.URLConnection#getURL()
182 * @see java.net.URLConnection#url
187 * This variable is set by the <code>setDoInput</code> method. Its
188 * value is returned by the <code>getDoInput</code> method.
190 * A URL connection can be used for input and/or output. Setting the
191 * <code>doInput</code> flag to <code>true</code> indicates that
192 * the application intends to read data from the URL connection.
194 * The default value of this field is <code>true</code>.
196 * @see java.net.URLConnection#getDoInput()
197 * @see java.net.URLConnection#setDoInput(boolean)
199 protected boolean doInput = true;
202 * This variable is set by the <code>setDoOutput</code> method. Its
203 * value is returned by the <code>getDoOutput</code> method.
205 * A URL connection can be used for input and/or output. Setting the
206 * <code>doOutput</code> flag to <code>true</code> indicates
207 * that the application intends to write data to the URL connection.
209 * The default value of this field is <code>false</code>.
211 * @see java.net.URLConnection#getDoOutput()
212 * @see java.net.URLConnection#setDoOutput(boolean)
214 protected boolean doOutput = false;
216 private static boolean defaultAllowUserInteraction = false;
219 * If <code>true</code>, this <code>URL</code> is being examined in
220 * a context in which it makes sense to allow user interactions such
221 * as popping up an authentication dialog. If <code>false</code>,
222 * then no user interaction is allowed.
224 * The value of this field can be set by the
225 * <code>setAllowUserInteraction</code> method.
226 * Its value is returned by the
227 * <code>getAllowUserInteraction</code> method.
228 * Its default value is the value of the argument in the last invocation
229 * of the <code>setDefaultAllowUserInteraction</code> method.
231 * @see java.net.URLConnection#getAllowUserInteraction()
232 * @see java.net.URLConnection#setAllowUserInteraction(boolean)
233 * @see java.net.URLConnection#setDefaultAllowUserInteraction(boolean)
235 protected boolean allowUserInteraction = defaultAllowUserInteraction;
237 private static boolean defaultUseCaches = true;
240 * If <code>true</code>, the protocol is allowed to use caching
241 * whenever it can. If <code>false</code>, the protocol must always
242 * try to get a fresh copy of the object.
244 * This field is set by the <code>setUseCaches</code> method. Its
245 * value is returned by the <code>getUseCaches</code> method.
247 * Its default value is the value given in the last invocation of the
248 * <code>setDefaultUseCaches</code> method.
250 * @see java.net.URLConnection#setUseCaches(boolean)
251 * @see java.net.URLConnection#getUseCaches()
252 * @see java.net.URLConnection#setDefaultUseCaches(boolean)
254 protected boolean useCaches = defaultUseCaches;
257 * Some protocols support skipping the fetching of the object unless
258 * the object has been modified more recently than a certain time.
260 * A nonzero value gives a time as the number of milliseconds since
261 * January 1, 1970, GMT. The object is fetched only if it has been
262 * modified more recently than that time.
264 * This variable is set by the <code>setIfModifiedSince</code>
265 * method. Its value is returned by the
266 * <code>getIfModifiedSince</code> method.
268 * The default value of this field is <code>0</code>, indicating
269 * that the fetching must always occur.
271 * @see java.net.URLConnection#getIfModifiedSince()
272 * @see java.net.URLConnection#setIfModifiedSince(long)
274 protected long ifModifiedSince = 0;
277 * If <code>false</code>, this connection object has not created a
278 * communications link to the specified URL. If <code>true</code>,
279 * the communications link has been established.
281 protected boolean connected = false;
286 private int connectTimeout;
287 private int readTimeout;
292 private MessageHeader requests;
297 private static FileNameMap fileNameMap;
302 private static boolean fileNameMapLoaded = false;
305 * Loads filename map (a mimetable) from a data file. It will
306 * first try to load the user-specific table, defined
307 * by "content.types.user.table" property. If that fails,
308 * it tries to load the default built-in table at
309 * lib/content-types.properties under java home.
311 * @return the FileNameMap
313 * @see #setFileNameMap(java.net.FileNameMap)
315 public static synchronized FileNameMap getFileNameMap() {
316 if ((fileNameMap == null) && !fileNameMapLoaded) {
317 fileNameMap = sun.net.www.MimeTable.loadTable();
318 fileNameMapLoaded = true;
321 return new FileNameMap() {
322 private FileNameMap map = fileNameMap;
323 public String getContentTypeFor(String fileName) {
324 return map.getContentTypeFor(fileName);
330 * Sets the FileNameMap.
332 * If there is a security manager, this method first calls
333 * the security manager's <code>checkSetFactory</code> method
334 * to ensure the operation is allowed.
335 * This could result in a SecurityException.
337 * @param map the FileNameMap to be set
338 * @exception SecurityException if a security manager exists and its
339 * <code>checkSetFactory</code> method doesn't allow the operation.
340 * @see SecurityManager#checkSetFactory
341 * @see #getFileNameMap()
344 public static void setFileNameMap(FileNameMap map) {
345 SecurityManager sm = System.getSecurityManager();
346 if (sm != null) sm.checkSetFactory();
351 * Opens a communications link to the resource referenced by this
352 * URL, if such a connection has not already been established.
354 * If the <code>connect</code> method is called when the connection
355 * has already been opened (indicated by the <code>connected</code>
356 * field having the value <code>true</code>), the call is ignored.
358 * URLConnection objects go through two phases: first they are
359 * created, then they are connected. After being created, and
360 * before being connected, various options can be specified
361 * (e.g., doInput and UseCaches). After connecting, it is an
362 * error to try to set them. Operations that depend on being
363 * connected, like getContentLength, will implicitly perform the
364 * connection, if necessary.
366 * @throws SocketTimeoutException if the timeout expires before
367 * the connection can be established
368 * @exception IOException if an I/O error occurs while opening the
370 * @see java.net.URLConnection#connected
371 * @see #getConnectTimeout()
372 * @see #setConnectTimeout(int)
374 abstract public void connect() throws IOException;
377 * Sets a specified timeout value, in milliseconds, to be used
378 * when opening a communications link to the resource referenced
379 * by this URLConnection. If the timeout expires before the
380 * connection can be established, a
381 * java.net.SocketTimeoutException is raised. A timeout of zero is
382 * interpreted as an infinite timeout.
384 * <p> Some non-standard implmentation of this method may ignore
385 * the specified timeout. To see the connect timeout set, please
386 * call getConnectTimeout().
388 * @param timeout an <code>int</code> that specifies the connect
389 * timeout value in milliseconds
390 * @throws IllegalArgumentException if the timeout parameter is negative
392 * @see #getConnectTimeout()
396 public void setConnectTimeout(int timeout) {
398 throw new IllegalArgumentException("timeout can not be negative");
400 connectTimeout = timeout;
404 * Returns setting for connect timeout.
406 * 0 return implies that the option is disabled
407 * (i.e., timeout of infinity).
409 * @return an <code>int</code> that indicates the connect timeout
410 * value in milliseconds
411 * @see #setConnectTimeout(int)
415 public int getConnectTimeout() {
416 return connectTimeout;
420 * Sets the read timeout to a specified timeout, in
421 * milliseconds. A non-zero value specifies the timeout when
422 * reading from Input stream when a connection is established to a
423 * resource. If the timeout expires before there is data available
424 * for read, a java.net.SocketTimeoutException is raised. A
425 * timeout of zero is interpreted as an infinite timeout.
427 *<p> Some non-standard implementation of this method ignores the
428 * specified timeout. To see the read timeout set, please call
431 * @param timeout an <code>int</code> that specifies the timeout
432 * value to be used in milliseconds
433 * @throws IllegalArgumentException if the timeout parameter is negative
435 * @see #getReadTimeout()
436 * @see InputStream#read()
439 public void setReadTimeout(int timeout) {
441 throw new IllegalArgumentException("timeout can not be negative");
443 readTimeout = timeout;
447 * Returns setting for read timeout. 0 return implies that the
448 * option is disabled (i.e., timeout of infinity).
450 * @return an <code>int</code> that indicates the read timeout
451 * value in milliseconds
453 * @see #setReadTimeout(int)
454 * @see InputStream#read()
457 public int getReadTimeout() {
462 * Constructs a URL connection to the specified URL. A connection to
463 * the object referenced by the URL is not created.
465 * @param url the specified URL.
467 protected URLConnection(URL url) {
472 * Returns the value of this <code>URLConnection</code>'s <code>URL</code>
475 * @return the value of this <code>URLConnection</code>'s <code>URL</code>
477 * @see java.net.URLConnection#url
479 public URL getURL() {
484 * Returns the value of the <code>content-length</code> header field.
486 * <B>Note</B>: {@link #getContentLengthLong() getContentLengthLong()}
487 * should be preferred over this method, since it returns a {@code long}
488 * instead and is therefore more portable.</P>
490 * @return the content length of the resource that this connection's URL
491 * references, {@code -1} if the content length is not known,
492 * or if the content length is greater than Integer.MAX_VALUE.
494 public int getContentLength() {
495 long l = getContentLengthLong();
496 if (l > Integer.MAX_VALUE)
502 * Returns the value of the <code>content-length</code> header field as a
505 * @return the content length of the resource that this connection's URL
506 * references, or <code>-1</code> if the content length is
510 public long getContentLengthLong() {
511 return getHeaderFieldLong("content-length", -1);
515 * Returns the value of the <code>content-type</code> header field.
517 * @return the content type of the resource that the URL references,
518 * or <code>null</code> if not known.
519 * @see java.net.URLConnection#getHeaderField(java.lang.String)
521 public String getContentType() {
522 return getHeaderField("content-type");
526 * Returns the value of the <code>content-encoding</code> header field.
528 * @return the content encoding of the resource that the URL references,
529 * or <code>null</code> if not known.
530 * @see java.net.URLConnection#getHeaderField(java.lang.String)
532 public String getContentEncoding() {
533 return getHeaderField("content-encoding");
537 * Returns the value of the <code>expires</code> header field.
539 * @return the expiration date of the resource that this URL references,
540 * or 0 if not known. The value is the number of milliseconds since
541 * January 1, 1970 GMT.
542 * @see java.net.URLConnection#getHeaderField(java.lang.String)
544 public long getExpiration() {
545 return getHeaderFieldDate("expires", 0);
549 * Returns the value of the <code>date</code> header field.
551 * @return the sending date of the resource that the URL references,
552 * or <code>0</code> if not known. The value returned is the
553 * number of milliseconds since January 1, 1970 GMT.
554 * @see java.net.URLConnection#getHeaderField(java.lang.String)
556 public long getDate() {
557 return getHeaderFieldDate("date", 0);
561 * Returns the value of the <code>last-modified</code> header field.
562 * The result is the number of milliseconds since January 1, 1970 GMT.
564 * @return the date the resource referenced by this
565 * <code>URLConnection</code> was last modified, or 0 if not known.
566 * @see java.net.URLConnection#getHeaderField(java.lang.String)
568 public long getLastModified() {
569 return getHeaderFieldDate("last-modified", 0);
573 * Returns the value of the named header field.
575 * If called on a connection that sets the same header multiple times
576 * with possibly different values, only the last value is returned.
579 * @param name the name of a header field.
580 * @return the value of the named header field, or <code>null</code>
581 * if there is no such field in the header.
583 public String getHeaderField(String name) {
588 * Returns an unmodifiable Map of the header fields.
589 * The Map keys are Strings that represent the
590 * response-header field names. Each Map value is an
591 * unmodifiable List of Strings that represents
592 * the corresponding field values.
594 * @return a Map of header fields
597 public Map<String,List<String>> getHeaderFields() {
598 return Collections.EMPTY_MAP;
602 * Returns the value of the named field parsed as a number.
604 * This form of <code>getHeaderField</code> exists because some
605 * connection types (e.g., <code>http-ng</code>) have pre-parsed
606 * headers. Classes for that connection type can override this method
607 * and short-circuit the parsing.
609 * @param name the name of the header field.
610 * @param Default the default value.
611 * @return the value of the named field, parsed as an integer. The
612 * <code>Default</code> value is returned if the field is
613 * missing or malformed.
615 public int getHeaderFieldInt(String name, int Default) {
616 String value = getHeaderField(name);
618 return Integer.parseInt(value);
619 } catch (Exception e) { }
624 * Returns the value of the named field parsed as a number.
626 * This form of <code>getHeaderField</code> exists because some
627 * connection types (e.g., <code>http-ng</code>) have pre-parsed
628 * headers. Classes for that connection type can override this method
629 * and short-circuit the parsing.
631 * @param name the name of the header field.
632 * @param Default the default value.
633 * @return the value of the named field, parsed as a long. The
634 * <code>Default</code> value is returned if the field is
635 * missing or malformed.
638 public long getHeaderFieldLong(String name, long Default) {
639 String value = getHeaderField(name);
641 return Long.parseLong(value);
642 } catch (Exception e) { }
647 * Returns the value of the named field parsed as date.
648 * The result is the number of milliseconds since January 1, 1970 GMT
649 * represented by the named field.
651 * This form of <code>getHeaderField</code> exists because some
652 * connection types (e.g., <code>http-ng</code>) have pre-parsed
653 * headers. Classes for that connection type can override this method
654 * and short-circuit the parsing.
656 * @param name the name of the header field.
657 * @param Default a default value.
658 * @return the value of the field, parsed as a date. The value of the
659 * <code>Default</code> argument is returned if the field is
660 * missing or malformed.
662 public long getHeaderFieldDate(String name, long Default) {
663 String value = getHeaderField(name);
665 return Date.parse(value);
666 } catch (Exception e) { }
671 * Returns the key for the <code>n</code><sup>th</sup> header field.
672 * It returns <code>null</code> if there are fewer than <code>n+1</code> fields.
674 * @param n an index, where n>=0
675 * @return the key for the <code>n</code><sup>th</sup> header field,
676 * or <code>null</code> if there are fewer than <code>n+1</code>
679 public String getHeaderFieldKey(int n) {
684 * Returns the value for the <code>n</code><sup>th</sup> header field.
685 * It returns <code>null</code> if there are fewer than
686 * <code>n+1</code>fields.
688 * This method can be used in conjunction with the
689 * {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all
690 * the headers in the message.
692 * @param n an index, where n>=0
693 * @return the value of the <code>n</code><sup>th</sup> header field
694 * or <code>null</code> if there are fewer than <code>n+1</code> fields
695 * @see java.net.URLConnection#getHeaderFieldKey(int)
697 public String getHeaderField(int n) {
702 * Retrieves the contents of this URL connection.
704 * This method first determines the content type of the object by
705 * calling the <code>getContentType</code> method. If this is
706 * the first time that the application has seen that specific content
707 * type, a content handler for that content type is created:
709 * <li>If the application has set up a content handler factory instance
710 * using the <code>setContentHandlerFactory</code> method, the
711 * <code>createContentHandler</code> method of that instance is called
712 * with the content type as an argument; the result is a content
713 * handler for that content type.
714 * <li>If no content handler factory has yet been set up, or if the
715 * factory's <code>createContentHandler</code> method returns
716 * <code>null</code>, then the application loads the class named:
718 * sun.net.www.content.<<i>contentType</i>>
719 * </pre></blockquote>
720 * where <<i>contentType</i>> is formed by taking the
721 * content-type string, replacing all slash characters with a
722 * <code>period</code> ('.'), and all other non-alphanumeric characters
723 * with the underscore character '<code>_</code>'. The alphanumeric
724 * characters are specifically the 26 uppercase ASCII letters
725 * '<code>A</code>' through '<code>Z</code>', the 26 lowercase ASCII
726 * letters '<code>a</code>' through '<code>z</code>', and the 10 ASCII
727 * digits '<code>0</code>' through '<code>9</code>'. If the specified
728 * class does not exist, or is not a subclass of
729 * <code>ContentHandler</code>, then an
730 * <code>UnknownServiceException</code> is thrown.
733 * @return the object fetched. The <code>instanceof</code> operator
734 * should be used to determine the specific kind of object
736 * @exception IOException if an I/O error occurs while
737 * getting the content.
738 * @exception UnknownServiceException if the protocol does not support
740 * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
741 * @see java.net.URLConnection#getContentType()
742 * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
744 public Object getContent() throws IOException {
745 // Must call getInputStream before GetHeaderField gets called
746 // so that FileNotFoundException has a chance to be thrown up
747 // from here without being caught.
749 return getContentHandler().getContent(this);
753 * Retrieves the contents of this URL connection.
755 * @param classes the <code>Class</code> array
756 * indicating the requested types
757 * @return the object fetched that is the first match of the type
758 * specified in the classes array. null if none of
759 * the requested types are supported.
760 * The <code>instanceof</code> operator should be used to
761 * determine the specific kind of object returned.
762 * @exception IOException if an I/O error occurs while
763 * getting the content.
764 * @exception UnknownServiceException if the protocol does not support
766 * @see java.net.URLConnection#getContent()
767 * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
768 * @see java.net.URLConnection#getContent(java.lang.Class[])
769 * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
772 public Object getContent(Class[] classes) throws IOException {
773 // Must call getInputStream before GetHeaderField gets called
774 // so that FileNotFoundException has a chance to be thrown up
775 // from here without being caught.
777 return getContentHandler().getContent(this, classes);
781 * Returns a permission object representing the permission
782 * necessary to make the connection represented by this
783 * object. This method returns null if no permission is
784 * required to make the connection. By default, this method
785 * returns <code>java.security.AllPermission</code>. Subclasses
786 * should override this method and return the permission
787 * that best represents the permission required to make a
788 * a connection to the URL. For example, a <code>URLConnection</code>
789 * representing a <code>file:</code> URL would return a
790 * <code>java.io.FilePermission</code> object.
792 * <p>The permission returned may dependent upon the state of the
793 * connection. For example, the permission before connecting may be
794 * different from that after connecting. For example, an HTTP
795 * sever, say foo.com, may redirect the connection to a different
796 * host, say bar.com. Before connecting the permission returned by
797 * the connection will represent the permission needed to connect
798 * to foo.com, while the permission returned after connecting will
801 * <p>Permissions are generally used for two purposes: to protect
802 * caches of objects obtained through URLConnections, and to check
803 * the right of a recipient to learn about a particular URL. In
804 * the first case, the permission should be obtained
805 * <em>after</em> the object has been obtained. For example, in an
806 * HTTP connection, this will represent the permission to connect
807 * to the host from which the data was ultimately fetched. In the
808 * second case, the permission should be obtained and tested
809 * <em>before</em> connecting.
811 * @return the permission object representing the permission
812 * necessary to make the connection represented by this
815 * @exception IOException if the computation of the permission
816 * requires network or file I/O and an exception occurs while
819 public Permission getPermission() throws IOException {
820 return SecurityConstants.ALL_PERMISSION;
824 * Returns an input stream that reads from this open connection.
826 * A SocketTimeoutException can be thrown when reading from the
827 * returned input stream if the read timeout expires before data
828 * is available for read.
830 * @return an input stream that reads from this open connection.
831 * @exception IOException if an I/O error occurs while
832 * creating the input stream.
833 * @exception UnknownServiceException if the protocol does not support
835 * @see #setReadTimeout(int)
836 * @see #getReadTimeout()
838 public InputStream getInputStream() throws IOException {
839 throw new UnknownServiceException("protocol doesn't support input");
843 * Returns an output stream that writes to this connection.
845 * @return an output stream that writes to this connection.
846 * @exception IOException if an I/O error occurs while
847 * creating the output stream.
848 * @exception UnknownServiceException if the protocol does not support
851 public OutputStream getOutputStream() throws IOException {
852 throw new UnknownServiceException("protocol doesn't support output");
856 * Returns a <code>String</code> representation of this URL connection.
858 * @return a string representation of this <code>URLConnection</code>.
860 public String toString() {
861 return this.getClass().getName() + ":" + url;
865 * Sets the value of the <code>doInput</code> field for this
866 * <code>URLConnection</code> to the specified value.
868 * A URL connection can be used for input and/or output. Set the DoInput
869 * flag to true if you intend to use the URL connection for input,
870 * false if not. The default is true.
872 * @param doinput the new value.
873 * @throws IllegalStateException if already connected
874 * @see java.net.URLConnection#doInput
877 public void setDoInput(boolean doinput) {
879 throw new IllegalStateException("Already connected");
884 * Returns the value of this <code>URLConnection</code>'s
885 * <code>doInput</code> flag.
887 * @return the value of this <code>URLConnection</code>'s
888 * <code>doInput</code> flag.
889 * @see #setDoInput(boolean)
891 public boolean getDoInput() {
896 * Sets the value of the <code>doOutput</code> field for this
897 * <code>URLConnection</code> to the specified value.
899 * A URL connection can be used for input and/or output. Set the DoOutput
900 * flag to true if you intend to use the URL connection for output,
901 * false if not. The default is false.
903 * @param dooutput the new value.
904 * @throws IllegalStateException if already connected
905 * @see #getDoOutput()
907 public void setDoOutput(boolean dooutput) {
909 throw new IllegalStateException("Already connected");
914 * Returns the value of this <code>URLConnection</code>'s
915 * <code>doOutput</code> flag.
917 * @return the value of this <code>URLConnection</code>'s
918 * <code>doOutput</code> flag.
919 * @see #setDoOutput(boolean)
921 public boolean getDoOutput() {
926 * Set the value of the <code>allowUserInteraction</code> field of
927 * this <code>URLConnection</code>.
929 * @param allowuserinteraction the new value.
930 * @throws IllegalStateException if already connected
931 * @see #getAllowUserInteraction()
933 public void setAllowUserInteraction(boolean allowuserinteraction) {
935 throw new IllegalStateException("Already connected");
936 allowUserInteraction = allowuserinteraction;
940 * Returns the value of the <code>allowUserInteraction</code> field for
943 * @return the value of the <code>allowUserInteraction</code> field for
945 * @see #setAllowUserInteraction(boolean)
947 public boolean getAllowUserInteraction() {
948 return allowUserInteraction;
952 * Sets the default value of the
953 * <code>allowUserInteraction</code> field for all future
954 * <code>URLConnection</code> objects to the specified value.
956 * @param defaultallowuserinteraction the new value.
957 * @see #getDefaultAllowUserInteraction()
959 public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {
960 defaultAllowUserInteraction = defaultallowuserinteraction;
964 * Returns the default value of the <code>allowUserInteraction</code>
967 * Ths default is "sticky", being a part of the static state of all
968 * URLConnections. This flag applies to the next, and all following
969 * URLConnections that are created.
971 * @return the default value of the <code>allowUserInteraction</code>
973 * @see #setDefaultAllowUserInteraction(boolean)
975 public static boolean getDefaultAllowUserInteraction() {
976 return defaultAllowUserInteraction;
980 * Sets the value of the <code>useCaches</code> field of this
981 * <code>URLConnection</code> to the specified value.
983 * Some protocols do caching of documents. Occasionally, it is important
984 * to be able to "tunnel through" and ignore the caches (e.g., the
985 * "reload" button in a browser). If the UseCaches flag on a connection
986 * is true, the connection is allowed to use whatever caches it can.
987 * If false, caches are to be ignored.
988 * The default value comes from DefaultUseCaches, which defaults to
991 * @param usecaches a <code>boolean</code> indicating whether
992 * or not to allow caching
993 * @throws IllegalStateException if already connected
994 * @see #getUseCaches()
996 public void setUseCaches(boolean usecaches) {
998 throw new IllegalStateException("Already connected");
999 useCaches = usecaches;
1003 * Returns the value of this <code>URLConnection</code>'s
1004 * <code>useCaches</code> field.
1006 * @return the value of this <code>URLConnection</code>'s
1007 * <code>useCaches</code> field.
1008 * @see #setUseCaches(boolean)
1010 public boolean getUseCaches() {
1015 * Sets the value of the <code>ifModifiedSince</code> field of
1016 * this <code>URLConnection</code> to the specified value.
1018 * @param ifmodifiedsince the new value.
1019 * @throws IllegalStateException if already connected
1020 * @see #getIfModifiedSince()
1022 public void setIfModifiedSince(long ifmodifiedsince) {
1024 throw new IllegalStateException("Already connected");
1025 ifModifiedSince = ifmodifiedsince;
1029 * Returns the value of this object's <code>ifModifiedSince</code> field.
1031 * @return the value of this object's <code>ifModifiedSince</code> field.
1032 * @see #setIfModifiedSince(long)
1034 public long getIfModifiedSince() {
1035 return ifModifiedSince;
1039 * Returns the default value of a <code>URLConnection</code>'s
1040 * <code>useCaches</code> flag.
1042 * Ths default is "sticky", being a part of the static state of all
1043 * URLConnections. This flag applies to the next, and all following
1044 * URLConnections that are created.
1046 * @return the default value of a <code>URLConnection</code>'s
1047 * <code>useCaches</code> flag.
1048 * @see #setDefaultUseCaches(boolean)
1050 public boolean getDefaultUseCaches() {
1051 return defaultUseCaches;
1055 * Sets the default value of the <code>useCaches</code> field to the
1058 * @param defaultusecaches the new value.
1059 * @see #getDefaultUseCaches()
1061 public void setDefaultUseCaches(boolean defaultusecaches) {
1062 defaultUseCaches = defaultusecaches;
1066 * Sets the general request property. If a property with the key already
1067 * exists, overwrite its value with the new value.
1069 * <p> NOTE: HTTP requires all request properties which can
1070 * legally have multiple instances with the same key
1071 * to use a comma-seperated list syntax which enables multiple
1072 * properties to be appended into a single property.
1074 * @param key the keyword by which the request is known
1075 * (e.g., "<code>Accept</code>").
1076 * @param value the value associated with it.
1077 * @throws IllegalStateException if already connected
1078 * @throws NullPointerException if key is <CODE>null</CODE>
1079 * @see #getRequestProperty(java.lang.String)
1081 public void setRequestProperty(String key, String value) {
1083 throw new IllegalStateException("Already connected");
1085 throw new NullPointerException ("key is null");
1087 if (requests == null)
1088 requests = new MessageHeader();
1090 requests.set(key, value);
1094 * Adds a general request property specified by a
1095 * key-value pair. This method will not overwrite
1096 * existing values associated with the same key.
1098 * @param key the keyword by which the request is known
1099 * (e.g., "<code>Accept</code>").
1100 * @param value the value associated with it.
1101 * @throws IllegalStateException if already connected
1102 * @throws NullPointerException if key is null
1103 * @see #getRequestProperties()
1106 public void addRequestProperty(String key, String value) {
1108 throw new IllegalStateException("Already connected");
1110 throw new NullPointerException ("key is null");
1112 if (requests == null)
1113 requests = new MessageHeader();
1115 requests.add(key, value);
1120 * Returns the value of the named general request property for this
1123 * @param key the keyword by which the request is known (e.g., "Accept").
1124 * @return the value of the named general request property for this
1125 * connection. If key is null, then null is returned.
1126 * @throws IllegalStateException if already connected
1127 * @see #setRequestProperty(java.lang.String, java.lang.String)
1129 public String getRequestProperty(String key) {
1131 throw new IllegalStateException("Already connected");
1133 if (requests == null)
1136 return requests.findValue(key);
1140 * Returns an unmodifiable Map of general request
1141 * properties for this connection. The Map keys
1142 * are Strings that represent the request-header
1143 * field names. Each Map value is a unmodifiable List
1144 * of Strings that represents the corresponding
1147 * @return a Map of the general request properties for this connection.
1148 * @throws IllegalStateException if already connected
1151 public Map<String,List<String>> getRequestProperties() {
1153 throw new IllegalStateException("Already connected");
1155 if (requests == null)
1156 return Collections.EMPTY_MAP;
1158 return requests.getHeaders(null);
1162 * Sets the default value of a general request property. When a
1163 * <code>URLConnection</code> is created, it is initialized with
1166 * @param key the keyword by which the request is known
1167 * (e.g., "<code>Accept</code>").
1168 * @param value the value associated with the key.
1170 * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String)
1172 * @deprecated The instance specific setRequestProperty method
1173 * should be used after an appropriate instance of URLConnection
1174 * is obtained. Invoking this method will have no effect.
1176 * @see #getDefaultRequestProperty(java.lang.String)
1179 public static void setDefaultRequestProperty(String key, String value) {
1183 * Returns the value of the default request property. Default request
1184 * properties are set for every connection.
1186 * @param key the keyword by which the request is known (e.g., "Accept").
1187 * @return the value of the default request property
1188 * for the specified key.
1190 * @see java.net.URLConnection#getRequestProperty(java.lang.String)
1192 * @deprecated The instance specific getRequestProperty method
1193 * should be used after an appropriate instance of URLConnection
1196 * @see #setDefaultRequestProperty(java.lang.String, java.lang.String)
1199 public static String getDefaultRequestProperty(String key) {
1204 * The ContentHandler factory.
1206 static ContentHandlerFactory factory;
1209 * Sets the <code>ContentHandlerFactory</code> of an
1210 * application. It can be called at most once by an application.
1212 * The <code>ContentHandlerFactory</code> instance is used to
1213 * construct a content handler from a content type
1215 * If there is a security manager, this method first calls
1216 * the security manager's <code>checkSetFactory</code> method
1217 * to ensure the operation is allowed.
1218 * This could result in a SecurityException.
1220 * @param fac the desired factory.
1221 * @exception Error if the factory has already been defined.
1222 * @exception SecurityException if a security manager exists and its
1223 * <code>checkSetFactory</code> method doesn't allow the operation.
1224 * @see java.net.ContentHandlerFactory
1225 * @see java.net.URLConnection#getContent()
1226 * @see SecurityManager#checkSetFactory
1228 public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {
1229 if (factory != null) {
1230 throw new Error("factory already defined");
1232 SecurityManager security = System.getSecurityManager();
1233 if (security != null) {
1234 security.checkSetFactory();
1239 private static Hashtable handlers = new Hashtable();
1242 * Gets the Content Handler appropriate for this connection.
1243 * @param connection the connection to use.
1245 synchronized ContentHandler getContentHandler()
1246 throws UnknownServiceException
1248 String contentType = stripOffParameters(getContentType());
1249 ContentHandler handler = null;
1250 if (contentType == null)
1251 throw new UnknownServiceException("no content-type");
1253 handler = (ContentHandler) handlers.get(contentType);
1254 if (handler != null)
1256 } catch(Exception e) {
1259 if (factory != null)
1260 handler = factory.createContentHandler(contentType);
1261 if (handler == null) {
1263 handler = lookupContentHandlerClassFor(contentType);
1264 } catch(Exception e) {
1265 e.printStackTrace();
1266 handler = UnknownContentHandler.INSTANCE;
1268 handlers.put(contentType, handler);
1274 * Media types are in the format: type/subtype*(; parameter).
1275 * For looking up the content handler, we should ignore those
1278 private String stripOffParameters(String contentType)
1280 if (contentType == null)
1282 int index = contentType.indexOf(';');
1285 return contentType.substring(0, index);
1290 private static final String contentClassPrefix = "sun.net.www.content";
1291 private static final String contentPathProp = "java.content.handler.pkgs";
1294 * Looks for a content handler in a user-defineable set of places.
1295 * By default it looks in sun.net.www.content, but users can define a
1296 * vertical-bar delimited set of class prefixes to search through in
1297 * addition by defining the java.content.handler.pkgs property.
1298 * The class name must be of the form:
1300 * {package-prefix}.{major}.{minor}
1302 * YoyoDyne.experimental.text.plain
1305 private ContentHandler lookupContentHandlerClassFor(String contentType)
1306 throws InstantiationException, IllegalAccessException, ClassNotFoundException {
1307 String contentHandlerClassName = typeToPackageName(contentType);
1309 String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes();
1311 StringTokenizer packagePrefixIter =
1312 new StringTokenizer(contentHandlerPkgPrefixes, "|");
1314 while (packagePrefixIter.hasMoreTokens()) {
1315 String packagePrefix = packagePrefixIter.nextToken().trim();
1318 String clsName = packagePrefix + "." + contentHandlerClassName;
1321 cls = Class.forName(clsName);
1322 } catch (ClassNotFoundException e) {
1323 ClassLoader cl = ClassLoader.getSystemClassLoader();
1325 cls = cl.loadClass(clsName);
1329 ContentHandler handler =
1330 (ContentHandler)cls.newInstance();
1333 } catch(Exception e) {
1337 return UnknownContentHandler.INSTANCE;
1341 * Utility function to map a MIME content type into an equivalent
1342 * pair of class name components. For example: "text/html" would
1343 * be returned as "text.html"
1345 private String typeToPackageName(String contentType) {
1346 // make sure we canonicalize the class name: all lower case
1347 contentType = contentType.toLowerCase();
1348 int len = contentType.length();
1349 char nm[] = new char[len];
1350 contentType.getChars(0, len, nm, 0);
1351 for (int i = 0; i < len; i++) {
1355 } else if (!('A' <= c && c <= 'Z' ||
1356 'a' <= c && c <= 'z' ||
1357 '0' <= c && c <= '9')) {
1361 return new String(nm);
1366 * Returns a vertical bar separated list of package prefixes for potential
1367 * content handlers. Tries to get the java.content.handler.pkgs property
1368 * to use as a set of package prefixes to search. Whether or not
1369 * that property has been defined, the sun.net.www.content is always
1370 * the last one on the returned package list.
1372 private String getContentHandlerPkgPrefixes() {
1373 String packagePrefixList = AccessController.doPrivileged(
1374 new sun.security.action.GetPropertyAction(contentPathProp, ""));
1376 if (packagePrefixList != "") {
1377 packagePrefixList += "|";
1380 return packagePrefixList + contentClassPrefix;
1384 * Tries to determine the content type of an object, based
1385 * on the specified "file" component of a URL.
1386 * This is a convenience method that can be used by
1387 * subclasses that override the <code>getContentType</code> method.
1389 * @param fname a filename.
1390 * @return a guess as to what the content type of the object is,
1391 * based upon its file name.
1392 * @see java.net.URLConnection#getContentType()
1394 public static String guessContentTypeFromName(String fname) {
1395 return getFileNameMap().getContentTypeFor(fname);
1399 * Tries to determine the type of an input stream based on the
1400 * characters at the beginning of the input stream. This method can
1401 * be used by subclasses that override the
1402 * <code>getContentType</code> method.
1404 * Ideally, this routine would not be needed. But many
1405 * <code>http</code> servers return the incorrect content type; in
1406 * addition, there are many nonstandard extensions. Direct inspection
1407 * of the bytes to determine the content type is often more accurate
1408 * than believing the content type claimed by the <code>http</code> server.
1410 * @param is an input stream that supports marks.
1411 * @return a guess at the content type, or <code>null</code> if none
1412 * can be determined.
1413 * @exception IOException if an I/O error occurs while reading the
1415 * @see java.io.InputStream#mark(int)
1416 * @see java.io.InputStream#markSupported()
1417 * @see java.net.URLConnection#getContentType()
1419 static public String guessContentTypeFromStream(InputStream is)
1420 throws IOException {
1421 // If we can't read ahead safely, just give up on guessing
1422 if (!is.markSupported())
1435 int c10 = is.read();
1436 int c11 = is.read();
1437 int c12 = is.read();
1438 int c13 = is.read();
1439 int c14 = is.read();
1440 int c15 = is.read();
1441 int c16 = is.read();
1444 if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {
1445 return "application/java-vm";
1448 if (c1 == 0xAC && c2 == 0xED) {
1449 // next two bytes are version number, currently 0x00 0x05
1450 return "application/x-java-serialized-object";
1455 || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' ||
1456 c3 == 'e' && c4 == 'a' && c5 == 'd') ||
1457 (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) ||
1458 ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' ||
1459 c3 == 'E' && c4 == 'A' && c5 == 'D') ||
1460 (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) {
1464 if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') {
1465 return "application/xml";
1469 // big and little (identical) endian UTF-8 encodings, with BOM
1470 if (c1 == 0xef && c2 == 0xbb && c3 == 0xbf) {
1471 if (c4 == '<' && c5 == '?' && c6 == 'x') {
1472 return "application/xml";
1476 // big and little endian UTF-16 encodings, with byte order mark
1477 if (c1 == 0xfe && c2 == 0xff) {
1478 if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' &&
1479 c7 == 0 && c8 == 'x') {
1480 return "application/xml";
1484 if (c1 == 0xff && c2 == 0xfe) {
1485 if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 &&
1486 c7 == 'x' && c8 == 0) {
1487 return "application/xml";
1491 // big and little endian UTF-32 encodings, with BOM
1492 if (c1 == 0x00 && c2 == 0x00 && c3 == 0xfe && c4 == 0xff) {
1493 if (c5 == 0 && c6 == 0 && c7 == 0 && c8 == '<' &&
1494 c9 == 0 && c10 == 0 && c11 == 0 && c12 == '?' &&
1495 c13 == 0 && c14 == 0 && c15 == 0 && c16 == 'x') {
1496 return "application/xml";
1500 if (c1 == 0xff && c2 == 0xfe && c3 == 0x00 && c4 == 0x00) {
1501 if (c5 == '<' && c6 == 0 && c7 == 0 && c8 == 0 &&
1502 c9 == '?' && c10 == 0 && c11 == 0 && c12 == 0 &&
1503 c13 == 'x' && c14 == 0 && c15 == 0 && c16 == 0) {
1504 return "application/xml";
1508 if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
1512 if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
1513 return "image/x-bitmap";
1516 if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
1517 c5 == 'M' && c6 == '2') {
1518 return "image/x-pixmap";
1521 if (c1 == 137 && c2 == 80 && c3 == 78 &&
1522 c4 == 71 && c5 == 13 && c6 == 10 &&
1523 c7 == 26 && c8 == 10) {
1527 if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {
1529 return "image/jpeg";
1533 * File format used by digital cameras to store images.
1534 * Exif Format can be read by any application supporting
1535 * JPEG. Exif Spec can be found at:
1536 * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
1539 (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' &&
1541 return "image/jpeg";
1549 if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 &&
1550 c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {
1552 /* Above is signature of Microsoft Structured Storage.
1553 * Below this, could have tests for various SS entities.
1554 * For now, just test for FlashPix.
1557 return "image/vnd.fpx";
1561 if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) {
1562 return "audio/basic"; // .au format, big endian
1565 if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) {
1566 return "audio/basic"; // .au format, little endian
1569 if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') {
1570 /* I don't know if this is official but evidence
1571 * suggests that .wav files start with "RIFF" - brown
1573 return "audio/x-wav";
1579 * Check for FlashPix image data in InputStream is. Return true if
1580 * the stream has FlashPix data, false otherwise. Before calling this
1581 * method, the stream should have already been checked to be sure it
1582 * contains Microsoft Structured Storage data.
1584 static private boolean checkfpx(InputStream is) throws IOException {
1586 /* Test for FlashPix image data in Microsoft Structured Storage format.
1587 * In general, should do this with calls to an SS implementation.
1588 * Lacking that, need to dig via offsets to get to the FlashPix
1591 * Offset to Fpx ClsID from beginning of stream should be:
1593 * FpxClsidOffset = rootEntryOffset + clsidOffset
1595 * where: clsidOffset = 0x50.
1596 * rootEntryOffset = headerSize + sectorSize*sectDirStart
1597 * + 128*rootEntryDirectory
1599 * where: headerSize = 0x200 (always)
1600 * sectorSize = 2 raised to power of uSectorShift,
1601 * which is found in the header at
1603 * sectDirStart = found in the header at offset 0x30.
1604 * rootEntryDirectory = in general, should search for
1605 * directory labelled as root.
1606 * We will assume value of 0 (i.e.,
1607 * rootEntry is in first directory)
1610 // Mark the stream so we can reset it. 0x100 is enough for the first
1611 // few reads, but the mark will have to be reset and set again once
1612 // the offset to the root directory entry is computed. That offset
1613 // can be very large and isn't know until the stream has been read from
1616 // Get the byte ordering located at 0x1E. 0xFE is Intel,
1618 long toSkip = (long)0x1C;
1621 if ((posn = skipForward(is, toSkip)) < toSkip) {
1626 int c[] = new int[16];
1627 if (readBytes(c, 2, is) < 0) {
1632 int byteOrder = c[0];
1636 if (readBytes(c, 2, is) < 0) {
1641 if(byteOrder == 0xFE) {
1642 uSectorShift = c[0];
1643 uSectorShift += c[1] << 8;
1646 uSectorShift = c[0] << 8;
1647 uSectorShift += c[1];
1651 toSkip = (long)0x30 - posn;
1653 if ((skipped = skipForward(is, toSkip)) < toSkip) {
1659 if (readBytes(c, 4, is) < 0) {
1665 if(byteOrder == 0xFE) {
1666 sectDirStart = c[0];
1667 sectDirStart += c[1] << 8;
1668 sectDirStart += c[2] << 16;
1669 sectDirStart += c[3] << 24;
1671 sectDirStart = c[0] << 24;
1672 sectDirStart += c[1] << 16;
1673 sectDirStart += c[2] << 8;
1674 sectDirStart += c[3];
1677 is.reset(); // Reset back to the beginning
1679 toSkip = 0x200L + (long)(1<<uSectorShift)*sectDirStart + 0x50L;
1687 * How far can we skip? Is there any performance problem here?
1688 * This skip can be fairly long, at least 0x4c650 in at least
1689 * one case. Have to assume that the skip will fit in an int.
1690 * Leave room to read whole root dir
1692 is.mark((int)toSkip+0x30);
1694 if ((skipForward(is, toSkip)) < toSkip) {
1699 /* should be at beginning of ClassID, which is as follows
1700 * (in Intel byte order):
1701 * 00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B
1703 * This is stored from Windows as long,short,short,char[8]
1704 * so for byte order changes, the order only changes for
1705 * the first 8 bytes in the ClassID.
1707 * Test against this, ignoring second byte (Intel) since
1708 * this could change depending on part of Fpx file we have.
1711 if (readBytes(c, 16, is) < 0) {
1717 if (byteOrder == 0xFE &&
1718 c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 &&
1719 c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE &&
1720 c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
1721 c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
1722 c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
1727 // non-intel byte order
1728 else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 &&
1729 c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE &&
1730 c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
1731 c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
1732 c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
1741 * Tries to read the specified number of bytes from the stream
1742 * Returns -1, If EOF is reached before len bytes are read, returns 0
1745 static private int readBytes(int c[], int len, InputStream is)
1746 throws IOException {
1748 byte buf[] = new byte[len];
1749 if (is.read(buf, 0, len) < len) {
1753 // fill the passed in int array
1754 for (int i = 0; i < len; i++) {
1755 c[i] = buf[i] & 0xff;
1762 * Skips through the specified number of bytes from the stream
1763 * until either EOF is reached, or the specified
1764 * number of bytes have been skipped
1766 static private long skipForward(InputStream is, long toSkip)
1767 throws IOException {
1772 while (skipped != toSkip) {
1773 eachSkip = is.skip(toSkip - skipped);
1775 // check if EOF is reached
1776 if (eachSkip <= 0) {
1777 if (is.read() == -1) {
1783 skipped += eachSkip;
1791 class UnknownContentHandler extends ContentHandler {
1792 static final ContentHandler INSTANCE = new UnknownContentHandler();
1794 public Object getContent(URLConnection uc) throws IOException {
1795 return uc.getInputStream();