| /* URLConnection.java -- Abstract superclass for reading from URL's | |
| Copyright (C) 1998, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath is distributed in the hope that it will be useful, but | |
| WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package java.net; | |
| import gnu.classpath.SystemProperties; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.io.OutputStream; | |
| import java.security.AllPermission; | |
| import java.security.Permission; | |
| import java.text.ParsePosition; | |
| import java.text.SimpleDateFormat; | |
| import java.util.Collections; | |
| import java.util.Date; | |
| import java.util.Locale; | |
| import java.util.Map; | |
| import java.util.StringTokenizer; | |
| /** | |
| * Written using on-line Java Platform 1.2 API Specification, as well | |
| * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). | |
| * Status: One guessContentTypeFrom... methods not implemented. | |
| * getContent method assumes content type from response; see comment there. | |
| */ | |
| /** | |
| * This class models a connection that retrieves the information pointed | |
| * to by a URL object. This is typically a connection to a remote node | |
| * on the network, but could be a simple disk read. | |
| * <p> | |
| * A URLConnection object is normally created by calling the openConnection() | |
| * method of a URL object. This method is somewhat misnamed because it does | |
| * not actually open the connection. Instead, it return an unconnected | |
| * instance of this object. The caller then has the opportunity to set | |
| * various connection options prior to calling the actual connect() method. | |
| * <p> | |
| * After the connection has been opened, there are a number of methods in | |
| * this class that access various attributes of the data, typically | |
| * represented by headers sent in advance of the actual data itself. | |
| * <p> | |
| * Also of note are the getInputStream and getContent() methods which allow | |
| * the caller to retrieve the actual data from the connection. Note that | |
| * for some types of connections, writing is also allowed. The setDoOutput() | |
| * method must be called prior to connecing in order to enable this, then | |
| * the getOutputStream method called after the connection in order to | |
| * obtain a stream to write the output to. | |
| * <p> | |
| * The getContent() method is of particular note. This method returns an | |
| * Object that encapsulates the data returned. There is no way do determine | |
| * the type of object that will be returned in advance. This is determined | |
| * by the actual content handlers as described in the description of that | |
| * method. | |
| * | |
| * @author Aaron M. Renn (arenn@urbanophile.com) | |
| * @author Warren Levy (warrenl@cygnus.com) | |
| */ | |
| public abstract class URLConnection | |
| { | |
| /** | |
| * This is an object that maps filenames to MIME types. The interface | |
| * to do this is implemented by this class, so just create an empty | |
| * instance and store it here. | |
| */ | |
| private static FileNameMap fileNameMap; | |
| /** | |
| * This is the ContentHandlerFactory set by the caller, if any | |
| */ | |
| private static ContentHandlerFactory factory; | |
| /** | |
| * This is the default value that will be used to determine whether or | |
| * not user interaction should be allowed. | |
| */ | |
| private static boolean defaultAllowUserInteraction; | |
| /** | |
| * This is the default flag indicating whether or not to use caches to | |
| * store the data returned from a server | |
| */ | |
| private static boolean defaultUseCaches = true; | |
| /** | |
| * Default internal content handler factory. | |
| */ | |
| private static ContentHandlerFactory defaultFactory | |
| = new gnu.java.net.DefaultContentHandlerFactory(); | |
| /** | |
| * This variable determines whether or not interaction is allowed with | |
| * the user. For example, to prompt for a username and password. | |
| */ | |
| protected boolean allowUserInteraction; | |
| /** | |
| * Indicates whether or not a connection has been established to the | |
| * destination specified in the URL | |
| */ | |
| protected boolean connected; | |
| /** | |
| * Indicates whether or not input can be read from this URL | |
| */ | |
| protected boolean doInput = true; | |
| /** | |
| * Indicates whether or not output can be sent to this URL | |
| */ | |
| protected boolean doOutput; | |
| /** | |
| * If this flag is set, the protocol is allowed to cache data whenever | |
| * it can (caching is not guaranteed). If it is not set, the protocol | |
| * must a get a fresh copy of the data. | |
| * <p> | |
| * This field is set by the setUseCaches method and returned by the | |
| * getUseCaches method. | |
| * | |
| * Its default value is that determined by the last invocation of | |
| * setDefaultUseCaches | |
| */ | |
| protected boolean useCaches; | |
| /** | |
| * If this value is non-zero, then the connection will only attempt to | |
| * fetch the document pointed to by the URL if the document has been | |
| * modified more recently than the date set in this variable. That date | |
| * should be specified as the number of seconds since 1/1/1970 GMT. | |
| */ | |
| protected long ifModifiedSince; | |
| /** | |
| * This is the URL associated with this connection | |
| */ | |
| protected URL url; | |
| private static SimpleDateFormat[] dateFormats; | |
| private static boolean dateformats_initialized; | |
| /** | |
| * The timeout period. | |
| */ | |
| private int timeout; | |
| /* Cached ParsePosition, used when parsing dates. */ | |
| private ParsePosition position; | |
| /** | |
| * Creates a URL connection to a given URL. A real connection is not made. | |
| * Use <code>connect()</code> to do this. | |
| * | |
| * @param url The Object to create the URL connection to | |
| * | |
| * @see URLConnection#connect() | |
| */ | |
| protected URLConnection(URL url) | |
| { | |
| // Set up all our instance variables | |
| this.url = url; | |
| allowUserInteraction = defaultAllowUserInteraction; | |
| useCaches = defaultUseCaches; | |
| } | |
| /** | |
| * Establishes the actual connection to the URL associated with this | |
| * connection object | |
| * | |
| * @exception IOException if an error occurs | |
| */ | |
| public abstract void connect() throws IOException; | |
| /** | |
| * Returns the URL object associated with this connection | |
| * | |
| * @return The URL for this connection. | |
| */ | |
| public URL getURL() | |
| { | |
| return url; | |
| } | |
| /** | |
| * Returns the connection timeout speed, in milliseconds, or zero if the timeout | |
| * is infinite or not set. | |
| * | |
| * @return The timeout. | |
| * | |
| * @since 1.5 | |
| */ | |
| public int getConnectTimeout() | |
| { | |
| return timeout; | |
| } | |
| /** | |
| * Set the connection timeout speed, in milliseconds, or zero if the timeout | |
| * is to be considered infinite. Note that in certain socket | |
| * implementations/platforms this method may not have any effect. | |
| * | |
| * Throws an <code>IllegalArgumentException</code> if timeout < 0. | |
| * | |
| * @param timeout - The timeout, in milliseconds. | |
| * | |
| * @since 1.5 | |
| */ | |
| public void setConnectTimeout(int timeout) | |
| throws IllegalArgumentException | |
| { | |
| if( timeout < 0 ) | |
| throw new IllegalArgumentException("Timeout must be 0 or positive."); | |
| this.timeout = timeout; | |
| } | |
| /** | |
| * Returns the value of the content-length header field or -1 if the value | |
| * is not known or not present. | |
| * | |
| * @return The content-length field | |
| */ | |
| public int getContentLength() | |
| { | |
| return getHeaderFieldInt("content-length", -1); | |
| } | |
| /** | |
| * Returns the the content-type of the data pointed to by the URL. This | |
| * method first tries looking for a content-type header. If that is not | |
| * present, it attempts to use the file name to determine the content's | |
| * MIME type. If that is unsuccessful, the method returns null. The caller | |
| * may then still attempt to determine the MIME type by a call to | |
| * guessContentTypeFromStream() | |
| * | |
| * @return The content MIME type | |
| */ | |
| public String getContentType() | |
| { | |
| return getHeaderField("content-type"); | |
| } | |
| /** | |
| * Returns the value of the content-encoding field or null if it is not | |
| * known or not present. | |
| * | |
| * @return The content-encoding field | |
| */ | |
| public String getContentEncoding() | |
| { | |
| return getHeaderField("content-encoding"); | |
| } | |
| /** | |
| * Returns the value of the expires header or 0 if not known or present. | |
| * If populated, the return value is number of seconds since midnight | |
| * on 1/1/1970 GMT. | |
| * | |
| * @return The expiration time. | |
| */ | |
| public long getExpiration() | |
| { | |
| return getHeaderFieldDate("expires", 0L); | |
| } | |
| /** | |
| * Returns the date of the document pointed to by the URL as reported in | |
| * the date field of the header or 0 if the value is not present or not | |
| * known. If populated, the return value is number of seconds since | |
| * midnight on 1/1/1970 GMT. | |
| * | |
| * @return The document date | |
| */ | |
| public long getDate() | |
| { | |
| return getHeaderFieldDate("date", 0L); | |
| } | |
| /** | |
| * Returns the value of the last-modified header field or 0 if not known known | |
| * or not present. If populated, the return value is the number of seconds | |
| * since midnight on 1/1/1970. | |
| * | |
| * @return The last modified time | |
| */ | |
| public long getLastModified() | |
| { | |
| return getHeaderFieldDate("last-modified", 0L); | |
| } | |
| /** | |
| * Return a String representing the header value at the specified index. | |
| * This allows the caller to walk the list of header fields. The analogous | |
| * {@link #getHeaderField(int)} method allows access to the corresponding | |
| * key for this header field | |
| * | |
| * @param index The index into the header field list to retrieve the value for | |
| * | |
| * @return The header value or null if index is past the end of the headers | |
| */ | |
| public String getHeaderField(int index) | |
| { | |
| // Subclasses for specific protocols override this. | |
| return null; | |
| } | |
| /** | |
| * Returns a String representing the value of the header field having | |
| * the named key. Returns null if the header field does not exist. | |
| * | |
| * @param name The key of the header field | |
| * | |
| * @return The value of the header field as a String | |
| */ | |
| public String getHeaderField(String name) | |
| { | |
| // Subclasses for specific protocols override this. | |
| return null; | |
| } | |
| /** | |
| * Returns an unmodifiable Map containing all sent header fields. | |
| * | |
| * @return The map of header fields. The map consists of String keys with | |
| * an unmodifiable List of String objects as value. | |
| * | |
| * @since 1.4 | |
| */ | |
| public Map getHeaderFields() | |
| { | |
| // Subclasses for specific protocols override this. | |
| return Collections.EMPTY_MAP; | |
| } | |
| /** | |
| * Returns the value of the named header field as an int. If the field | |
| * is not present or cannot be parsed as an integer, the default value | |
| * will be returned. | |
| * | |
| * @param name The header field key to lookup | |
| * @param defaultValue The defaule value if the header field is not found | |
| * or can't be parsed. | |
| * | |
| * @return The value of the header field or the default value if the field | |
| * is missing or malformed | |
| */ | |
| public int getHeaderFieldInt(String name, int defaultValue) | |
| { | |
| String value = getHeaderField(name); | |
| if (value == null) | |
| return defaultValue; | |
| try | |
| { | |
| return Integer.parseInt(value); | |
| } | |
| catch (NumberFormatException e) | |
| { | |
| return defaultValue; | |
| } | |
| } | |
| /** | |
| * Returns the value of the named header field as a date. This date will | |
| * be the number of seconds since midnight 1/1/1970 GMT or the default | |
| * value if the field is not present or cannot be converted to a date. | |
| * | |
| * @param name The name of the header field | |
| * @param defaultValue The default date if the header field is not found | |
| * or can't be converted. | |
| * | |
| * @return The date value of the header filed or the default value | |
| * if the field is missing or malformed | |
| */ | |
| public long getHeaderFieldDate(String name, long defaultValue) | |
| { | |
| if (! dateformats_initialized) | |
| initializeDateFormats(); | |
| if (position == null) | |
| position = new ParsePosition(0); | |
| long result = defaultValue; | |
| String str = getHeaderField(name); | |
| if (str != null) | |
| { | |
| for (int i = 0; i < dateFormats.length; i++) | |
| { | |
| SimpleDateFormat df = dateFormats[i]; | |
| position.setIndex(0); | |
| position.setErrorIndex(0); | |
| Date date = df.parse(str, position); | |
| if (date != null) | |
| return date.getTime(); | |
| } | |
| } | |
| return result; | |
| } | |
| /** | |
| * Returns a String representing the header key at the specified index. | |
| * This allows the caller to walk the list of header fields. The analogous | |
| * {@link #getHeaderField(int)} method allows access to the corresponding | |
| * value for this tag. | |
| * | |
| * @param index The index into the header field list to retrieve the key for. | |
| * | |
| * @return The header field key or null if index is past the end | |
| * of the headers. | |
| */ | |
| public String getHeaderFieldKey(int index) | |
| { | |
| // Subclasses for specific protocols override this. | |
| return null; | |
| } | |
| /** | |
| * This method returns the content of the document pointed to by the | |
| * URL as an Object. The type of object depends on the MIME type of | |
| * the object and particular content hander loaded. Most text type | |
| * content handlers will return a subclass of | |
| * <code>InputStream</code>. Images usually return a class that | |
| * implements <code>ImageProducer</code>. There is not guarantee | |
| * what type of object will be returned, however. | |
| * | |
| * <p>This class first determines the MIME type of the content, then | |
| * creates a ContentHandler object to process the input. If the | |
| * <code>ContentHandlerFactory</code> is set, then that object is | |
| * called to load a content handler, otherwise a class called | |
| * gnu.java.net.content.<content_type> is tried. If this | |
| * handler does not exist, the method will simple return the | |
| * <code>InputStream</code> returned by | |
| * <code>getInputStream()</code>. Note that the default | |
| * implementation of <code>getInputStream()</code> throws a | |
| * <code>UnknownServiceException</code> so subclasses are encouraged | |
| * to override this method.</p> | |
| * | |
| * @return the content | |
| * | |
| * @exception IOException If an error with the connection occurs. | |
| * @exception UnknownServiceException If the protocol does not support the | |
| * content type at all. | |
| */ | |
| public Object getContent() throws IOException | |
| { | |
| if (!connected) | |
| connect(); | |
| // FIXME: Doc indicates that other criteria should be applied as | |
| // heuristics to determine the true content type, e.g. see | |
| // guessContentTypeFromName() and guessContentTypeFromStream methods | |
| // as well as FileNameMap class & fileNameMap field & get/set methods. | |
| String type = getContentType(); | |
| ContentHandler ch = getContentHandler(type); | |
| if (ch != null) | |
| return ch.getContent(this); | |
| return getInputStream(); | |
| } | |
| /** | |
| * Retrieves the content of this URLConnection | |
| * | |
| * @param classes The allowed classes for the content | |
| * | |
| * @return the content | |
| * | |
| * @exception IOException If an error occurs | |
| * @exception UnknownServiceException If the protocol does not support the | |
| * content type | |
| */ | |
| public Object getContent(Class[] classes) | |
| throws IOException | |
| { | |
| if (! connected) | |
| connect(); | |
| String type = getContentType(); | |
| ContentHandler ch = getContentHandler(type); | |
| if (ch != null) | |
| return ch.getContent(this, classes); | |
| throw new UnknownServiceException("protocol does not support the content type"); | |
| } | |
| /** | |
| * This method returns a <code>Permission</code> object representing the | |
| * permissions required to access this URL. This method returns | |
| * <code>java.security.AllPermission</code> by default. Subclasses should | |
| * override it to return a more specific permission. For example, an | |
| * HTTP URL should return an instance of <code>SocketPermission</code> | |
| * for the appropriate host and port. | |
| * <p> | |
| * Note that because of items such as HTTP redirects, the permission | |
| * object returned might be different before and after connecting. | |
| * | |
| * @return A Permission object | |
| * | |
| * @exception IOException If the computation of the permission requires | |
| * network or file I/O and an exception occurs while computing it | |
| */ | |
| public Permission getPermission() throws IOException | |
| { | |
| // Subclasses may override this. | |
| return new AllPermission(); | |
| } | |
| /** | |
| * Returns an InputStream for this connection. As this default | |
| * implementation returns null, subclasses should override this method | |
| * | |
| * @return An InputStream for this connection | |
| * | |
| * @exception IOException If an error occurs | |
| * @exception UnknownServiceException If the protocol does not support input | |
| */ | |
| public InputStream getInputStream() throws IOException | |
| { | |
| // Subclasses for specific protocols override this. | |
| throw new UnknownServiceException("Protocol " + url.getProtocol() | |
| + " does not support input."); | |
| } | |
| /** | |
| * Returns an OutputStream for this connection. As this default | |
| * implementation returns null, subclasses should override this method | |
| * | |
| * @return An OutputStream for this connection | |
| * | |
| * @exception IOException If an error occurs | |
| * @exception UnknownServiceException If the protocol does not support output | |
| */ | |
| public OutputStream getOutputStream() throws IOException | |
| { | |
| // Subclasses for specific protocols override this. | |
| throw new UnknownServiceException("Protocol " + url.getProtocol() | |
| + " does not support output."); | |
| } | |
| /** | |
| * The methods prints the value of this object as a String by calling the | |
| * toString() method of its associated URL. Overrides Object.toString() | |
| * | |
| * @return A String representation of this object | |
| */ | |
| public String toString() | |
| { | |
| return this.getClass().getName() + ":" + url.toString(); | |
| } | |
| /** | |
| * Sets the value of a flag indicating whether or not input is going | |
| * to be done for this connection. This default to true unless the | |
| * doOutput flag is set to false, in which case this defaults to false. | |
| * | |
| * @param input <code>true</code> if input is to be done, | |
| * <code>false</code> otherwise | |
| * | |
| * @exception IllegalStateException If already connected | |
| */ | |
| public void setDoInput(boolean input) | |
| { | |
| if (connected) | |
| throw new IllegalStateException("Already connected"); | |
| doInput = input; | |
| } | |
| /** | |
| * Returns the value of a flag indicating whether or not input is going | |
| * to be done for this connection. This default to true unless the | |
| * doOutput flag is set to false, in which case this defaults to false. | |
| * | |
| * @return true if input is to be done, false otherwise | |
| */ | |
| public boolean getDoInput() | |
| { | |
| return doInput; | |
| } | |
| /** | |
| * Sets a boolean flag indicating whether or not output will be done | |
| * on this connection. The default value is false, so this method can | |
| * be used to override the default | |
| * | |
| * @param output ture if output is to be done, false otherwise | |
| * | |
| * @exception IllegalStateException If already connected | |
| */ | |
| public void setDoOutput(boolean output) | |
| { | |
| if (connected) | |
| throw new IllegalStateException("Already connected"); | |
| doOutput = output; | |
| } | |
| /** | |
| * Returns a boolean flag indicating whether or not output will be done | |
| * on this connection. This defaults to false. | |
| * | |
| * @return true if output is to be done, false otherwise | |
| */ | |
| public boolean getDoOutput() | |
| { | |
| return doOutput; | |
| } | |
| /** | |
| * Sets a boolean flag indicating whether or not user interaction is | |
| * allowed for this connection. (For example, in order to prompt for | |
| * username and password info. | |
| * | |
| * @param allow true if user interaction should be allowed, false otherwise. | |
| * | |
| * @exception IllegalStateException If already connected | |
| */ | |
| public void setAllowUserInteraction(boolean allow) | |
| { | |
| if (connected) | |
| throw new IllegalStateException("Already connected"); | |
| allowUserInteraction = allow; | |
| } | |
| /** | |
| * Returns a boolean flag indicating whether or not user interaction is | |
| * allowed for this connection. (For example, in order to prompt for | |
| * username and password info. | |
| * | |
| * @return true if user interaction is allowed, false otherwise | |
| */ | |
| public boolean getAllowUserInteraction() | |
| { | |
| return allowUserInteraction; | |
| } | |
| /** | |
| * Sets the default flag for whether or not interaction with a user | |
| * is allowed. This will be used for all connections unless overridden | |
| * | |
| * @param allow true to allow user interaction, false otherwise | |
| */ | |
| public static void setDefaultAllowUserInteraction(boolean allow) | |
| { | |
| defaultAllowUserInteraction = allow; | |
| } | |
| /** | |
| * Returns the default flag for whether or not interaction with a user | |
| * is allowed. This will be used for all connections unless overridden | |
| * | |
| * @return true if user interaction is allowed, false otherwise | |
| */ | |
| public static boolean getDefaultAllowUserInteraction() | |
| { | |
| return defaultAllowUserInteraction; | |
| } | |
| /** | |
| * Sets a boolean flag indicating whether or not caching will be used | |
| * (if possible) to store data downloaded via the connection. | |
| * | |
| * @param usecaches The new value | |
| * | |
| * @exception IllegalStateException If already connected | |
| */ | |
| public void setUseCaches(boolean usecaches) | |
| { | |
| if (connected) | |
| throw new IllegalStateException("Already connected"); | |
| useCaches = usecaches; | |
| } | |
| /** | |
| * Returns a boolean flag indicating whether or not caching will be used | |
| * (if possible) to store data downloaded via the connection. | |
| * | |
| * @return true if caching should be used if possible, false otherwise | |
| */ | |
| public boolean getUseCaches() | |
| { | |
| return useCaches; | |
| } | |
| /** | |
| * Sets the ifModified since instance variable. If this value is non | |
| * zero and the underlying protocol supports it, the actual document will | |
| * not be fetched unless it has been modified since this time. The value | |
| * passed should be 0 if this feature is to be disabled or the time expressed | |
| * as the number of seconds since midnight 1/1/1970 GMT otherwise. | |
| * | |
| * @param ifmodifiedsince The new value in milliseconds | |
| * since January 1, 1970 GMT | |
| * | |
| * @exception IllegalStateException If already connected | |
| */ | |
| public void setIfModifiedSince(long ifmodifiedsince) | |
| { | |
| if (connected) | |
| throw new IllegalStateException("Already connected"); | |
| ifModifiedSince = ifmodifiedsince; | |
| } | |
| /** | |
| * Returns the ifModified since instance variable. If this value is non | |
| * zero and the underlying protocol supports it, the actual document will | |
| * not be fetched unless it has been modified since this time. The value | |
| * returned will be 0 if this feature is disabled or the time expressed | |
| * as the number of seconds since midnight 1/1/1970 GMT otherwise | |
| * | |
| * @return The ifModifiedSince value | |
| */ | |
| public long getIfModifiedSince() | |
| { | |
| return ifModifiedSince; | |
| } | |
| /** | |
| * Returns the default value used to determine whether or not caching | |
| * of documents will be done when possible. | |
| * | |
| * @return true if caches will be used, false otherwise | |
| */ | |
| public boolean getDefaultUseCaches() | |
| { | |
| return defaultUseCaches; | |
| } | |
| /** | |
| * Sets the default value used to determine whether or not caching | |
| * of documents will be done when possible. | |
| * | |
| * @param use true to use caches if possible by default, false otherwise | |
| */ | |
| public void setDefaultUseCaches(boolean use) | |
| { | |
| defaultUseCaches = use; | |
| } | |
| /** | |
| * Sets the value of the named request property. | |
| * This method does overwrite the value of existing properties with | |
| * the new value. | |
| * | |
| * @param key The name of the property | |
| * @param value The value of the property | |
| * | |
| * @exception IllegalStateException If already connected | |
| * @exception NullPointerException If key is null | |
| * | |
| * @see URLConnection#getRequestProperty(String key) | |
| * @see URLConnection#addRequestProperty(String key, String value) | |
| * | |
| * @since 1.4 | |
| */ | |
| public void setRequestProperty(String key, String value) | |
| { | |
| if (connected) | |
| throw new IllegalStateException("Already connected"); | |
| if (key == null) | |
| throw new NullPointerException("key is null"); | |
| // Do nothing unless overridden by subclasses that support setting | |
| // header fields in the request. | |
| } | |
| /** | |
| * Adds a new request property by a key/value pair. | |
| * This method does not overwrite existing properties with the same key. | |
| * | |
| * @param key Key of the property to add | |
| * @param value Value of the Property to add | |
| * | |
| * @exception IllegalStateException If already connected | |
| * @exception NullPointerException If key is null | |
| * | |
| * @see URLConnection#getRequestProperty(String) | |
| * @see URLConnection#setRequestProperty(String, String) | |
| * | |
| * @since 1.4 | |
| */ | |
| public void addRequestProperty(String key, String value) | |
| { | |
| if (connected) | |
| throw new IllegalStateException("Already connected"); | |
| if (key == null) | |
| throw new NullPointerException("key is null"); | |
| // Do nothing unless overridden by subclasses that support adding | |
| // header fields in the request. | |
| } | |
| /** | |
| * Returns the value of the named request property. | |
| * | |
| * @param key The name of the property | |
| * | |
| * @return Value of the property, or <code>null</code> if key is null. | |
| * | |
| * @exception IllegalStateException If already connected | |
| * | |
| * @see URLConnection#setRequestProperty(String, String) | |
| * @see URLConnection#addRequestProperty(String, String) | |
| */ | |
| public String getRequestProperty(String key) | |
| { | |
| if (connected) | |
| throw new IllegalStateException("Already connected"); | |
| // Overridden by subclasses that support reading header fields from the | |
| // request. | |
| return null; | |
| } | |
| /** | |
| * Returns an unmodifiable Map containing the request properties. | |
| * | |
| * @return The map of properties. The map consists of String keys with an | |
| * unmodifiable List of String objects as value. | |
| * | |
| * @exception IllegalStateException If already connected | |
| * | |
| * @since 1.4 | |
| */ | |
| public Map getRequestProperties() | |
| { | |
| if (connected) | |
| throw new IllegalStateException("Already connected"); | |
| // Overridden by subclasses that support reading header fields from the | |
| // request. | |
| return Collections.EMPTY_MAP; | |
| } | |
| /** | |
| * Sets the default value of a request property. This will be used | |
| * for all connections unless the value of the property is manually | |
| * overridden. | |
| * | |
| * @param key The request property name the default is being set for | |
| * @param value The value to set the default to | |
| * | |
| * @deprecated 1.3 The method setRequestProperty should be used instead. | |
| * This method does nothing now. | |
| * | |
| * @see URLConnection#setRequestProperty(String, String) | |
| */ | |
| public static void setDefaultRequestProperty(String key, String value) | |
| { | |
| // This method does nothing since JDK 1.3. | |
| } | |
| /** | |
| * Returns the default value of a request property. This will be used | |
| * for all connections unless the value of the property is manually | |
| * overridden. | |
| * | |
| * @param key The request property to return the default value of | |
| * | |
| * @return The value of the default property or null if not available | |
| * | |
| * @deprecated 1.3 The method getRequestProperty should be used instead. | |
| * This method does nothing now. | |
| * | |
| * @see URLConnection#getRequestProperty(String) | |
| */ | |
| public static String getDefaultRequestProperty(String key) | |
| { | |
| // This method does nothing since JDK 1.3. | |
| return null; | |
| } | |
| /** | |
| * Sets the ContentHandlerFactory for an application. This can be called | |
| * once and only once. If it is called again, then an Error is thrown. | |
| * Unlike for other set factory methods, this one does not do a security | |
| * check prior to setting the factory. | |
| * | |
| * @param factory The ContentHandlerFactory for this application | |
| * | |
| * @exception Error If the factory has already been defined | |
| * @exception SecurityException If a security manager exists and its | |
| * checkSetFactory method doesn't allow the operation | |
| */ | |
| public static synchronized void setContentHandlerFactory(ContentHandlerFactory factory) | |
| { | |
| if (URLConnection.factory != null) | |
| throw new Error("ContentHandlerFactory already set"); | |
| // Throw an exception if an extant security mgr precludes | |
| // setting the factory. | |
| SecurityManager s = System.getSecurityManager(); | |
| if (s != null) | |
| s.checkSetFactory(); | |
| URLConnection.factory = factory; | |
| } | |
| /** | |
| * Returns the MIME type of a file based on the name of the file. This | |
| * works by searching for the file's extension in a list of file extensions | |
| * and returning the MIME type associated with it. If no type is found, | |
| * then a MIME type of "application/octet-stream" will be returned. | |
| * | |
| * @param filename The filename to determine the MIME type for | |
| * | |
| * @return The MIME type String | |
| * | |
| * @specnote public since JDK 1.4 | |
| */ | |
| public static String guessContentTypeFromName(String filename) | |
| { | |
| return getFileNameMap().getContentTypeFor(filename.toLowerCase()); | |
| } | |
| /** | |
| * Returns the MIME type of a stream based on the first few characters | |
| * at the beginning of the stream. This routine can be used to determine | |
| * the MIME type if a server is believed to be returning an incorrect | |
| * MIME type. This method returns "application/octet-stream" if it | |
| * cannot determine the MIME type. | |
| * <p> | |
| * NOTE: Overriding MIME types sent from the server can be obnoxious | |
| * to user's. See Internet Exploder 4 if you don't believe me. | |
| * | |
| * @param is The InputStream to determine the MIME type from | |
| * | |
| * @return The MIME type | |
| * | |
| * @exception IOException If an error occurs | |
| */ | |
| public static String guessContentTypeFromStream(InputStream is) | |
| throws IOException | |
| { | |
| String result = VMURLConnection.guessContentTypeFromStream(is); | |
| if (result == null) | |
| return "application/octet-stream"; | |
| return result; | |
| } | |
| /** | |
| * This method returns the <code>FileNameMap</code> object being used | |
| * to decode MIME types by file extension. | |
| * | |
| * @return The <code>FileNameMap</code>. | |
| * | |
| * @since 1.2 | |
| */ | |
| public static synchronized FileNameMap getFileNameMap() | |
| { | |
| // Delayed initialization. | |
| if (fileNameMap == null) | |
| fileNameMap = new MimeTypeMapper(); | |
| return fileNameMap; | |
| } | |
| /** | |
| * This method sets the <code>FileNameMap</code> object being used | |
| * to decode MIME types by file extension. | |
| * | |
| * @param map The <code>FileNameMap</code>. | |
| * | |
| * @exception SecurityException If a security manager exists and its | |
| * checkSetFactory method doesn't allow the operation | |
| * | |
| * @since 1.2 | |
| */ | |
| public static synchronized void setFileNameMap(FileNameMap map) | |
| { | |
| // Throw an exception if an extant security manager precludes | |
| // setting the factory. | |
| SecurityManager s = System.getSecurityManager(); | |
| if (s != null) | |
| s.checkSetFactory(); | |
| fileNameMap = map; | |
| } | |
| private ContentHandler getContentHandler(String contentType) | |
| { | |
| // No content type so just handle it as the default. | |
| if (contentType == null || contentType.equals("")) | |
| return null; | |
| ContentHandler handler = null; | |
| // If a non-default factory has been set, use it. | |
| if (factory != null) | |
| handler = factory.createContentHandler(contentType); | |
| // Now try default factory. Using this factory to instantiate built-in | |
| // content handlers is preferable | |
| if (handler == null) | |
| handler = defaultFactory.createContentHandler(contentType); | |
| // User-set factory has not returned a handler. Use the default search | |
| // algorithm. | |
| if (handler == null) | |
| { | |
| // Get the list of packages to check and append our default handler | |
| // to it, along with the JDK specified default as a last resort. | |
| // Except in very unusual environments the JDK specified one shouldn't | |
| // ever be needed (or available). | |
| String propVal = SystemProperties.getProperty("java.content.handler.pkgs"); | |
| propVal = (((propVal == null) ? "" : (propVal + "|")) | |
| + "gnu.java.net.content|sun.net.www.content"); | |
| // Deal with "Content-Type: text/html; charset=ISO-8859-1". | |
| int parameterBegin = contentType.indexOf(';'); | |
| if (parameterBegin >= 1) | |
| contentType = contentType.substring(0, parameterBegin); | |
| contentType = contentType.trim(); | |
| // Replace the '/' character in the content type with '.' and | |
| // all other non-alphabetic, non-numeric characters with '_'. | |
| char[] cArray = contentType.toCharArray(); | |
| for (int i = 0; i < cArray.length; i++) | |
| { | |
| if (cArray[i] == '/') | |
| cArray[i] = '.'; | |
| else if (! ((cArray[i] >= 'A' && cArray[i] <= 'Z') || | |
| (cArray[i] >= 'a' && cArray[i] <= 'z') || | |
| (cArray[i] >= '0' && cArray[i] <= '9'))) | |
| cArray[i] = '_'; | |
| } | |
| String contentClass = new String(cArray); | |
| // See if a class of this content type exists in any of the packages. | |
| StringTokenizer pkgPrefix = new StringTokenizer(propVal, "|"); | |
| do | |
| { | |
| String facName = pkgPrefix.nextToken() + "." + contentClass; | |
| try | |
| { | |
| handler = | |
| (ContentHandler) Class.forName(facName).newInstance(); | |
| } | |
| catch (Exception e) | |
| { | |
| // Can't instantiate; handler still null, go on to next element. | |
| } | |
| } while (handler == null && pkgPrefix.hasMoreTokens()); | |
| } | |
| return handler; | |
| } | |
| // We don't put these in a static initializer, because it creates problems | |
| // with initializer co-dependency: SimpleDateFormat's constructors | |
| // eventually depend on URLConnection (via the java.text.*Symbols classes). | |
| private static synchronized void initializeDateFormats() | |
| { | |
| if (dateformats_initialized) | |
| return; | |
| Locale locale = new Locale("En", "Us", "Unix"); | |
| dateFormats = new SimpleDateFormat[3]; | |
| dateFormats[0] = | |
| new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'", locale); | |
| dateFormats[1] = | |
| new SimpleDateFormat("EEEE, dd-MMM-yy hh:mm:ss 'GMT'", locale); | |
| dateFormats[2] = new SimpleDateFormat("EEE MMM d hh:mm:ss yyyy", locale); | |
| dateformats_initialized = true; | |
| } | |
| } |