0001 /*
0002 * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package java.net;
0027
0028 import java.io.IOException;
0029 import java.io.InputStream;
0030 import java.io.OutputStream;
0031 import java.util.Hashtable;
0032 import java.util.Date;
0033 import java.util.StringTokenizer;
0034 import java.util.Collections;
0035 import java.util.Map;
0036 import java.util.List;
0037 import java.security.Permission;
0038 import java.security.AccessController;
0039 import sun.security.util.SecurityConstants;
0040 import sun.net.www.MessageHeader;
0041
0042 /**
0043 * The abstract class <code>URLConnection</code> is the superclass
0044 * of all classes that represent a communications link between the
0045 * application and a URL. Instances of this class can be used both to
0046 * read from and to write to the resource referenced by the URL. In
0047 * general, creating a connection to a URL is a multistep process:
0048 * <p>
0049 * <center><table border=2 summary="Describes the process of creating a connection to a URL: openConnection() and connect() over time.">
0050 * <tr><th><code>openConnection()</code></th>
0051 * <th><code>connect()</code></th></tr>
0052 * <tr><td>Manipulate parameters that affect the connection to the remote
0053 * resource.</td>
0054 * <td>Interact with the resource; query header fields and
0055 * contents.</td></tr>
0056 * </table>
0057 * ---------------------------->
0058 * <br>time</center>
0059 *
0060 * <ol>
0061 * <li>The connection object is created by invoking the
0062 * <code>openConnection</code> method on a URL.
0063 * <li>The setup parameters and general request properties are manipulated.
0064 * <li>The actual connection to the remote object is made, using the
0065 * <code>connect</code> method.
0066 * <li>The remote object becomes available. The header fields and the contents
0067 * of the remote object can be accessed.
0068 * </ol>
0069 * <p>
0070 * The setup parameters are modified using the following methods:
0071 * <ul>
0072 * <li><code>setAllowUserInteraction</code>
0073 * <li><code>setDoInput</code>
0074 * <li><code>setDoOutput</code>
0075 * <li><code>setIfModifiedSince</code>
0076 * <li><code>setUseCaches</code>
0077 * </ul>
0078 * <p>
0079 * and the general request properties are modified using the method:
0080 * <ul>
0081 * <li><code>setRequestProperty</code>
0082 * </ul>
0083 * <p>
0084 * Default values for the <code>AllowUserInteraction</code> and
0085 * <code>UseCaches</code> parameters can be set using the methods
0086 * <code>setDefaultAllowUserInteraction</code> and
0087 * <code>setDefaultUseCaches</code>.
0088 * <p>
0089 * Each of the above <code>set</code> methods has a corresponding
0090 * <code>get</code> method to retrieve the value of the parameter or
0091 * general request property. The specific parameters and general
0092 * request properties that are applicable are protocol specific.
0093 * <p>
0094 * The following methods are used to access the header fields and
0095 * the contents after the connection is made to the remote object:
0096 * <ul>
0097 * <li><code>getContent</code>
0098 * <li><code>getHeaderField</code>
0099 * <li><code>getInputStream</code>
0100 * <li><code>getOutputStream</code>
0101 * </ul>
0102 * <p>
0103 * Certain header fields are accessed frequently. The methods:
0104 * <ul>
0105 * <li><code>getContentEncoding</code>
0106 * <li><code>getContentLength</code>
0107 * <li><code>getContentType</code>
0108 * <li><code>getDate</code>
0109 * <li><code>getExpiration</code>
0110 * <li><code>getLastModifed</code>
0111 * </ul>
0112 * <p>
0113 * provide convenient access to these fields. The
0114 * <code>getContentType</code> method is used by the
0115 * <code>getContent</code> method to determine the type of the remote
0116 * object; subclasses may find it convenient to override the
0117 * <code>getContentType</code> method.
0118 * <p>
0119 * In the common case, all of the pre-connection parameters and
0120 * general request properties can be ignored: the pre-connection
0121 * parameters and request properties default to sensible values. For
0122 * most clients of this interface, there are only two interesting
0123 * methods: <code>getInputStream</code> and <code>getContent</code>,
0124 * which are mirrored in the <code>URL</code> class by convenience methods.
0125 * <p>
0126 * More information on the request properties and header fields of
0127 * an <code>http</code> connection can be found at:
0128 * <blockquote><pre>
0129 * <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a>
0130 * </pre></blockquote>
0131 *
0132 * Note about <code>fileNameMap</code>: In versions prior to JDK 1.1.6,
0133 * field <code>fileNameMap</code> of <code>URLConnection</code> was public.
0134 * In JDK 1.1.6 and later, <code>fileNameMap</code> is private; accessor
0135 * and mutator methods {@link #getFileNameMap() getFileNameMap} and
0136 * {@link #setFileNameMap(java.net.FileNameMap) setFileNameMap} are added
0137 * to access it. This change is also described on the <a href=
0138 * "http://java.sun.com/products/jdk/1.2/compatibility.html">
0139 * Compatibility</a> page.
0140 *
0141 * Invoking the <tt>close()</tt> methods on the <tt>InputStream</tt> or <tt>OutputStream</tt> of an
0142 * <tt>URLConnection</tt> after a request may free network resources associated with this
0143 * instance, unless particular protocol specifications specify different behaviours
0144 * for it.
0145 *
0146 * @author James Gosling
0147 * @version 1.113, 05/05/07
0148 * @see java.net.URL#openConnection()
0149 * @see java.net.URLConnection#connect()
0150 * @see java.net.URLConnection#getContent()
0151 * @see java.net.URLConnection#getContentEncoding()
0152 * @see java.net.URLConnection#getContentLength()
0153 * @see java.net.URLConnection#getContentType()
0154 * @see java.net.URLConnection#getDate()
0155 * @see java.net.URLConnection#getExpiration()
0156 * @see java.net.URLConnection#getHeaderField(int)
0157 * @see java.net.URLConnection#getHeaderField(java.lang.String)
0158 * @see java.net.URLConnection#getInputStream()
0159 * @see java.net.URLConnection#getLastModified()
0160 * @see java.net.URLConnection#getOutputStream()
0161 * @see java.net.URLConnection#setAllowUserInteraction(boolean)
0162 * @see java.net.URLConnection#setDefaultUseCaches(boolean)
0163 * @see java.net.URLConnection#setDoInput(boolean)
0164 * @see java.net.URLConnection#setDoOutput(boolean)
0165 * @see java.net.URLConnection#setIfModifiedSince(long)
0166 * @see java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String)
0167 * @see java.net.URLConnection#setUseCaches(boolean)
0168 * @since JDK1.0
0169 */
0170 public abstract class URLConnection {
0171
0172 /**
0173 * The URL represents the remote object on the World Wide Web to
0174 * which this connection is opened.
0175 * <p>
0176 * The value of this field can be accessed by the
0177 * <code>getURL</code> method.
0178 * <p>
0179 * The default value of this variable is the value of the URL
0180 * argument in the <code>URLConnection</code> constructor.
0181 *
0182 * @see java.net.URLConnection#getURL()
0183 * @see java.net.URLConnection#url
0184 */
0185 protected URL url;
0186
0187 /**
0188 * This variable is set by the <code>setDoInput</code> method. Its
0189 * value is returned by the <code>getDoInput</code> method.
0190 * <p>
0191 * A URL connection can be used for input and/or output. Setting the
0192 * <code>doInput</code> flag to <code>true</code> indicates that
0193 * the application intends to read data from the URL connection.
0194 * <p>
0195 * The default value of this field is <code>true</code>.
0196 *
0197 * @see java.net.URLConnection#getDoInput()
0198 * @see java.net.URLConnection#setDoInput(boolean)
0199 */
0200 protected boolean doInput = true;
0201
0202 /**
0203 * This variable is set by the <code>setDoOutput</code> method. Its
0204 * value is returned by the <code>getDoOutput</code> method.
0205 * <p>
0206 * A URL connection can be used for input and/or output. Setting the
0207 * <code>doOutput</code> flag to <code>true</code> indicates
0208 * that the application intends to write data to the URL connection.
0209 * <p>
0210 * The default value of this field is <code>false</code>.
0211 *
0212 * @see java.net.URLConnection#getDoOutput()
0213 * @see java.net.URLConnection#setDoOutput(boolean)
0214 */
0215 protected boolean doOutput = false;
0216
0217 private static boolean defaultAllowUserInteraction = false;
0218
0219 /**
0220 * If <code>true</code>, this <code>URL</code> is being examined in
0221 * a context in which it makes sense to allow user interactions such
0222 * as popping up an authentication dialog. If <code>false</code>,
0223 * then no user interaction is allowed.
0224 * <p>
0225 * The value of this field can be set by the
0226 * <code>setAllowUserInteraction</code> method.
0227 * Its value is returned by the
0228 * <code>getAllowUserInteraction</code> method.
0229 * Its default value is the value of the argument in the last invocation
0230 * of the <code>setDefaultAllowUserInteraction</code> method.
0231 *
0232 * @see java.net.URLConnection#getAllowUserInteraction()
0233 * @see java.net.URLConnection#setAllowUserInteraction(boolean)
0234 * @see java.net.URLConnection#setDefaultAllowUserInteraction(boolean)
0235 */
0236 protected boolean allowUserInteraction = defaultAllowUserInteraction;
0237
0238 private static boolean defaultUseCaches = true;
0239
0240 /**
0241 * If <code>true</code>, the protocol is allowed to use caching
0242 * whenever it can. If <code>false</code>, the protocol must always
0243 * try to get a fresh copy of the object.
0244 * <p>
0245 * This field is set by the <code>setUseCaches</code> method. Its
0246 * value is returned by the <code>getUseCaches</code> method.
0247 * <p>
0248 * Its default value is the value given in the last invocation of the
0249 * <code>setDefaultUseCaches</code> method.
0250 *
0251 * @see java.net.URLConnection#setUseCaches(boolean)
0252 * @see java.net.URLConnection#getUseCaches()
0253 * @see java.net.URLConnection#setDefaultUseCaches(boolean)
0254 */
0255 protected boolean useCaches = defaultUseCaches;
0256
0257 /**
0258 * Some protocols support skipping the fetching of the object unless
0259 * the object has been modified more recently than a certain time.
0260 * <p>
0261 * A nonzero value gives a time as the number of milliseconds since
0262 * January 1, 1970, GMT. The object is fetched only if it has been
0263 * modified more recently than that time.
0264 * <p>
0265 * This variable is set by the <code>setIfModifiedSince</code>
0266 * method. Its value is returned by the
0267 * <code>getIfModifiedSince</code> method.
0268 * <p>
0269 * The default value of this field is <code>0</code>, indicating
0270 * that the fetching must always occur.
0271 *
0272 * @see java.net.URLConnection#getIfModifiedSince()
0273 * @see java.net.URLConnection#setIfModifiedSince(long)
0274 */
0275 protected long ifModifiedSince = 0;
0276
0277 /**
0278 * If <code>false</code>, this connection object has not created a
0279 * communications link to the specified URL. If <code>true</code>,
0280 * the communications link has been established.
0281 */
0282 protected boolean connected = false;
0283
0284 /**
0285 * @since 1.5
0286 */
0287 private int connectTimeout;
0288 private int readTimeout;
0289
0290 /**
0291 * @since 1.6
0292 */
0293 private MessageHeader requests;
0294
0295 /**
0296 * @since JDK1.1
0297 */
0298 private static FileNameMap fileNameMap;
0299
0300 /**
0301 * @since 1.2.2
0302 */
0303 private static boolean fileNameMapLoaded = false;
0304
0305 /**
0306 * Loads filename map (a mimetable) from a data file. It will
0307 * first try to load the user-specific table, defined
0308 * by "content.types.user.table" property. If that fails,
0309 * it tries to load the default built-in table at
0310 * lib/content-types.properties under java home.
0311 *
0312 * @return the FileNameMap
0313 * @since 1.2
0314 * @see #setFileNameMap(java.net.FileNameMap)
0315 */
0316 public static synchronized FileNameMap getFileNameMap() {
0317 if ((fileNameMap == null) && !fileNameMapLoaded) {
0318 fileNameMap = sun.net.www.MimeTable.loadTable();
0319 fileNameMapLoaded = true;
0320 }
0321
0322 return new FileNameMap() {
0323 private FileNameMap map = fileNameMap;
0324
0325 public String getContentTypeFor(String fileName) {
0326 return map.getContentTypeFor(fileName);
0327 }
0328 };
0329 }
0330
0331 /**
0332 * Sets the FileNameMap.
0333 * <p>
0334 * If there is a security manager, this method first calls
0335 * the security manager's <code>checkSetFactory</code> method
0336 * to ensure the operation is allowed.
0337 * This could result in a SecurityException.
0338 *
0339 * @param map the FileNameMap to be set
0340 * @exception SecurityException if a security manager exists and its
0341 * <code>checkSetFactory</code> method doesn't allow the operation.
0342 * @see SecurityManager#checkSetFactory
0343 * @see #getFileNameMap()
0344 * @since 1.2
0345 */
0346 public static void setFileNameMap(FileNameMap map) {
0347 SecurityManager sm = System.getSecurityManager();
0348 if (sm != null)
0349 sm.checkSetFactory();
0350 fileNameMap = map;
0351 }
0352
0353 /**
0354 * Opens a communications link to the resource referenced by this
0355 * URL, if such a connection has not already been established.
0356 * <p>
0357 * If the <code>connect</code> method is called when the connection
0358 * has already been opened (indicated by the <code>connected</code>
0359 * field having the value <code>true</code>), the call is ignored.
0360 * <p>
0361 * URLConnection objects go through two phases: first they are
0362 * created, then they are connected. After being created, and
0363 * before being connected, various options can be specified
0364 * (e.g., doInput and UseCaches). After connecting, it is an
0365 * error to try to set them. Operations that depend on being
0366 * connected, like getContentLength, will implicitly perform the
0367 * connection, if necessary.
0368 *
0369 * @throws SocketTimeoutException if the timeout expires before
0370 * the connection can be established
0371 * @exception IOException if an I/O error occurs while opening the
0372 * connection.
0373 * @see java.net.URLConnection#connected
0374 * @see #getConnectTimeout()
0375 * @see #setConnectTimeout(int)
0376 */
0377 abstract public void connect() throws IOException;
0378
0379 /**
0380 * Sets a specified timeout value, in milliseconds, to be used
0381 * when opening a communications link to the resource referenced
0382 * by this URLConnection. If the timeout expires before the
0383 * connection can be established, a
0384 * java.net.SocketTimeoutException is raised. A timeout of zero is
0385 * interpreted as an infinite timeout.
0386
0387 * <p> Some non-standard implmentation of this method may ignore
0388 * the specified timeout. To see the connect timeout set, please
0389 * call getConnectTimeout().
0390 *
0391 * @param timeout an <code>int</code> that specifies the connect
0392 * timeout value in milliseconds
0393 * @throws IllegalArgumentException if the timeout parameter is negative
0394 *
0395 * @see #getConnectTimeout()
0396 * @see #connect()
0397 * @since 1.5
0398 */
0399 public void setConnectTimeout(int timeout) {
0400 if (timeout < 0) {
0401 throw new IllegalArgumentException(
0402 "timeout can not be negative");
0403 }
0404 connectTimeout = timeout;
0405 }
0406
0407 /**
0408 * Returns setting for connect timeout.
0409 * <p>
0410 * 0 return implies that the option is disabled
0411 * (i.e., timeout of infinity).
0412 *
0413 * @return an <code>int</code> that indicates the connect timeout
0414 * value in milliseconds
0415 * @see #setConnectTimeout(int)
0416 * @see #connect()
0417 * @since 1.5
0418 */
0419 public int getConnectTimeout() {
0420 return connectTimeout;
0421 }
0422
0423 /**
0424 * Sets the read timeout to a specified timeout, in
0425 * milliseconds. A non-zero value specifies the timeout when
0426 * reading from Input stream when a connection is established to a
0427 * resource. If the timeout expires before there is data available
0428 * for read, a java.net.SocketTimeoutException is raised. A
0429 * timeout of zero is interpreted as an infinite timeout.
0430 *
0431 *<p> Some non-standard implementation of this method ignores the
0432 * specified timeout. To see the read timeout set, please call
0433 * getReadTimeout().
0434 *
0435 * @param timeout an <code>int</code> that specifies the timeout
0436 * value to be used in milliseconds
0437 * @throws IllegalArgumentException if the timeout parameter is negative
0438 *
0439 * @see #getReadTimeout()
0440 * @see InputStream#read()
0441 * @since 1.5
0442 */
0443 public void setReadTimeout(int timeout) {
0444 if (timeout < 0) {
0445 throw new IllegalArgumentException(
0446 "timeout can not be negative");
0447 }
0448 readTimeout = timeout;
0449 }
0450
0451 /**
0452 * Returns setting for read timeout. 0 return implies that the
0453 * option is disabled (i.e., timeout of infinity).
0454 *
0455 * @return an <code>int</code> that indicates the read timeout
0456 * value in milliseconds
0457 *
0458 * @see #setReadTimeout(int)
0459 * @see InputStream#read()
0460 * @since 1.5
0461 */
0462 public int getReadTimeout() {
0463 return readTimeout;
0464 }
0465
0466 /**
0467 * Constructs a URL connection to the specified URL. A connection to
0468 * the object referenced by the URL is not created.
0469 *
0470 * @param url the specified URL.
0471 */
0472 protected URLConnection(URL url) {
0473 this .url = url;
0474 }
0475
0476 /**
0477 * Returns the value of this <code>URLConnection</code>'s <code>URL</code>
0478 * field.
0479 *
0480 * @return the value of this <code>URLConnection</code>'s <code>URL</code>
0481 * field.
0482 * @see java.net.URLConnection#url
0483 */
0484 public URL getURL() {
0485 return url;
0486 }
0487
0488 /**
0489 * Returns the value of the <code>content-length</code> header field.
0490 *
0491 * @return the content length of the resource that this connection's URL
0492 * references, or <code>-1</code> if the content length is
0493 * not known.
0494 */
0495 public int getContentLength() {
0496 return getHeaderFieldInt("content-length", -1);
0497 }
0498
0499 /**
0500 * Returns the value of the <code>content-type</code> header field.
0501 *
0502 * @return the content type of the resource that the URL references,
0503 * or <code>null</code> if not known.
0504 * @see java.net.URLConnection#getHeaderField(java.lang.String)
0505 */
0506 public String getContentType() {
0507 return getHeaderField("content-type");
0508 }
0509
0510 /**
0511 * Returns the value of the <code>content-encoding</code> header field.
0512 *
0513 * @return the content encoding of the resource that the URL references,
0514 * or <code>null</code> if not known.
0515 * @see java.net.URLConnection#getHeaderField(java.lang.String)
0516 */
0517 public String getContentEncoding() {
0518 return getHeaderField("content-encoding");
0519 }
0520
0521 /**
0522 * Returns the value of the <code>expires</code> header field.
0523 *
0524 * @return the expiration date of the resource that this URL references,
0525 * or 0 if not known. The value is the number of milliseconds since
0526 * January 1, 1970 GMT.
0527 * @see java.net.URLConnection#getHeaderField(java.lang.String)
0528 */
0529 public long getExpiration() {
0530 return getHeaderFieldDate("expires", 0);
0531 }
0532
0533 /**
0534 * Returns the value of the <code>date</code> header field.
0535 *
0536 * @return the sending date of the resource that the URL references,
0537 * or <code>0</code> if not known. The value returned is the
0538 * number of milliseconds since January 1, 1970 GMT.
0539 * @see java.net.URLConnection#getHeaderField(java.lang.String)
0540 */
0541 public long getDate() {
0542 return getHeaderFieldDate("date", 0);
0543 }
0544
0545 /**
0546 * Returns the value of the <code>last-modified</code> header field.
0547 * The result is the number of milliseconds since January 1, 1970 GMT.
0548 *
0549 * @return the date the resource referenced by this
0550 * <code>URLConnection</code> was last modified, or 0 if not known.
0551 * @see java.net.URLConnection#getHeaderField(java.lang.String)
0552 */
0553 public long getLastModified() {
0554 return getHeaderFieldDate("last-modified", 0);
0555 }
0556
0557 /**
0558 * Returns the value of the named header field.
0559 * <p>
0560 * If called on a connection that sets the same header multiple times
0561 * with possibly different values, only the last value is returned.
0562 *
0563 *
0564 * @param name the name of a header field.
0565 * @return the value of the named header field, or <code>null</code>
0566 * if there is no such field in the header.
0567 */
0568 public String getHeaderField(String name) {
0569 return null;
0570 }
0571
0572 /**
0573 * Returns an unmodifiable Map of the header fields.
0574 * The Map keys are Strings that represent the
0575 * response-header field names. Each Map value is an
0576 * unmodifiable List of Strings that represents
0577 * the corresponding field values.
0578 *
0579 * @return a Map of header fields
0580 * @since 1.4
0581 */
0582 public Map<String, List<String>> getHeaderFields() {
0583 return Collections.EMPTY_MAP;
0584 }
0585
0586 /**
0587 * Returns the value of the named field parsed as a number.
0588 * <p>
0589 * This form of <code>getHeaderField</code> exists because some
0590 * connection types (e.g., <code>http-ng</code>) have pre-parsed
0591 * headers. Classes for that connection type can override this method
0592 * and short-circuit the parsing.
0593 *
0594 * @param name the name of the header field.
0595 * @param Default the default value.
0596 * @return the value of the named field, parsed as an integer. The
0597 * <code>Default</code> value is returned if the field is
0598 * missing or malformed.
0599 */
0600 public int getHeaderFieldInt(String name, int Default) {
0601 String value = getHeaderField(name);
0602 try {
0603 return Integer.parseInt(value);
0604 } catch (Exception e) {
0605 }
0606 return Default;
0607 }
0608
0609 /**
0610 * Returns the value of the named field parsed as date.
0611 * The result is the number of milliseconds since January 1, 1970 GMT
0612 * represented by the named field.
0613 * <p>
0614 * This form of <code>getHeaderField</code> exists because some
0615 * connection types (e.g., <code>http-ng</code>) have pre-parsed
0616 * headers. Classes for that connection type can override this method
0617 * and short-circuit the parsing.
0618 *
0619 * @param name the name of the header field.
0620 * @param Default a default value.
0621 * @return the value of the field, parsed as a date. The value of the
0622 * <code>Default</code> argument is returned if the field is
0623 * missing or malformed.
0624 */
0625 public long getHeaderFieldDate(String name, long Default) {
0626 String value = getHeaderField(name);
0627 try {
0628 return Date.parse(value);
0629 } catch (Exception e) {
0630 }
0631 return Default;
0632 }
0633
0634 /**
0635 * Returns the key for the <code>n</code><sup>th</sup> header field.
0636 * It returns <code>null</code> if there are fewer than <code>n+1</code> fields.
0637 *
0638 * @param n an index, where n>=0
0639 * @return the key for the <code>n</code><sup>th</sup> header field,
0640 * or <code>null</code> if there are fewer than <code>n+1</code>
0641 * fields.
0642 */
0643 public String getHeaderFieldKey(int n) {
0644 return null;
0645 }
0646
0647 /**
0648 * Returns the value for the <code>n</code><sup>th</sup> header field.
0649 * It returns <code>null</code> if there are fewer than
0650 * <code>n+1</code>fields.
0651 * <p>
0652 * This method can be used in conjunction with the
0653 * {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all
0654 * the headers in the message.
0655 *
0656 * @param n an index, where n>=0
0657 * @return the value of the <code>n</code><sup>th</sup> header field
0658 * or <code>null</code> if there are fewer than <code>n+1</code> fields
0659 * @see java.net.URLConnection#getHeaderFieldKey(int)
0660 */
0661 public String getHeaderField(int n) {
0662 return null;
0663 }
0664
0665 /**
0666 * Retrieves the contents of this URL connection.
0667 * <p>
0668 * This method first determines the content type of the object by
0669 * calling the <code>getContentType</code> method. If this is
0670 * the first time that the application has seen that specific content
0671 * type, a content handler for that content type is created:
0672 * <ol>
0673 * <li>If the application has set up a content handler factory instance
0674 * using the <code>setContentHandlerFactory</code> method, the
0675 * <code>createContentHandler</code> method of that instance is called
0676 * with the content type as an argument; the result is a content
0677 * handler for that content type.
0678 * <li>If no content handler factory has yet been set up, or if the
0679 * factory's <code>createContentHandler</code> method returns
0680 * <code>null</code>, then the application loads the class named:
0681 * <blockquote><pre>
0682 * sun.net.www.content.<<i>contentType</i>>
0683 * </pre></blockquote>
0684 * where <<i>contentType</i>> is formed by taking the
0685 * content-type string, replacing all slash characters with a
0686 * <code>period</code> ('.'), and all other non-alphanumeric characters
0687 * with the underscore character '<code>_</code>'. The alphanumeric
0688 * characters are specifically the 26 uppercase ASCII letters
0689 * '<code>A</code>' through '<code>Z</code>', the 26 lowercase ASCII
0690 * letters '<code>a</code>' through '<code>z</code>', and the 10 ASCII
0691 * digits '<code>0</code>' through '<code>9</code>'. If the specified
0692 * class does not exist, or is not a subclass of
0693 * <code>ContentHandler</code>, then an
0694 * <code>UnknownServiceException</code> is thrown.
0695 * </ol>
0696 *
0697 * @return the object fetched. The <code>instanceof</code> operator
0698 * should be used to determine the specific kind of object
0699 * returned.
0700 * @exception IOException if an I/O error occurs while
0701 * getting the content.
0702 * @exception UnknownServiceException if the protocol does not support
0703 * the content type.
0704 * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
0705 * @see java.net.URLConnection#getContentType()
0706 * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
0707 */
0708 public Object getContent() throws IOException {
0709 // Must call getInputStream before GetHeaderField gets called
0710 // so that FileNotFoundException has a chance to be thrown up
0711 // from here without being caught.
0712 getInputStream();
0713 return getContentHandler().getContent(this );
0714 }
0715
0716 /**
0717 * Retrieves the contents of this URL connection.
0718 *
0719 * @param classes the <code>Class</code> array
0720 * indicating the requested types
0721 * @return the object fetched that is the first match of the type
0722 * specified in the classes array. null if none of
0723 * the requested types are supported.
0724 * The <code>instanceof</code> operator should be used to
0725 * determine the specific kind of object returned.
0726 * @exception IOException if an I/O error occurs while
0727 * getting the content.
0728 * @exception UnknownServiceException if the protocol does not support
0729 * the content type.
0730 * @see java.net.URLConnection#getContent()
0731 * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
0732 * @see java.net.URLConnection#getContent(java.lang.Class[])
0733 * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
0734 * @since 1.3
0735 */
0736 public Object getContent(Class[] classes) throws IOException {
0737 // Must call getInputStream before GetHeaderField gets called
0738 // so that FileNotFoundException has a chance to be thrown up
0739 // from here without being caught.
0740 getInputStream();
0741 return getContentHandler().getContent(this , classes);
0742 }
0743
0744 /**
0745 * Returns a permission object representing the permission
0746 * necessary to make the connection represented by this
0747 * object. This method returns null if no permission is
0748 * required to make the connection. By default, this method
0749 * returns <code>java.security.AllPermission</code>. Subclasses
0750 * should override this method and return the permission
0751 * that best represents the permission required to make a
0752 * a connection to the URL. For example, a <code>URLConnection</code>
0753 * representing a <code>file:</code> URL would return a
0754 * <code>java.io.FilePermission</code> object.
0755 *
0756 * <p>The permission returned may dependent upon the state of the
0757 * connection. For example, the permission before connecting may be
0758 * different from that after connecting. For example, an HTTP
0759 * sever, say foo.com, may redirect the connection to a different
0760 * host, say bar.com. Before connecting the permission returned by
0761 * the connection will represent the permission needed to connect
0762 * to foo.com, while the permission returned after connecting will
0763 * be to bar.com.
0764 *
0765 * <p>Permissions are generally used for two purposes: to protect
0766 * caches of objects obtained through URLConnections, and to check
0767 * the right of a recipient to learn about a particular URL. In
0768 * the first case, the permission should be obtained
0769 * <em>after</em> the object has been obtained. For example, in an
0770 * HTTP connection, this will represent the permission to connect
0771 * to the host from which the data was ultimately fetched. In the
0772 * second case, the permission should be obtained and tested
0773 * <em>before</em> connecting.
0774 *
0775 * @return the permission object representing the permission
0776 * necessary to make the connection represented by this
0777 * URLConnection.
0778 *
0779 * @exception IOException if the computation of the permission
0780 * requires network or file I/O and an exception occurs while
0781 * computing it.
0782 */
0783 public Permission getPermission() throws IOException {
0784 return SecurityConstants.ALL_PERMISSION;
0785 }
0786
0787 /**
0788 * Returns an input stream that reads from this open connection.
0789 *
0790 * A SocketTimeoutException can be thrown when reading from the
0791 * returned input stream if the read timeout expires before data
0792 * is available for read.
0793 *
0794 * @return an input stream that reads from this open connection.
0795 * @exception IOException if an I/O error occurs while
0796 * creating the input stream.
0797 * @exception UnknownServiceException if the protocol does not support
0798 * input.
0799 * @see #setReadTimeout(int)
0800 * @see #getReadTimeout()
0801 */
0802 public InputStream getInputStream() throws IOException {
0803 throw new UnknownServiceException(
0804 "protocol doesn't support input");
0805 }
0806
0807 /**
0808 * Returns an output stream that writes to this connection.
0809 *
0810 * @return an output stream that writes to this connection.
0811 * @exception IOException if an I/O error occurs while
0812 * creating the output stream.
0813 * @exception UnknownServiceException if the protocol does not support
0814 * output.
0815 */
0816 public OutputStream getOutputStream() throws IOException {
0817 throw new UnknownServiceException(
0818 "protocol doesn't support output");
0819 }
0820
0821 /**
0822 * Returns a <code>String</code> representation of this URL connection.
0823 *
0824 * @return a string representation of this <code>URLConnection</code>.
0825 */
0826 public String toString() {
0827 return this .getClass().getName() + ":" + url;
0828 }
0829
0830 /**
0831 * Sets the value of the <code>doInput</code> field for this
0832 * <code>URLConnection</code> to the specified value.
0833 * <p>
0834 * A URL connection can be used for input and/or output. Set the DoInput
0835 * flag to true if you intend to use the URL connection for input,
0836 * false if not. The default is true.
0837 *
0838 * @param doinput the new value.
0839 * @throws IllegalStateException if already connected
0840 * @see java.net.URLConnection#doInput
0841 * @see #getDoInput()
0842 */
0843 public void setDoInput(boolean doinput) {
0844 if (connected)
0845 throw new IllegalStateException("Already connected");
0846 doInput = doinput;
0847 }
0848
0849 /**
0850 * Returns the value of this <code>URLConnection</code>'s
0851 * <code>doInput</code> flag.
0852 *
0853 * @return the value of this <code>URLConnection</code>'s
0854 * <code>doInput</code> flag.
0855 * @see #setDoInput(boolean)
0856 */
0857 public boolean getDoInput() {
0858 return doInput;
0859 }
0860
0861 /**
0862 * Sets the value of the <code>doOutput</code> field for this
0863 * <code>URLConnection</code> to the specified value.
0864 * <p>
0865 * A URL connection can be used for input and/or output. Set the DoOutput
0866 * flag to true if you intend to use the URL connection for output,
0867 * false if not. The default is false.
0868 *
0869 * @param dooutput the new value.
0870 * @throws IllegalStateException if already connected
0871 * @see #getDoOutput()
0872 */
0873 public void setDoOutput(boolean dooutput) {
0874 if (connected)
0875 throw new IllegalStateException("Already connected");
0876 doOutput = dooutput;
0877 }
0878
0879 /**
0880 * Returns the value of this <code>URLConnection</code>'s
0881 * <code>doOutput</code> flag.
0882 *
0883 * @return the value of this <code>URLConnection</code>'s
0884 * <code>doOutput</code> flag.
0885 * @see #setDoOutput(boolean)
0886 */
0887 public boolean getDoOutput() {
0888 return doOutput;
0889 }
0890
0891 /**
0892 * Set the value of the <code>allowUserInteraction</code> field of
0893 * this <code>URLConnection</code>.
0894 *
0895 * @param allowuserinteraction the new value.
0896 * @throws IllegalStateException if already connected
0897 * @see #getAllowUserInteraction()
0898 */
0899 public void setAllowUserInteraction(boolean allowuserinteraction) {
0900 if (connected)
0901 throw new IllegalStateException("Already connected");
0902 allowUserInteraction = allowuserinteraction;
0903 }
0904
0905 /**
0906 * Returns the value of the <code>allowUserInteraction</code> field for
0907 * this object.
0908 *
0909 * @return the value of the <code>allowUserInteraction</code> field for
0910 * this object.
0911 * @see #setAllowUserInteraction(boolean)
0912 */
0913 public boolean getAllowUserInteraction() {
0914 return allowUserInteraction;
0915 }
0916
0917 /**
0918 * Sets the default value of the
0919 * <code>allowUserInteraction</code> field for all future
0920 * <code>URLConnection</code> objects to the specified value.
0921 *
0922 * @param defaultallowuserinteraction the new value.
0923 * @see #getDefaultAllowUserInteraction()
0924 */
0925 public static void setDefaultAllowUserInteraction(
0926 boolean defaultallowuserinteraction) {
0927 defaultAllowUserInteraction = defaultallowuserinteraction;
0928 }
0929
0930 /**
0931 * Returns the default value of the <code>allowUserInteraction</code>
0932 * field.
0933 * <p>
0934 * Ths default is "sticky", being a part of the static state of all
0935 * URLConnections. This flag applies to the next, and all following
0936 * URLConnections that are created.
0937 *
0938 * @return the default value of the <code>allowUserInteraction</code>
0939 * field.
0940 * @see #setDefaultAllowUserInteraction(boolean)
0941 */
0942 public static boolean getDefaultAllowUserInteraction() {
0943 return defaultAllowUserInteraction;
0944 }
0945
0946 /**
0947 * Sets the value of the <code>useCaches</code> field of this
0948 * <code>URLConnection</code> to the specified value.
0949 * <p>
0950 * Some protocols do caching of documents. Occasionally, it is important
0951 * to be able to "tunnel through" and ignore the caches (e.g., the
0952 * "reload" button in a browser). If the UseCaches flag on a connection
0953 * is true, the connection is allowed to use whatever caches it can.
0954 * If false, caches are to be ignored.
0955 * The default value comes from DefaultUseCaches, which defaults to
0956 * true.
0957 *
0958 * @param usecaches a <code>boolean</code> indicating whether
0959 * or not to allow caching
0960 * @throws IllegalStateException if already connected
0961 * @see #getUseCaches()
0962 */
0963 public void setUseCaches(boolean usecaches) {
0964 if (connected)
0965 throw new IllegalStateException("Already connected");
0966 useCaches = usecaches;
0967 }
0968
0969 /**
0970 * Returns the value of this <code>URLConnection</code>'s
0971 * <code>useCaches</code> field.
0972 *
0973 * @return the value of this <code>URLConnection</code>'s
0974 * <code>useCaches</code> field.
0975 * @see #setUseCaches(boolean)
0976 */
0977 public boolean getUseCaches() {
0978 return useCaches;
0979 }
0980
0981 /**
0982 * Sets the value of the <code>ifModifiedSince</code> field of
0983 * this <code>URLConnection</code> to the specified value.
0984 *
0985 * @param ifmodifiedsince the new value.
0986 * @throws IllegalStateException if already connected
0987 * @see #getIfModifiedSince()
0988 */
0989 public void setIfModifiedSince(long ifmodifiedsince) {
0990 if (connected)
0991 throw new IllegalStateException("Already connected");
0992 ifModifiedSince = ifmodifiedsince;
0993 }
0994
0995 /**
0996 * Returns the value of this object's <code>ifModifiedSince</code> field.
0997 *
0998 * @return the value of this object's <code>ifModifiedSince</code> field.
0999 * @see #setIfModifiedSince(long)
1000 */
1001 public long getIfModifiedSince() {
1002 return ifModifiedSince;
1003 }
1004
1005 /**
1006 * Returns the default value of a <code>URLConnection</code>'s
1007 * <code>useCaches</code> flag.
1008 * <p>
1009 * Ths default is "sticky", being a part of the static state of all
1010 * URLConnections. This flag applies to the next, and all following
1011 * URLConnections that are created.
1012 *
1013 * @return the default value of a <code>URLConnection</code>'s
1014 * <code>useCaches</code> flag.
1015 * @see #setDefaultUseCaches(boolean)
1016 */
1017 public boolean getDefaultUseCaches() {
1018 return defaultUseCaches;
1019 }
1020
1021 /**
1022 * Sets the default value of the <code>useCaches</code> field to the
1023 * specified value.
1024 *
1025 * @param defaultusecaches the new value.
1026 * @see #getDefaultUseCaches()
1027 */
1028 public void setDefaultUseCaches(boolean defaultusecaches) {
1029 defaultUseCaches = defaultusecaches;
1030 }
1031
1032 /**
1033 * Sets the general request property. If a property with the key already
1034 * exists, overwrite its value with the new value.
1035 *
1036 * <p> NOTE: HTTP requires all request properties which can
1037 * legally have multiple instances with the same key
1038 * to use a comma-seperated list syntax which enables multiple
1039 * properties to be appended into a single property.
1040 *
1041 * @param key the keyword by which the request is known
1042 * (e.g., "<code>accept</code>").
1043 * @param value the value associated with it.
1044 * @throws IllegalStateException if already connected
1045 * @throws NullPointerException if key is <CODE>null</CODE>
1046 * @see #getRequestProperty(java.lang.String)
1047 */
1048 public void setRequestProperty(String key, String value) {
1049 if (connected)
1050 throw new IllegalStateException("Already connected");
1051 if (key == null)
1052 throw new NullPointerException("key is null");
1053
1054 if (requests == null)
1055 requests = new MessageHeader();
1056
1057 requests.set(key, value);
1058 }
1059
1060 /**
1061 * Adds a general request property specified by a
1062 * key-value pair. This method will not overwrite
1063 * existing values associated with the same key.
1064 *
1065 * @param key the keyword by which the request is known
1066 * (e.g., "<code>accept</code>").
1067 * @param value the value associated with it.
1068 * @throws IllegalStateException if already connected
1069 * @throws NullPointerException if key is null
1070 * @see #getRequestProperties()
1071 * @since 1.4
1072 */
1073 public void addRequestProperty(String key, String value) {
1074 if (connected)
1075 throw new IllegalStateException("Already connected");
1076 if (key == null)
1077 throw new NullPointerException("key is null");
1078
1079 if (requests == null)
1080 requests = new MessageHeader();
1081
1082 requests.add(key, value);
1083 }
1084
1085 /**
1086 * Returns the value of the named general request property for this
1087 * connection.
1088 *
1089 * @param key the keyword by which the request is known (e.g., "accept").
1090 * @return the value of the named general request property for this
1091 * connection. If key is null, then null is returned.
1092 * @throws IllegalStateException if already connected
1093 * @see #setRequestProperty(java.lang.String, java.lang.String)
1094 */
1095 public String getRequestProperty(String key) {
1096 if (connected)
1097 throw new IllegalStateException("Already connected");
1098
1099 if (requests == null)
1100 return null;
1101
1102 return requests.findValue(key);
1103 }
1104
1105 /**
1106 * Returns an unmodifiable Map of general request
1107 * properties for this connection. The Map keys
1108 * are Strings that represent the request-header
1109 * field names. Each Map value is a unmodifiable List
1110 * of Strings that represents the corresponding
1111 * field values.
1112 *
1113 * @return a Map of the general request properties for this connection.
1114 * @throws IllegalStateException if already connected
1115 * @since 1.4
1116 */
1117 public Map<String, List<String>> getRequestProperties() {
1118 if (connected)
1119 throw new IllegalStateException("Already connected");
1120
1121 if (requests == null)
1122 return Collections.EMPTY_MAP;
1123
1124 return requests.getHeaders(null);
1125 }
1126
1127 /**
1128 * Sets the default value of a general request property. When a
1129 * <code>URLConnection</code> is created, it is initialized with
1130 * these properties.
1131 *
1132 * @param key the keyword by which the request is known
1133 * (e.g., "<code>accept</code>").
1134 * @param value the value associated with the key.
1135 *
1136 * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String)
1137 *
1138 * @deprecated The instance specific setRequestProperty method
1139 * should be used after an appropriate instance of URLConnection
1140 * is obtained. Invoking this method will have no effect.
1141 *
1142 * @see #getDefaultRequestProperty(java.lang.String)
1143 */
1144 @Deprecated
1145 public static void setDefaultRequestProperty(String key,
1146 String value) {
1147 }
1148
1149 /**
1150 * Returns the value of the default request property. Default request
1151 * properties are set for every connection.
1152 *
1153 * @param key the keyword by which the request is known (e.g., "accept").
1154 * @return the value of the default request property
1155 * for the specified key.
1156 *
1157 * @see java.net.URLConnection#getRequestProperty(java.lang.String)
1158 *
1159 * @deprecated The instance specific getRequestProperty method
1160 * should be used after an appropriate instance of URLConnection
1161 * is obtained.
1162 *
1163 * @see #setDefaultRequestProperty(java.lang.String, java.lang.String)
1164 */
1165 @Deprecated
1166 public static String getDefaultRequestProperty(String key) {
1167 return null;
1168 }
1169
1170 /**
1171 * The ContentHandler factory.
1172 */
1173 static ContentHandlerFactory factory;
1174
1175 /**
1176 * Sets the <code>ContentHandlerFactory</code> of an
1177 * application. It can be called at most once by an application.
1178 * <p>
1179 * The <code>ContentHandlerFactory</code> instance is used to
1180 * construct a content handler from a content type
1181 * <p>
1182 * If there is a security manager, this method first calls
1183 * the security manager's <code>checkSetFactory</code> method
1184 * to ensure the operation is allowed.
1185 * This could result in a SecurityException.
1186 *
1187 * @param fac the desired factory.
1188 * @exception Error if the factory has already been defined.
1189 * @exception SecurityException if a security manager exists and its
1190 * <code>checkSetFactory</code> method doesn't allow the operation.
1191 * @see java.net.ContentHandlerFactory
1192 * @see java.net.URLConnection#getContent()
1193 * @see SecurityManager#checkSetFactory
1194 */
1195 public static synchronized void setContentHandlerFactory(
1196 ContentHandlerFactory fac) {
1197 if (factory != null) {
1198 throw new Error("factory already defined");
1199 }
1200 SecurityManager security = System.getSecurityManager();
1201 if (security != null) {
1202 security.checkSetFactory();
1203 }
1204 factory = fac;
1205 }
1206
1207 private static Hashtable handlers = new Hashtable();
1208 private static final ContentHandler UnknownContentHandlerP = new UnknownContentHandler();
1209
1210 /**
1211 * Gets the Content Handler appropriate for this connection.
1212 * @param connection the connection to use.
1213 */
1214 synchronized ContentHandler getContentHandler()
1215 throws UnknownServiceException {
1216 String contentType = stripOffParameters(getContentType());
1217 ContentHandler handler = null;
1218 if (contentType == null)
1219 throw new UnknownServiceException("no content-type");
1220 try {
1221 handler = (ContentHandler) handlers.get(contentType);
1222 if (handler != null)
1223 return handler;
1224 } catch (Exception e) {
1225 }
1226
1227 if (factory != null)
1228 handler = factory.createContentHandler(contentType);
1229 if (handler == null) {
1230 try {
1231 handler = lookupContentHandlerClassFor(contentType);
1232 } catch (Exception e) {
1233 e.printStackTrace();
1234 handler = UnknownContentHandlerP;
1235 }
1236 handlers.put(contentType, handler);
1237 }
1238 return handler;
1239 }
1240
1241 /*
1242 * Media types are in the format: type/subtype*(; parameter).
1243 * For looking up the content handler, we should ignore those
1244 * parameters.
1245 */
1246 private String stripOffParameters(String contentType) {
1247 if (contentType == null)
1248 return null;
1249 int index = contentType.indexOf(';');
1250
1251 if (index > 0)
1252 return contentType.substring(0, index);
1253 else
1254 return contentType;
1255 }
1256
1257 private static final String contentClassPrefix = "sun.net.www.content";
1258 private static final String contentPathProp = "java.content.handler.pkgs";
1259
1260 /**
1261 * Looks for a content handler in a user-defineable set of places.
1262 * By default it looks in sun.net.www.content, but users can define a
1263 * vertical-bar delimited set of class prefixes to search through in
1264 * addition by defining the java.content.handler.pkgs property.
1265 * The class name must be of the form:
1266 * <pre>
1267 * {package-prefix}.{major}.{minor}
1268 * e.g.
1269 * YoyoDyne.experimental.text.plain
1270 * </pre>
1271 */
1272 private ContentHandler lookupContentHandlerClassFor(
1273 String contentType) throws InstantiationException,
1274 IllegalAccessException, ClassNotFoundException {
1275 String contentHandlerClassName = typeToPackageName(contentType);
1276
1277 String contentHandlerPkgPrefixes = getContentHandlerPkgPrefixes();
1278
1279 StringTokenizer packagePrefixIter = new StringTokenizer(
1280 contentHandlerPkgPrefixes, "|");
1281
1282 while (packagePrefixIter.hasMoreTokens()) {
1283 String packagePrefix = packagePrefixIter.nextToken().trim();
1284
1285 try {
1286 String clsName = packagePrefix + "."
1287 + contentHandlerClassName;
1288 Class cls = null;
1289 try {
1290 cls = Class.forName(clsName);
1291 } catch (ClassNotFoundException e) {
1292 ClassLoader cl = ClassLoader.getSystemClassLoader();
1293 if (cl != null) {
1294 cls = cl.loadClass(clsName);
1295 }
1296 }
1297 if (cls != null) {
1298 ContentHandler handler = (ContentHandler) cls
1299 .newInstance();
1300 return handler;
1301 }
1302 } catch (Exception e) {
1303 }
1304 }
1305
1306 return UnknownContentHandlerP;
1307 }
1308
1309 /**
1310 * Utility function to map a MIME content type into an equivalent
1311 * pair of class name components. For example: "text/html" would
1312 * be returned as "text.html"
1313 */
1314 private String typeToPackageName(String contentType) {
1315 // make sure we canonicalize the class name: all lower case
1316 contentType = contentType.toLowerCase();
1317 int len = contentType.length();
1318 char nm[] = new char[len];
1319 contentType.getChars(0, len, nm, 0);
1320 for (int i = 0; i < len; i++) {
1321 char c = nm[i];
1322 if (c == '/') {
1323 nm[i] = '.';
1324 } else if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c
1325 && c <= '9')) {
1326 nm[i] = '_';
1327 }
1328 }
1329 return new String(nm);
1330 }
1331
1332 /**
1333 * Returns a vertical bar separated list of package prefixes for potential
1334 * content handlers. Tries to get the java.content.handler.pkgs property
1335 * to use as a set of package prefixes to search. Whether or not
1336 * that property has been defined, the sun.net.www.content is always
1337 * the last one on the returned package list.
1338 */
1339 private String getContentHandlerPkgPrefixes() {
1340 String packagePrefixList = (String) AccessController
1341 .doPrivileged(new sun.security.action.GetPropertyAction(
1342 contentPathProp, ""));
1343
1344 if (packagePrefixList != "") {
1345 packagePrefixList += "|";
1346 }
1347
1348 return packagePrefixList + contentClassPrefix;
1349 }
1350
1351 /**
1352 * Tries to determine the content type of an object, based
1353 * on the specified "file" component of a URL.
1354 * This is a convenience method that can be used by
1355 * subclasses that override the <code>getContentType</code> method.
1356 *
1357 * @param fname a filename.
1358 * @return a guess as to what the content type of the object is,
1359 * based upon its file name.
1360 * @see java.net.URLConnection#getContentType()
1361 */
1362 public static String guessContentTypeFromName(String fname) {
1363 return getFileNameMap().getContentTypeFor(fname);
1364 }
1365
1366 /**
1367 * Tries to determine the type of an input stream based on the
1368 * characters at the beginning of the input stream. This method can
1369 * be used by subclasses that override the
1370 * <code>getContentType</code> method.
1371 * <p>
1372 * Ideally, this routine would not be needed. But many
1373 * <code>http</code> servers return the incorrect content type; in
1374 * addition, there are many nonstandard extensions. Direct inspection
1375 * of the bytes to determine the content type is often more accurate
1376 * than believing the content type claimed by the <code>http</code> server.
1377 *
1378 * @param is an input stream that supports marks.
1379 * @return a guess at the content type, or <code>null</code> if none
1380 * can be determined.
1381 * @exception IOException if an I/O error occurs while reading the
1382 * input stream.
1383 * @see java.io.InputStream#mark(int)
1384 * @see java.io.InputStream#markSupported()
1385 * @see java.net.URLConnection#getContentType()
1386 */
1387 static public String guessContentTypeFromStream(InputStream is)
1388 throws IOException {
1389 // If we can't read ahead safely, just give up on guessing
1390 if (!is.markSupported())
1391 return null;
1392
1393 is.mark(12);
1394 int c1 = is.read();
1395 int c2 = is.read();
1396 int c3 = is.read();
1397 int c4 = is.read();
1398 int c5 = is.read();
1399 int c6 = is.read();
1400 int c7 = is.read();
1401 int c8 = is.read();
1402 int c9 = is.read();
1403 int c10 = is.read();
1404 int c11 = is.read();
1405 is.reset();
1406
1407 if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {
1408 return "application/java-vm";
1409 }
1410
1411 if (c1 == 0xAC && c2 == 0xED) {
1412 // next two bytes are version number, currently 0x00 0x05
1413 return "application/x-java-serialized-object";
1414 }
1415
1416 if (c1 == '<') {
1417 if (c2 == '!'
1418 || ((c2 == 'h'
1419 && (c3 == 't' && c4 == 'm' && c5 == 'l' || c3 == 'e'
1420 && c4 == 'a' && c5 == 'd') || (c2 == 'b'
1421 && c3 == 'o' && c4 == 'd' && c5 == 'y')))
1422 || ((c2 == 'H'
1423 && (c3 == 'T' && c4 == 'M' && c5 == 'L' || c3 == 'E'
1424 && c4 == 'A' && c5 == 'D') || (c2 == 'B'
1425 && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) {
1426 return "text/html";
1427 }
1428
1429 if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l'
1430 && c6 == ' ') {
1431 return "application/xml";
1432 }
1433 }
1434
1435 // big and little endian UTF-16 encodings, with byte order mark
1436 if (c1 == 0xfe && c2 == 0xff) {
1437 if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' && c7 == 0
1438 && c8 == 'x') {
1439 return "application/xml";
1440 }
1441 }
1442
1443 if (c1 == 0xff && c2 == 0xfe) {
1444 if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0
1445 && c7 == 'x' && c8 == 0) {
1446 return "application/xml";
1447 }
1448 }
1449
1450 if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
1451 return "image/gif";
1452 }
1453
1454 if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
1455 return "image/x-bitmap";
1456 }
1457
1458 if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P'
1459 && c5 == 'M' && c6 == '2') {
1460 return "image/x-pixmap";
1461 }
1462
1463 if (c1 == 137 && c2 == 80 && c3 == 78 && c4 == 71 && c5 == 13
1464 && c6 == 10 && c7 == 26 && c8 == 10) {
1465 return "image/png";
1466 }
1467
1468 if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {
1469 if (c4 == 0xE0) {
1470 return "image/jpeg";
1471 }
1472
1473 /**
1474 * File format used by digital cameras to store images.
1475 * Exif Format can be read by any application supporting
1476 * JPEG. Exif Spec can be found at:
1477 * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
1478 */
1479 if ((c4 == 0xE1)
1480 && (c7 == 'E' && c8 == 'x' && c9 == 'i'
1481 && c10 == 'f' && c11 == 0)) {
1482 return "image/jpeg";
1483 }
1484
1485 if (c4 == 0xEE) {
1486 return "image/jpg";
1487 }
1488 }
1489
1490 if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0
1491 && c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {
1492
1493 /* Above is signature of Microsoft Structured Storage.
1494 * Below this, could have tests for various SS entities.
1495 * For now, just test for FlashPix.
1496 */
1497 if (checkfpx(is)) {
1498 return "image/vnd.fpx";
1499 }
1500 }
1501
1502 if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) {
1503 return "audio/basic"; // .au format, big endian
1504 }
1505
1506 if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) {
1507 return "audio/basic"; // .au format, little endian
1508 }
1509
1510 if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') {
1511 /* I don't know if this is official but evidence
1512 * suggests that .wav files start with "RIFF" - brown
1513 */
1514 return "audio/x-wav";
1515 }
1516 return null;
1517 }
1518
1519 /**
1520 * Check for FlashPix image data in InputStream is. Return true if
1521 * the stream has FlashPix data, false otherwise. Before calling this
1522 * method, the stream should have already been checked to be sure it
1523 * contains Microsoft Structured Storage data.
1524 */
1525 static private boolean checkfpx(InputStream is) throws IOException {
1526
1527 /* Test for FlashPix image data in Microsoft Structured Storage format.
1528 * In general, should do this with calls to an SS implementation.
1529 * Lacking that, need to dig via offsets to get to the FlashPix
1530 * ClassID. Details:
1531 *
1532 * Offset to Fpx ClsID from beginning of stream should be:
1533 *
1534 * FpxClsidOffset = rootEntryOffset + clsidOffset
1535 *
1536 * where: clsidOffset = 0x50.
1537 * rootEntryOffset = headerSize + sectorSize*sectDirStart
1538 * + 128*rootEntryDirectory
1539 *
1540 * where: headerSize = 0x200 (always)
1541 * sectorSize = 2 raised to power of uSectorShift,
1542 * which is found in the header at
1543 * offset 0x1E.
1544 * sectDirStart = found in the header at offset 0x30.
1545 * rootEntryDirectory = in general, should search for
1546 * directory labelled as root.
1547 * We will assume value of 0 (i.e.,
1548 * rootEntry is in first directory)
1549 */
1550
1551 // Mark the stream so we can reset it. 0x100 is enough for the first
1552 // few reads, but the mark will have to be reset and set again once
1553 // the offset to the root directory entry is computed. That offset
1554 // can be very large and isn't know until the stream has been read from
1555 is.mark(0x100);
1556
1557 // Get the byte ordering located at 0x1E. 0xFE is Intel,
1558 // 0xFF is other
1559 long toSkip = (long) 0x1C;
1560 long posn;
1561
1562 if ((posn = skipForward(is, toSkip)) < toSkip) {
1563 is.reset();
1564 return false;
1565 }
1566
1567 int c[] = new int[16];
1568 if (readBytes(c, 2, is) < 0) {
1569 is.reset();
1570 return false;
1571 }
1572
1573 int byteOrder = c[0];
1574
1575 posn += 2;
1576 int uSectorShift;
1577 if (readBytes(c, 2, is) < 0) {
1578 is.reset();
1579 return false;
1580 }
1581
1582 if (byteOrder == 0xFE) {
1583 uSectorShift = c[0];
1584 uSectorShift += c[1] << 8;
1585 } else {
1586 uSectorShift = c[0] << 8;
1587 uSectorShift += c[1];
1588 }
1589
1590 posn += 2;
1591 toSkip = (long) 0x30 - posn;
1592 long skipped = 0;
1593 if ((skipped = skipForward(is, toSkip)) < toSkip) {
1594 is.reset();
1595 return false;
1596 }
1597 posn += skipped;
1598
1599 if (readBytes(c, 4, is) < 0) {
1600 is.reset();
1601 return false;
1602 }
1603
1604 int sectDirStart;
1605 if (byteOrder == 0xFE) {
1606 sectDirStart = c[0];
1607 sectDirStart += c[1] << 8;
1608 sectDirStart += c[2] << 16;
1609 sectDirStart += c[3] << 24;
1610 } else {
1611 sectDirStart = c[0] << 24;
1612 sectDirStart += c[1] << 16;
1613 sectDirStart += c[2] << 8;
1614 sectDirStart += c[3];
1615 }
1616 posn += 4;
1617 is.reset(); // Reset back to the beginning
1618
1619 toSkip = (long) 0x200 + (long) ((int) 1 << uSectorShift)
1620 * sectDirStart + (long) 0x50;
1621
1622 // Sanity check!
1623 if (toSkip < 0) {
1624 return false;
1625 }
1626
1627 /*
1628 * How far can we skip? Is there any performance problem here?
1629 * This skip can be fairly long, at least 0x4c650 in at least
1630 * one case. Have to assume that the skip will fit in an int.
1631 * Leave room to read whole root dir
1632 */
1633 is.mark((int) toSkip + 0x30);
1634
1635 if ((skipForward(is, toSkip)) < toSkip) {
1636 is.reset();
1637 return false;
1638 }
1639
1640 /* should be at beginning of ClassID, which is as follows
1641 * (in Intel byte order):
1642 * 00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B
1643 *
1644 * This is stored from Windows as long,short,short,char[8]
1645 * so for byte order changes, the order only changes for
1646 * the first 8 bytes in the ClassID.
1647 *
1648 * Test against this, ignoring second byte (Intel) since
1649 * this could change depending on part of Fpx file we have.
1650 */
1651
1652 if (readBytes(c, 16, is) < 0) {
1653 is.reset();
1654 return false;
1655 }
1656
1657 // intel byte order
1658 if (byteOrder == 0xFE && c[0] == 0x00 && c[2] == 0x61
1659 && c[3] == 0x56 && c[4] == 0x54 && c[5] == 0xC1
1660 && c[6] == 0xCE && c[7] == 0x11 && c[8] == 0x85
1661 && c[9] == 0x53 && c[10] == 0x00 && c[11] == 0xAA
1662 && c[12] == 0x00 && c[13] == 0xA1 && c[14] == 0xF9
1663 && c[15] == 0x5B) {
1664 is.reset();
1665 return true;
1666 }
1667
1668 // non-intel byte order
1669 else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56
1670 && c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE
1671 && c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53
1672 && c[10] == 0x00 && c[11] == 0xAA && c[12] == 0x00
1673 && c[13] == 0xA1 && c[14] == 0xF9 && c[15] == 0x5B) {
1674 is.reset();
1675 return true;
1676 }
1677 is.reset();
1678 return false;
1679 }
1680
1681 /**
1682 * Tries to read the specified number of bytes from the stream
1683 * Returns -1, If EOF is reached before len bytes are read, returns 0
1684 * otherwise
1685 */
1686 static private int readBytes(int c[], int len, InputStream is)
1687 throws IOException {
1688
1689 byte buf[] = new byte[len];
1690 if (is.read(buf, 0, len) < len) {
1691 return -1;
1692 }
1693
1694 // fill the passed in int array
1695 for (int i = 0; i < len; i++) {
1696 c[i] = buf[i] & 0xff;
1697 }
1698 return 0;
1699 }
1700
1701 /**
1702 * Skips through the specified number of bytes from the stream
1703 * until either EOF is reached, or the specified
1704 * number of bytes have been skipped
1705 */
1706 static private long skipForward(InputStream is, long toSkip)
1707 throws IOException {
1708
1709 long eachSkip = 0;
1710 long skipped = 0;
1711
1712 while (skipped != toSkip) {
1713 eachSkip = is.skip(toSkip - skipped);
1714
1715 // check if EOF is reached
1716 if (eachSkip <= 0) {
1717 if (is.read() == -1) {
1718 return skipped;
1719 } else {
1720 skipped++;
1721 }
1722 }
1723 skipped += eachSkip;
1724 }
1725 return skipped;
1726 }
1727
1728 }
1729
1730 class UnknownContentHandler extends ContentHandler {
1731 public Object getContent(URLConnection uc) throws IOException {
1732 return uc.getInputStream();
1733 }
1734 }
|