jtulach@1396: /* jtulach@1396: * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. jtulach@1396: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jtulach@1396: * jtulach@1396: * This code is free software; you can redistribute it and/or modify it jtulach@1396: * under the terms of the GNU General Public License version 2 only, as jtulach@1396: * published by the Free Software Foundation. Oracle designates this jtulach@1396: * particular file as subject to the "Classpath" exception as provided jtulach@1396: * by Oracle in the LICENSE file that accompanied this code. jtulach@1396: * jtulach@1396: * This code is distributed in the hope that it will be useful, but WITHOUT jtulach@1396: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jtulach@1396: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jtulach@1396: * version 2 for more details (a copy is included in the LICENSE file that jtulach@1396: * accompanied this code). jtulach@1396: * jtulach@1396: * You should have received a copy of the GNU General Public License version jtulach@1396: * 2 along with this work; if not, write to the Free Software Foundation, jtulach@1396: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jtulach@1396: * jtulach@1396: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jtulach@1396: * or visit www.oracle.com if you need additional information or have any jtulach@1396: * questions. jtulach@1396: */ jtulach@1396: jtulach@1396: package java.net; jtulach@1396: jtulach@1396: import java.io.IOException; jtulach@1396: import java.io.InputStream; jtulach@1396: import java.io.OutputStream; jaroslav@1398: import java.io.PrintStream; jaroslav@1398: import java.util.ArrayList; jtulach@1396: import java.util.Date; jtulach@1396: import java.util.StringTokenizer; jtulach@1396: import java.util.Collections; jaroslav@1398: import java.util.HashMap; jaroslav@1398: import java.util.Hashtable; jaroslav@1398: import java.util.Iterator; jtulach@1396: import java.util.Map; jtulach@1396: import java.util.List; jaroslav@1398: import java.util.NoSuchElementException; jtulach@1396: jtulach@1396: /** jtulach@1396: * The abstract class URLConnection is the superclass jtulach@1396: * of all classes that represent a communications link between the jtulach@1396: * application and a URL. Instances of this class can be used both to jtulach@1396: * read from and to write to the resource referenced by the URL. In jtulach@1396: * general, creating a connection to a URL is a multistep process: jtulach@1396: *

jtulach@1396: *

jtulach@1396: * jtulach@1396: * jtulach@1396: * jtulach@1396: * jtulach@1396: *
openConnection()connect()
Manipulate parameters that affect the connection to the remote jtulach@1396: * resource.Interact with the resource; query header fields and jtulach@1396: * contents.
jtulach@1396: * ----------------------------> jtulach@1396: *
time
jtulach@1396: * jtulach@1396: *
    jtulach@1396: *
  1. The connection object is created by invoking the jtulach@1396: * openConnection method on a URL. jtulach@1396: *
  2. The setup parameters and general request properties are manipulated. jtulach@1396: *
  3. The actual connection to the remote object is made, using the jtulach@1396: * connect method. jtulach@1396: *
  4. The remote object becomes available. The header fields and the contents jtulach@1396: * of the remote object can be accessed. jtulach@1396: *
jtulach@1396: *

jtulach@1396: * The setup parameters are modified using the following methods: jtulach@1396: *

jtulach@1396: *

jtulach@1396: * and the general request properties are modified using the method: jtulach@1396: *

jtulach@1396: *

jtulach@1396: * Default values for the AllowUserInteraction and jtulach@1396: * UseCaches parameters can be set using the methods jtulach@1396: * setDefaultAllowUserInteraction and jtulach@1396: * setDefaultUseCaches. jtulach@1396: *

jtulach@1396: * Each of the above set methods has a corresponding jtulach@1396: * get method to retrieve the value of the parameter or jtulach@1396: * general request property. The specific parameters and general jtulach@1396: * request properties that are applicable are protocol specific. jtulach@1396: *

jtulach@1396: * The following methods are used to access the header fields and jtulach@1396: * the contents after the connection is made to the remote object: jtulach@1396: *

jtulach@1396: *

jtulach@1396: * Certain header fields are accessed frequently. The methods: jtulach@1396: *

jtulach@1396: *

jtulach@1396: * provide convenient access to these fields. The jtulach@1396: * getContentType method is used by the jtulach@1396: * getContent method to determine the type of the remote jtulach@1396: * object; subclasses may find it convenient to override the jtulach@1396: * getContentType method. jtulach@1396: *

jtulach@1396: * In the common case, all of the pre-connection parameters and jtulach@1396: * general request properties can be ignored: the pre-connection jtulach@1396: * parameters and request properties default to sensible values. For jtulach@1396: * most clients of this interface, there are only two interesting jtulach@1396: * methods: getInputStream and getContent, jtulach@1396: * which are mirrored in the URL class by convenience methods. jtulach@1396: *

jtulach@1396: * More information on the request properties and header fields of jtulach@1396: * an http connection can be found at: jtulach@1396: *

jtulach@1396:  * http://www.ietf.org/rfc/rfc2616.txt
jtulach@1396:  * 
jtulach@1396: * jtulach@1396: * Note about fileNameMap: In versions prior to JDK 1.1.6, jtulach@1396: * field fileNameMap of URLConnection was public. jtulach@1396: * In JDK 1.1.6 and later, fileNameMap is private; accessor jtulach@1396: * and mutator methods {@link #getFileNameMap() getFileNameMap} and jtulach@1396: * {@link #setFileNameMap(java.net.FileNameMap) setFileNameMap} are added jtulach@1396: * to access it. This change is also described on the jtulach@1396: * Compatibility page. jtulach@1396: * jtulach@1396: * Invoking the close() methods on the InputStream or OutputStream of an jtulach@1396: * URLConnection after a request may free network resources associated with this jtulach@1396: * instance, unless particular protocol specifications specify different behaviours jtulach@1396: * for it. jtulach@1396: * jtulach@1396: * @author James Gosling jtulach@1396: * @see java.net.URL#openConnection() jtulach@1396: * @see java.net.URLConnection#connect() jtulach@1396: * @see java.net.URLConnection#getContent() jtulach@1396: * @see java.net.URLConnection#getContentEncoding() jtulach@1396: * @see java.net.URLConnection#getContentLength() jtulach@1396: * @see java.net.URLConnection#getContentType() jtulach@1396: * @see java.net.URLConnection#getDate() jtulach@1396: * @see java.net.URLConnection#getExpiration() jtulach@1396: * @see java.net.URLConnection#getHeaderField(int) jtulach@1396: * @see java.net.URLConnection#getHeaderField(java.lang.String) jtulach@1396: * @see java.net.URLConnection#getInputStream() jtulach@1396: * @see java.net.URLConnection#getLastModified() jtulach@1396: * @see java.net.URLConnection#getOutputStream() jtulach@1396: * @see java.net.URLConnection#setAllowUserInteraction(boolean) jtulach@1396: * @see java.net.URLConnection#setDefaultUseCaches(boolean) jtulach@1396: * @see java.net.URLConnection#setDoInput(boolean) jtulach@1396: * @see java.net.URLConnection#setDoOutput(boolean) jtulach@1396: * @see java.net.URLConnection#setIfModifiedSince(long) jtulach@1396: * @see java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String) jtulach@1396: * @see java.net.URLConnection#setUseCaches(boolean) jtulach@1396: * @since JDK1.0 jtulach@1396: */ jtulach@1396: public abstract class URLConnection { jtulach@1396: jtulach@1396: /** jtulach@1396: * The URL represents the remote object on the World Wide Web to jtulach@1396: * which this connection is opened. jtulach@1396: *

jtulach@1396: * The value of this field can be accessed by the jtulach@1396: * getURL method. jtulach@1396: *

jtulach@1396: * The default value of this variable is the value of the URL jtulach@1396: * argument in the URLConnection constructor. jtulach@1396: * jtulach@1396: * @see java.net.URLConnection#getURL() jtulach@1396: * @see java.net.URLConnection#url jtulach@1396: */ jtulach@1396: protected URL url; jtulach@1396: jtulach@1396: /** jtulach@1396: * This variable is set by the setDoInput method. Its jtulach@1396: * value is returned by the getDoInput method. jtulach@1396: *

jtulach@1396: * A URL connection can be used for input and/or output. Setting the jtulach@1396: * doInput flag to true indicates that jtulach@1396: * the application intends to read data from the URL connection. jtulach@1396: *

jtulach@1396: * The default value of this field is true. jtulach@1396: * jtulach@1396: * @see java.net.URLConnection#getDoInput() jtulach@1396: * @see java.net.URLConnection#setDoInput(boolean) jtulach@1396: */ jtulach@1396: protected boolean doInput = true; jtulach@1396: jtulach@1396: /** jtulach@1396: * This variable is set by the setDoOutput method. Its jtulach@1396: * value is returned by the getDoOutput method. jtulach@1396: *

jtulach@1396: * A URL connection can be used for input and/or output. Setting the jtulach@1396: * doOutput flag to true indicates jtulach@1396: * that the application intends to write data to the URL connection. jtulach@1396: *

jtulach@1396: * The default value of this field is false. jtulach@1396: * jtulach@1396: * @see java.net.URLConnection#getDoOutput() jtulach@1396: * @see java.net.URLConnection#setDoOutput(boolean) jtulach@1396: */ jtulach@1396: protected boolean doOutput = false; jtulach@1396: jtulach@1396: private static boolean defaultAllowUserInteraction = false; jtulach@1396: jtulach@1396: /** jtulach@1396: * If true, this URL is being examined in jtulach@1396: * a context in which it makes sense to allow user interactions such jtulach@1396: * as popping up an authentication dialog. If false, jtulach@1396: * then no user interaction is allowed. jtulach@1396: *

jtulach@1396: * The value of this field can be set by the jtulach@1396: * setAllowUserInteraction method. jtulach@1396: * Its value is returned by the jtulach@1396: * getAllowUserInteraction method. jtulach@1396: * Its default value is the value of the argument in the last invocation jtulach@1396: * of the setDefaultAllowUserInteraction method. jtulach@1396: * jtulach@1396: * @see java.net.URLConnection#getAllowUserInteraction() jtulach@1396: * @see java.net.URLConnection#setAllowUserInteraction(boolean) jtulach@1396: * @see java.net.URLConnection#setDefaultAllowUserInteraction(boolean) jtulach@1396: */ jtulach@1396: protected boolean allowUserInteraction = defaultAllowUserInteraction; jtulach@1396: jtulach@1396: private static boolean defaultUseCaches = true; jtulach@1396: jtulach@1396: /** jtulach@1396: * If true, the protocol is allowed to use caching jtulach@1396: * whenever it can. If false, the protocol must always jtulach@1396: * try to get a fresh copy of the object. jtulach@1396: *

jtulach@1396: * This field is set by the setUseCaches method. Its jtulach@1396: * value is returned by the getUseCaches method. jtulach@1396: *

jtulach@1396: * Its default value is the value given in the last invocation of the jtulach@1396: * setDefaultUseCaches method. jtulach@1396: * jtulach@1396: * @see java.net.URLConnection#setUseCaches(boolean) jtulach@1396: * @see java.net.URLConnection#getUseCaches() jtulach@1396: * @see java.net.URLConnection#setDefaultUseCaches(boolean) jtulach@1396: */ jtulach@1396: protected boolean useCaches = defaultUseCaches; jtulach@1396: jtulach@1396: /** jtulach@1396: * Some protocols support skipping the fetching of the object unless jtulach@1396: * the object has been modified more recently than a certain time. jtulach@1396: *

jtulach@1396: * A nonzero value gives a time as the number of milliseconds since jtulach@1396: * January 1, 1970, GMT. The object is fetched only if it has been jtulach@1396: * modified more recently than that time. jtulach@1396: *

jtulach@1396: * This variable is set by the setIfModifiedSince jtulach@1396: * method. Its value is returned by the jtulach@1396: * getIfModifiedSince method. jtulach@1396: *

jtulach@1396: * The default value of this field is 0, indicating jtulach@1396: * that the fetching must always occur. jtulach@1396: * jtulach@1396: * @see java.net.URLConnection#getIfModifiedSince() jtulach@1396: * @see java.net.URLConnection#setIfModifiedSince(long) jtulach@1396: */ jtulach@1396: protected long ifModifiedSince = 0; jtulach@1396: jtulach@1396: /** jtulach@1396: * If false, this connection object has not created a jtulach@1396: * communications link to the specified URL. If true, jtulach@1396: * the communications link has been established. jtulach@1396: */ jtulach@1396: protected boolean connected = false; jtulach@1396: jtulach@1396: /** jtulach@1396: * @since 1.5 jtulach@1396: */ jtulach@1396: private int connectTimeout; jtulach@1396: private int readTimeout; jtulach@1396: jtulach@1396: /** jtulach@1396: * @since 1.6 jtulach@1396: */ jtulach@1396: private MessageHeader requests; jtulach@1396: jtulach@1396: /** jtulach@1396: * @since JDK1.1 jtulach@1396: */ jtulach@1396: private static FileNameMap fileNameMap; jtulach@1396: jtulach@1396: /** jtulach@1396: * @since 1.2.2 jtulach@1396: */ jtulach@1396: private static boolean fileNameMapLoaded = false; jtulach@1396: jtulach@1396: /** jtulach@1396: * Loads filename map (a mimetable) from a data file. It will jtulach@1396: * first try to load the user-specific table, defined jtulach@1396: * by "content.types.user.table" property. If that fails, jtulach@1396: * it tries to load the default built-in table at jtulach@1396: * lib/content-types.properties under java home. jtulach@1396: * jtulach@1396: * @return the FileNameMap jtulach@1396: * @since 1.2 jtulach@1396: * @see #setFileNameMap(java.net.FileNameMap) jtulach@1396: */ jtulach@1396: public static synchronized FileNameMap getFileNameMap() { jtulach@1396: if ((fileNameMap == null) && !fileNameMapLoaded) { jaroslav@1398: fileNameMap = new FileNameMap() { jaroslav@1398: @Override jaroslav@1398: public String getContentTypeFor(String fileName) { jaroslav@1398: return "text/plain"; jaroslav@1398: } jaroslav@1398: }; jtulach@1396: fileNameMapLoaded = true; jtulach@1396: } jtulach@1396: jtulach@1396: return new FileNameMap() { jtulach@1396: private FileNameMap map = fileNameMap; jtulach@1396: public String getContentTypeFor(String fileName) { jtulach@1396: return map.getContentTypeFor(fileName); jtulach@1396: } jtulach@1396: }; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Sets the FileNameMap. jtulach@1396: *

jtulach@1396: * If there is a security manager, this method first calls jtulach@1396: * the security manager's checkSetFactory method jtulach@1396: * to ensure the operation is allowed. jtulach@1396: * This could result in a SecurityException. jtulach@1396: * jtulach@1396: * @param map the FileNameMap to be set jtulach@1396: * @exception SecurityException if a security manager exists and its jtulach@1396: * checkSetFactory method doesn't allow the operation. jtulach@1396: * @see SecurityManager#checkSetFactory jtulach@1396: * @see #getFileNameMap() jtulach@1396: * @since 1.2 jtulach@1396: */ jtulach@1396: public static void setFileNameMap(FileNameMap map) { jaroslav@1398: throw new SecurityException(); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Opens a communications link to the resource referenced by this jtulach@1396: * URL, if such a connection has not already been established. jtulach@1396: *

jtulach@1396: * If the connect method is called when the connection jtulach@1396: * has already been opened (indicated by the connected jtulach@1396: * field having the value true), the call is ignored. jtulach@1396: *

jtulach@1396: * URLConnection objects go through two phases: first they are jtulach@1396: * created, then they are connected. After being created, and jtulach@1396: * before being connected, various options can be specified jtulach@1396: * (e.g., doInput and UseCaches). After connecting, it is an jtulach@1396: * error to try to set them. Operations that depend on being jtulach@1396: * connected, like getContentLength, will implicitly perform the jtulach@1396: * connection, if necessary. jtulach@1396: * jtulach@1396: * @throws SocketTimeoutException if the timeout expires before jtulach@1396: * the connection can be established jtulach@1396: * @exception IOException if an I/O error occurs while opening the jtulach@1396: * connection. jtulach@1396: * @see java.net.URLConnection#connected jtulach@1396: * @see #getConnectTimeout() jtulach@1396: * @see #setConnectTimeout(int) jtulach@1396: */ jtulach@1396: abstract public void connect() throws IOException; jtulach@1396: jtulach@1396: /** jtulach@1396: * Sets a specified timeout value, in milliseconds, to be used jtulach@1396: * when opening a communications link to the resource referenced jtulach@1396: * by this URLConnection. If the timeout expires before the jtulach@1396: * connection can be established, a jtulach@1396: * java.net.SocketTimeoutException is raised. A timeout of zero is jtulach@1396: * interpreted as an infinite timeout. jtulach@1396: jtulach@1396: *

Some non-standard implmentation of this method may ignore jtulach@1396: * the specified timeout. To see the connect timeout set, please jtulach@1396: * call getConnectTimeout(). jtulach@1396: * jtulach@1396: * @param timeout an int that specifies the connect jtulach@1396: * timeout value in milliseconds jtulach@1396: * @throws IllegalArgumentException if the timeout parameter is negative jtulach@1396: * jtulach@1396: * @see #getConnectTimeout() jtulach@1396: * @see #connect() jtulach@1396: * @since 1.5 jtulach@1396: */ jtulach@1396: public void setConnectTimeout(int timeout) { jtulach@1396: if (timeout < 0) { jtulach@1396: throw new IllegalArgumentException("timeout can not be negative"); jtulach@1396: } jtulach@1396: connectTimeout = timeout; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns setting for connect timeout. jtulach@1396: *

jtulach@1396: * 0 return implies that the option is disabled jtulach@1396: * (i.e., timeout of infinity). jtulach@1396: * jtulach@1396: * @return an int that indicates the connect timeout jtulach@1396: * value in milliseconds jtulach@1396: * @see #setConnectTimeout(int) jtulach@1396: * @see #connect() jtulach@1396: * @since 1.5 jtulach@1396: */ jtulach@1396: public int getConnectTimeout() { jtulach@1396: return connectTimeout; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Sets the read timeout to a specified timeout, in jtulach@1396: * milliseconds. A non-zero value specifies the timeout when jtulach@1396: * reading from Input stream when a connection is established to a jtulach@1396: * resource. If the timeout expires before there is data available jtulach@1396: * for read, a java.net.SocketTimeoutException is raised. A jtulach@1396: * timeout of zero is interpreted as an infinite timeout. jtulach@1396: * jtulach@1396: *

Some non-standard implementation of this method ignores the jtulach@1396: * specified timeout. To see the read timeout set, please call jtulach@1396: * getReadTimeout(). jtulach@1396: * jtulach@1396: * @param timeout an int that specifies the timeout jtulach@1396: * value to be used in milliseconds jtulach@1396: * @throws IllegalArgumentException if the timeout parameter is negative jtulach@1396: * jtulach@1396: * @see #getReadTimeout() jtulach@1396: * @see InputStream#read() jtulach@1396: * @since 1.5 jtulach@1396: */ jtulach@1396: public void setReadTimeout(int timeout) { jtulach@1396: if (timeout < 0) { jtulach@1396: throw new IllegalArgumentException("timeout can not be negative"); jtulach@1396: } jtulach@1396: readTimeout = timeout; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns setting for read timeout. 0 return implies that the jtulach@1396: * option is disabled (i.e., timeout of infinity). jtulach@1396: * jtulach@1396: * @return an int that indicates the read timeout jtulach@1396: * value in milliseconds jtulach@1396: * jtulach@1396: * @see #setReadTimeout(int) jtulach@1396: * @see InputStream#read() jtulach@1396: * @since 1.5 jtulach@1396: */ jtulach@1396: public int getReadTimeout() { jtulach@1396: return readTimeout; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Constructs a URL connection to the specified URL. A connection to jtulach@1396: * the object referenced by the URL is not created. jtulach@1396: * jtulach@1396: * @param url the specified URL. jtulach@1396: */ jtulach@1396: protected URLConnection(URL url) { jtulach@1396: this.url = url; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of this URLConnection's URL jtulach@1396: * field. jtulach@1396: * jtulach@1396: * @return the value of this URLConnection's URL jtulach@1396: * field. jtulach@1396: * @see java.net.URLConnection#url jtulach@1396: */ jtulach@1396: public URL getURL() { jtulach@1396: return url; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the content-length header field. jtulach@1396: *

jtulach@1396: * Note: {@link #getContentLengthLong() getContentLengthLong()} jtulach@1396: * should be preferred over this method, since it returns a {@code long} jtulach@1396: * instead and is therefore more portable.

jtulach@1396: * jtulach@1396: * @return the content length of the resource that this connection's URL jtulach@1396: * references, {@code -1} if the content length is not known, jtulach@1396: * or if the content length is greater than Integer.MAX_VALUE. jtulach@1396: */ jtulach@1396: public int getContentLength() { jtulach@1396: long l = getContentLengthLong(); jtulach@1396: if (l > Integer.MAX_VALUE) jtulach@1396: return -1; jtulach@1396: return (int) l; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the content-length header field as a jtulach@1396: * long. jtulach@1396: * jtulach@1396: * @return the content length of the resource that this connection's URL jtulach@1396: * references, or -1 if the content length is jtulach@1396: * not known. jtulach@1396: * @since 7.0 jtulach@1396: */ jtulach@1396: public long getContentLengthLong() { jtulach@1396: return getHeaderFieldLong("content-length", -1); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the content-type header field. jtulach@1396: * jtulach@1396: * @return the content type of the resource that the URL references, jtulach@1396: * or null if not known. jtulach@1396: * @see java.net.URLConnection#getHeaderField(java.lang.String) jtulach@1396: */ jtulach@1396: public String getContentType() { jtulach@1396: return getHeaderField("content-type"); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the content-encoding header field. jtulach@1396: * jtulach@1396: * @return the content encoding of the resource that the URL references, jtulach@1396: * or null if not known. jtulach@1396: * @see java.net.URLConnection#getHeaderField(java.lang.String) jtulach@1396: */ jtulach@1396: public String getContentEncoding() { jtulach@1396: return getHeaderField("content-encoding"); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the expires header field. jtulach@1396: * jtulach@1396: * @return the expiration date of the resource that this URL references, jtulach@1396: * or 0 if not known. The value is the number of milliseconds since jtulach@1396: * January 1, 1970 GMT. jtulach@1396: * @see java.net.URLConnection#getHeaderField(java.lang.String) jtulach@1396: */ jtulach@1396: public long getExpiration() { jtulach@1396: return getHeaderFieldDate("expires", 0); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the date header field. jtulach@1396: * jtulach@1396: * @return the sending date of the resource that the URL references, jtulach@1396: * or 0 if not known. The value returned is the jtulach@1396: * number of milliseconds since January 1, 1970 GMT. jtulach@1396: * @see java.net.URLConnection#getHeaderField(java.lang.String) jtulach@1396: */ jtulach@1396: public long getDate() { jtulach@1396: return getHeaderFieldDate("date", 0); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the last-modified header field. jtulach@1396: * The result is the number of milliseconds since January 1, 1970 GMT. jtulach@1396: * jtulach@1396: * @return the date the resource referenced by this jtulach@1396: * URLConnection was last modified, or 0 if not known. jtulach@1396: * @see java.net.URLConnection#getHeaderField(java.lang.String) jtulach@1396: */ jtulach@1396: public long getLastModified() { jtulach@1396: return getHeaderFieldDate("last-modified", 0); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the named header field. jtulach@1396: *

jtulach@1396: * If called on a connection that sets the same header multiple times jtulach@1396: * with possibly different values, only the last value is returned. jtulach@1396: * jtulach@1396: * jtulach@1396: * @param name the name of a header field. jtulach@1396: * @return the value of the named header field, or null jtulach@1396: * if there is no such field in the header. jtulach@1396: */ jtulach@1396: public String getHeaderField(String name) { jtulach@1396: return null; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns an unmodifiable Map of the header fields. jtulach@1396: * The Map keys are Strings that represent the jtulach@1396: * response-header field names. Each Map value is an jtulach@1396: * unmodifiable List of Strings that represents jtulach@1396: * the corresponding field values. jtulach@1396: * jtulach@1396: * @return a Map of header fields jtulach@1396: * @since 1.4 jtulach@1396: */ jtulach@1396: public Map> getHeaderFields() { jtulach@1396: return Collections.EMPTY_MAP; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the named field parsed as a number. jtulach@1396: *

jtulach@1396: * This form of getHeaderField exists because some jtulach@1396: * connection types (e.g., http-ng) have pre-parsed jtulach@1396: * headers. Classes for that connection type can override this method jtulach@1396: * and short-circuit the parsing. jtulach@1396: * jtulach@1396: * @param name the name of the header field. jtulach@1396: * @param Default the default value. jtulach@1396: * @return the value of the named field, parsed as an integer. The jtulach@1396: * Default value is returned if the field is jtulach@1396: * missing or malformed. jtulach@1396: */ jtulach@1396: public int getHeaderFieldInt(String name, int Default) { jtulach@1396: String value = getHeaderField(name); jtulach@1396: try { jtulach@1396: return Integer.parseInt(value); jtulach@1396: } catch (Exception e) { } jtulach@1396: return Default; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the named field parsed as a number. jtulach@1396: *

jtulach@1396: * This form of getHeaderField exists because some jtulach@1396: * connection types (e.g., http-ng) have pre-parsed jtulach@1396: * headers. Classes for that connection type can override this method jtulach@1396: * and short-circuit the parsing. jtulach@1396: * jtulach@1396: * @param name the name of the header field. jtulach@1396: * @param Default the default value. jtulach@1396: * @return the value of the named field, parsed as a long. The jtulach@1396: * Default value is returned if the field is jtulach@1396: * missing or malformed. jtulach@1396: * @since 7.0 jtulach@1396: */ jtulach@1396: public long getHeaderFieldLong(String name, long Default) { jtulach@1396: String value = getHeaderField(name); jtulach@1396: try { jtulach@1396: return Long.parseLong(value); jtulach@1396: } catch (Exception e) { } jtulach@1396: return Default; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the named field parsed as date. jtulach@1396: * The result is the number of milliseconds since January 1, 1970 GMT jtulach@1396: * represented by the named field. jtulach@1396: *

jtulach@1396: * This form of getHeaderField exists because some jtulach@1396: * connection types (e.g., http-ng) have pre-parsed jtulach@1396: * headers. Classes for that connection type can override this method jtulach@1396: * and short-circuit the parsing. jtulach@1396: * jtulach@1396: * @param name the name of the header field. jtulach@1396: * @param Default a default value. jtulach@1396: * @return the value of the field, parsed as a date. The value of the jtulach@1396: * Default argument is returned if the field is jtulach@1396: * missing or malformed. jtulach@1396: */ jtulach@1396: public long getHeaderFieldDate(String name, long Default) { jtulach@1396: String value = getHeaderField(name); jtulach@1396: try { jtulach@1396: return Date.parse(value); jtulach@1396: } catch (Exception e) { } jtulach@1396: return Default; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the key for the nth header field. jtulach@1396: * It returns null if there are fewer than n+1 fields. jtulach@1396: * jtulach@1396: * @param n an index, where n>=0 jtulach@1396: * @return the key for the nth header field, jtulach@1396: * or null if there are fewer than n+1 jtulach@1396: * fields. jtulach@1396: */ jtulach@1396: public String getHeaderFieldKey(int n) { jtulach@1396: return null; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value for the nth header field. jtulach@1396: * It returns null if there are fewer than jtulach@1396: * n+1fields. jtulach@1396: *

jtulach@1396: * This method can be used in conjunction with the jtulach@1396: * {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all jtulach@1396: * the headers in the message. jtulach@1396: * jtulach@1396: * @param n an index, where n>=0 jtulach@1396: * @return the value of the nth header field jtulach@1396: * or null if there are fewer than n+1 fields jtulach@1396: * @see java.net.URLConnection#getHeaderFieldKey(int) jtulach@1396: */ jtulach@1396: public String getHeaderField(int n) { jtulach@1396: return null; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Retrieves the contents of this URL connection. jtulach@1396: *

jtulach@1396: * This method first determines the content type of the object by jtulach@1396: * calling the getContentType method. If this is jtulach@1396: * the first time that the application has seen that specific content jtulach@1396: * type, a content handler for that content type is created: jtulach@1396: *

    jtulach@1396: *
  1. If the application has set up a content handler factory instance jtulach@1396: * using the setContentHandlerFactory method, the jtulach@1396: * createContentHandler method of that instance is called jtulach@1396: * with the content type as an argument; the result is a content jtulach@1396: * handler for that content type. jtulach@1396: *
  2. If no content handler factory has yet been set up, or if the jtulach@1396: * factory's createContentHandler method returns jtulach@1396: * null, then the application loads the class named: jtulach@1396: *
    jtulach@1396:      *         sun.net.www.content.<contentType>
    jtulach@1396:      *     
    jtulach@1396: * where <contentType> is formed by taking the jtulach@1396: * content-type string, replacing all slash characters with a jtulach@1396: * period ('.'), and all other non-alphanumeric characters jtulach@1396: * with the underscore character '_'. The alphanumeric jtulach@1396: * characters are specifically the 26 uppercase ASCII letters jtulach@1396: * 'A' through 'Z', the 26 lowercase ASCII jtulach@1396: * letters 'a' through 'z', and the 10 ASCII jtulach@1396: * digits '0' through '9'. If the specified jtulach@1396: * class does not exist, or is not a subclass of jtulach@1396: * ContentHandler, then an jtulach@1396: * UnknownServiceException is thrown. jtulach@1396: *
jtulach@1396: * jtulach@1396: * @return the object fetched. The instanceof operator jtulach@1396: * should be used to determine the specific kind of object jtulach@1396: * returned. jtulach@1396: * @exception IOException if an I/O error occurs while jtulach@1396: * getting the content. jtulach@1396: * @exception UnknownServiceException if the protocol does not support jtulach@1396: * the content type. jtulach@1396: * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String) jtulach@1396: * @see java.net.URLConnection#getContentType() jtulach@1396: * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory) jtulach@1396: */ jtulach@1396: public Object getContent() throws IOException { jtulach@1396: // Must call getInputStream before GetHeaderField gets called jtulach@1396: // so that FileNotFoundException has a chance to be thrown up jtulach@1396: // from here without being caught. jtulach@1396: getInputStream(); jtulach@1396: return getContentHandler().getContent(this); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Retrieves the contents of this URL connection. jtulach@1396: * jtulach@1396: * @param classes the Class array jtulach@1396: * indicating the requested types jtulach@1396: * @return the object fetched that is the first match of the type jtulach@1396: * specified in the classes array. null if none of jtulach@1396: * the requested types are supported. jtulach@1396: * The instanceof operator should be used to jtulach@1396: * determine the specific kind of object returned. jtulach@1396: * @exception IOException if an I/O error occurs while jtulach@1396: * getting the content. jtulach@1396: * @exception UnknownServiceException if the protocol does not support jtulach@1396: * the content type. jtulach@1396: * @see java.net.URLConnection#getContent() jtulach@1396: * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String) jtulach@1396: * @see java.net.URLConnection#getContent(java.lang.Class[]) jtulach@1396: * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory) jtulach@1396: * @since 1.3 jtulach@1396: */ jtulach@1396: public Object getContent(Class[] classes) throws IOException { jtulach@1396: // Must call getInputStream before GetHeaderField gets called jtulach@1396: // so that FileNotFoundException has a chance to be thrown up jtulach@1396: // from here without being caught. jtulach@1396: getInputStream(); jtulach@1396: return getContentHandler().getContent(this, classes); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns a permission object representing the permission jtulach@1396: * necessary to make the connection represented by this jtulach@1396: * object. This method returns null if no permission is jtulach@1396: * required to make the connection. By default, this method jtulach@1396: * returns java.security.AllPermission. Subclasses jtulach@1396: * should override this method and return the permission jtulach@1396: * that best represents the permission required to make a jtulach@1396: * a connection to the URL. For example, a URLConnection jtulach@1396: * representing a file: URL would return a jtulach@1396: * java.io.FilePermission object. jtulach@1396: * jtulach@1396: *

The permission returned may dependent upon the state of the jtulach@1396: * connection. For example, the permission before connecting may be jtulach@1396: * different from that after connecting. For example, an HTTP jtulach@1396: * sever, say foo.com, may redirect the connection to a different jtulach@1396: * host, say bar.com. Before connecting the permission returned by jtulach@1396: * the connection will represent the permission needed to connect jtulach@1396: * to foo.com, while the permission returned after connecting will jtulach@1396: * be to bar.com. jtulach@1396: * jtulach@1396: *

Permissions are generally used for two purposes: to protect jtulach@1396: * caches of objects obtained through URLConnections, and to check jtulach@1396: * the right of a recipient to learn about a particular URL. In jtulach@1396: * the first case, the permission should be obtained jtulach@1396: * after the object has been obtained. For example, in an jtulach@1396: * HTTP connection, this will represent the permission to connect jtulach@1396: * to the host from which the data was ultimately fetched. In the jtulach@1396: * second case, the permission should be obtained and tested jtulach@1396: * before connecting. jtulach@1396: * jtulach@1396: * @return the permission object representing the permission jtulach@1396: * necessary to make the connection represented by this jtulach@1396: * URLConnection. jtulach@1396: * jtulach@1396: * @exception IOException if the computation of the permission jtulach@1396: * requires network or file I/O and an exception occurs while jtulach@1396: * computing it. jtulach@1396: */ jaroslav@1398: // public Permission getPermission() throws IOException { jaroslav@1398: // return SecurityConstants.ALL_PERMISSION; jaroslav@1398: // } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns an input stream that reads from this open connection. jtulach@1396: * jtulach@1396: * A SocketTimeoutException can be thrown when reading from the jtulach@1396: * returned input stream if the read timeout expires before data jtulach@1396: * is available for read. jtulach@1396: * jtulach@1396: * @return an input stream that reads from this open connection. jtulach@1396: * @exception IOException if an I/O error occurs while jtulach@1396: * creating the input stream. jtulach@1396: * @exception UnknownServiceException if the protocol does not support jtulach@1396: * input. jtulach@1396: * @see #setReadTimeout(int) jtulach@1396: * @see #getReadTimeout() jtulach@1396: */ jtulach@1396: public InputStream getInputStream() throws IOException { jtulach@1396: throw new UnknownServiceException("protocol doesn't support input"); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns an output stream that writes to this connection. jtulach@1396: * jtulach@1396: * @return an output stream that writes to this connection. jtulach@1396: * @exception IOException if an I/O error occurs while jtulach@1396: * creating the output stream. jtulach@1396: * @exception UnknownServiceException if the protocol does not support jtulach@1396: * output. jtulach@1396: */ jtulach@1396: public OutputStream getOutputStream() throws IOException { jtulach@1396: throw new UnknownServiceException("protocol doesn't support output"); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns a String representation of this URL connection. jtulach@1396: * jtulach@1396: * @return a string representation of this URLConnection. jtulach@1396: */ jtulach@1396: public String toString() { jtulach@1396: return this.getClass().getName() + ":" + url; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Sets the value of the doInput field for this jtulach@1396: * URLConnection to the specified value. jtulach@1396: *

jtulach@1396: * A URL connection can be used for input and/or output. Set the DoInput jtulach@1396: * flag to true if you intend to use the URL connection for input, jtulach@1396: * false if not. The default is true. jtulach@1396: * jtulach@1396: * @param doinput the new value. jtulach@1396: * @throws IllegalStateException if already connected jtulach@1396: * @see java.net.URLConnection#doInput jtulach@1396: * @see #getDoInput() jtulach@1396: */ jtulach@1396: public void setDoInput(boolean doinput) { jtulach@1396: if (connected) jtulach@1396: throw new IllegalStateException("Already connected"); jtulach@1396: doInput = doinput; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of this URLConnection's jtulach@1396: * doInput flag. jtulach@1396: * jtulach@1396: * @return the value of this URLConnection's jtulach@1396: * doInput flag. jtulach@1396: * @see #setDoInput(boolean) jtulach@1396: */ jtulach@1396: public boolean getDoInput() { jtulach@1396: return doInput; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Sets the value of the doOutput field for this jtulach@1396: * URLConnection to the specified value. jtulach@1396: *

jtulach@1396: * A URL connection can be used for input and/or output. Set the DoOutput jtulach@1396: * flag to true if you intend to use the URL connection for output, jtulach@1396: * false if not. The default is false. jtulach@1396: * jtulach@1396: * @param dooutput the new value. jtulach@1396: * @throws IllegalStateException if already connected jtulach@1396: * @see #getDoOutput() jtulach@1396: */ jtulach@1396: public void setDoOutput(boolean dooutput) { jtulach@1396: if (connected) jtulach@1396: throw new IllegalStateException("Already connected"); jtulach@1396: doOutput = dooutput; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of this URLConnection's jtulach@1396: * doOutput flag. jtulach@1396: * jtulach@1396: * @return the value of this URLConnection's jtulach@1396: * doOutput flag. jtulach@1396: * @see #setDoOutput(boolean) jtulach@1396: */ jtulach@1396: public boolean getDoOutput() { jtulach@1396: return doOutput; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Set the value of the allowUserInteraction field of jtulach@1396: * this URLConnection. jtulach@1396: * jtulach@1396: * @param allowuserinteraction the new value. jtulach@1396: * @throws IllegalStateException if already connected jtulach@1396: * @see #getAllowUserInteraction() jtulach@1396: */ jtulach@1396: public void setAllowUserInteraction(boolean allowuserinteraction) { jtulach@1396: if (connected) jtulach@1396: throw new IllegalStateException("Already connected"); jtulach@1396: allowUserInteraction = allowuserinteraction; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the allowUserInteraction field for jtulach@1396: * this object. jtulach@1396: * jtulach@1396: * @return the value of the allowUserInteraction field for jtulach@1396: * this object. jtulach@1396: * @see #setAllowUserInteraction(boolean) jtulach@1396: */ jtulach@1396: public boolean getAllowUserInteraction() { jtulach@1396: return allowUserInteraction; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Sets the default value of the jtulach@1396: * allowUserInteraction field for all future jtulach@1396: * URLConnection objects to the specified value. jtulach@1396: * jtulach@1396: * @param defaultallowuserinteraction the new value. jtulach@1396: * @see #getDefaultAllowUserInteraction() jtulach@1396: */ jtulach@1396: public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) { jtulach@1396: defaultAllowUserInteraction = defaultallowuserinteraction; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the default value of the allowUserInteraction jtulach@1396: * field. jtulach@1396: *

jtulach@1396: * Ths default is "sticky", being a part of the static state of all jtulach@1396: * URLConnections. This flag applies to the next, and all following jtulach@1396: * URLConnections that are created. jtulach@1396: * jtulach@1396: * @return the default value of the allowUserInteraction jtulach@1396: * field. jtulach@1396: * @see #setDefaultAllowUserInteraction(boolean) jtulach@1396: */ jtulach@1396: public static boolean getDefaultAllowUserInteraction() { jtulach@1396: return defaultAllowUserInteraction; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Sets the value of the useCaches field of this jtulach@1396: * URLConnection to the specified value. jtulach@1396: *

jtulach@1396: * Some protocols do caching of documents. Occasionally, it is important jtulach@1396: * to be able to "tunnel through" and ignore the caches (e.g., the jtulach@1396: * "reload" button in a browser). If the UseCaches flag on a connection jtulach@1396: * is true, the connection is allowed to use whatever caches it can. jtulach@1396: * If false, caches are to be ignored. jtulach@1396: * The default value comes from DefaultUseCaches, which defaults to jtulach@1396: * true. jtulach@1396: * jtulach@1396: * @param usecaches a boolean indicating whether jtulach@1396: * or not to allow caching jtulach@1396: * @throws IllegalStateException if already connected jtulach@1396: * @see #getUseCaches() jtulach@1396: */ jtulach@1396: public void setUseCaches(boolean usecaches) { jtulach@1396: if (connected) jtulach@1396: throw new IllegalStateException("Already connected"); jtulach@1396: useCaches = usecaches; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of this URLConnection's jtulach@1396: * useCaches field. jtulach@1396: * jtulach@1396: * @return the value of this URLConnection's jtulach@1396: * useCaches field. jtulach@1396: * @see #setUseCaches(boolean) jtulach@1396: */ jtulach@1396: public boolean getUseCaches() { jtulach@1396: return useCaches; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Sets the value of the ifModifiedSince field of jtulach@1396: * this URLConnection to the specified value. jtulach@1396: * jtulach@1396: * @param ifmodifiedsince the new value. jtulach@1396: * @throws IllegalStateException if already connected jtulach@1396: * @see #getIfModifiedSince() jtulach@1396: */ jtulach@1396: public void setIfModifiedSince(long ifmodifiedsince) { jtulach@1396: if (connected) jtulach@1396: throw new IllegalStateException("Already connected"); jtulach@1396: ifModifiedSince = ifmodifiedsince; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of this object's ifModifiedSince field. jtulach@1396: * jtulach@1396: * @return the value of this object's ifModifiedSince field. jtulach@1396: * @see #setIfModifiedSince(long) jtulach@1396: */ jtulach@1396: public long getIfModifiedSince() { jtulach@1396: return ifModifiedSince; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the default value of a URLConnection's jtulach@1396: * useCaches flag. jtulach@1396: *

jtulach@1396: * Ths default is "sticky", being a part of the static state of all jtulach@1396: * URLConnections. This flag applies to the next, and all following jtulach@1396: * URLConnections that are created. jtulach@1396: * jtulach@1396: * @return the default value of a URLConnection's jtulach@1396: * useCaches flag. jtulach@1396: * @see #setDefaultUseCaches(boolean) jtulach@1396: */ jtulach@1396: public boolean getDefaultUseCaches() { jtulach@1396: return defaultUseCaches; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Sets the default value of the useCaches field to the jtulach@1396: * specified value. jtulach@1396: * jtulach@1396: * @param defaultusecaches the new value. jtulach@1396: * @see #getDefaultUseCaches() jtulach@1396: */ jtulach@1396: public void setDefaultUseCaches(boolean defaultusecaches) { jtulach@1396: defaultUseCaches = defaultusecaches; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Sets the general request property. If a property with the key already jtulach@1396: * exists, overwrite its value with the new value. jtulach@1396: * jtulach@1396: *

NOTE: HTTP requires all request properties which can jtulach@1396: * legally have multiple instances with the same key jtulach@1396: * to use a comma-seperated list syntax which enables multiple jtulach@1396: * properties to be appended into a single property. jtulach@1396: * jtulach@1396: * @param key the keyword by which the request is known jtulach@1396: * (e.g., "Accept"). jtulach@1396: * @param value the value associated with it. jtulach@1396: * @throws IllegalStateException if already connected jtulach@1396: * @throws NullPointerException if key is null jtulach@1396: * @see #getRequestProperty(java.lang.String) jtulach@1396: */ jtulach@1396: public void setRequestProperty(String key, String value) { jtulach@1396: if (connected) jtulach@1396: throw new IllegalStateException("Already connected"); jtulach@1396: if (key == null) jtulach@1396: throw new NullPointerException ("key is null"); jtulach@1396: jtulach@1396: if (requests == null) jtulach@1396: requests = new MessageHeader(); jtulach@1396: jtulach@1396: requests.set(key, value); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Adds a general request property specified by a jtulach@1396: * key-value pair. This method will not overwrite jtulach@1396: * existing values associated with the same key. jtulach@1396: * jtulach@1396: * @param key the keyword by which the request is known jtulach@1396: * (e.g., "Accept"). jtulach@1396: * @param value the value associated with it. jtulach@1396: * @throws IllegalStateException if already connected jtulach@1396: * @throws NullPointerException if key is null jtulach@1396: * @see #getRequestProperties() jtulach@1396: * @since 1.4 jtulach@1396: */ jtulach@1396: public void addRequestProperty(String key, String value) { jtulach@1396: if (connected) jtulach@1396: throw new IllegalStateException("Already connected"); jtulach@1396: if (key == null) jtulach@1396: throw new NullPointerException ("key is null"); jtulach@1396: jtulach@1396: if (requests == null) jtulach@1396: requests = new MessageHeader(); jtulach@1396: jtulach@1396: requests.add(key, value); jtulach@1396: } jtulach@1396: jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the named general request property for this jtulach@1396: * connection. jtulach@1396: * jtulach@1396: * @param key the keyword by which the request is known (e.g., "Accept"). jtulach@1396: * @return the value of the named general request property for this jtulach@1396: * connection. If key is null, then null is returned. jtulach@1396: * @throws IllegalStateException if already connected jtulach@1396: * @see #setRequestProperty(java.lang.String, java.lang.String) jtulach@1396: */ jtulach@1396: public String getRequestProperty(String key) { jtulach@1396: if (connected) jtulach@1396: throw new IllegalStateException("Already connected"); jtulach@1396: jtulach@1396: if (requests == null) jtulach@1396: return null; jtulach@1396: jtulach@1396: return requests.findValue(key); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns an unmodifiable Map of general request jtulach@1396: * properties for this connection. The Map keys jtulach@1396: * are Strings that represent the request-header jtulach@1396: * field names. Each Map value is a unmodifiable List jtulach@1396: * of Strings that represents the corresponding jtulach@1396: * field values. jtulach@1396: * jtulach@1396: * @return a Map of the general request properties for this connection. jtulach@1396: * @throws IllegalStateException if already connected jtulach@1396: * @since 1.4 jtulach@1396: */ jtulach@1396: public Map> getRequestProperties() { jtulach@1396: if (connected) jtulach@1396: throw new IllegalStateException("Already connected"); jtulach@1396: jtulach@1396: if (requests == null) jtulach@1396: return Collections.EMPTY_MAP; jtulach@1396: jtulach@1396: return requests.getHeaders(null); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Sets the default value of a general request property. When a jtulach@1396: * URLConnection is created, it is initialized with jtulach@1396: * these properties. jtulach@1396: * jtulach@1396: * @param key the keyword by which the request is known jtulach@1396: * (e.g., "Accept"). jtulach@1396: * @param value the value associated with the key. jtulach@1396: * jtulach@1396: * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String) jtulach@1396: * jtulach@1396: * @deprecated The instance specific setRequestProperty method jtulach@1396: * should be used after an appropriate instance of URLConnection jtulach@1396: * is obtained. Invoking this method will have no effect. jtulach@1396: * jtulach@1396: * @see #getDefaultRequestProperty(java.lang.String) jtulach@1396: */ jtulach@1396: @Deprecated jtulach@1396: public static void setDefaultRequestProperty(String key, String value) { jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns the value of the default request property. Default request jtulach@1396: * properties are set for every connection. jtulach@1396: * jtulach@1396: * @param key the keyword by which the request is known (e.g., "Accept"). jtulach@1396: * @return the value of the default request property jtulach@1396: * for the specified key. jtulach@1396: * jtulach@1396: * @see java.net.URLConnection#getRequestProperty(java.lang.String) jtulach@1396: * jtulach@1396: * @deprecated The instance specific getRequestProperty method jtulach@1396: * should be used after an appropriate instance of URLConnection jtulach@1396: * is obtained. jtulach@1396: * jtulach@1396: * @see #setDefaultRequestProperty(java.lang.String, java.lang.String) jtulach@1396: */ jtulach@1396: @Deprecated jtulach@1396: public static String getDefaultRequestProperty(String key) { jtulach@1396: return null; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * The ContentHandler factory. jtulach@1396: */ jtulach@1396: static ContentHandlerFactory factory; jtulach@1396: jtulach@1396: /** jtulach@1396: * Sets the ContentHandlerFactory of an jtulach@1396: * application. It can be called at most once by an application. jtulach@1396: *

jtulach@1396: * The ContentHandlerFactory instance is used to jtulach@1396: * construct a content handler from a content type jtulach@1396: *

jtulach@1396: * If there is a security manager, this method first calls jtulach@1396: * the security manager's checkSetFactory method jtulach@1396: * to ensure the operation is allowed. jtulach@1396: * This could result in a SecurityException. jtulach@1396: * jtulach@1396: * @param fac the desired factory. jtulach@1396: * @exception Error if the factory has already been defined. jtulach@1396: * @exception SecurityException if a security manager exists and its jtulach@1396: * checkSetFactory method doesn't allow the operation. jtulach@1396: * @see java.net.ContentHandlerFactory jtulach@1396: * @see java.net.URLConnection#getContent() jtulach@1396: * @see SecurityManager#checkSetFactory jtulach@1396: */ jtulach@1396: public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) { jaroslav@1398: throw new SecurityException(); jtulach@1396: } jtulach@1396: jtulach@1396: private static Hashtable handlers = new Hashtable(); jtulach@1396: jtulach@1396: /** jtulach@1396: * Gets the Content Handler appropriate for this connection. jtulach@1396: * @param connection the connection to use. jtulach@1396: */ jtulach@1396: synchronized ContentHandler getContentHandler() jtulach@1396: throws UnknownServiceException jtulach@1396: { jtulach@1396: String contentType = stripOffParameters(getContentType()); jtulach@1396: ContentHandler handler = null; jtulach@1396: if (contentType == null) jtulach@1396: throw new UnknownServiceException("no content-type"); jtulach@1396: try { jtulach@1396: handler = (ContentHandler) handlers.get(contentType); jtulach@1396: if (handler != null) jtulach@1396: return handler; jtulach@1396: } catch(Exception e) { jtulach@1396: } jtulach@1396: jtulach@1396: if (factory != null) jtulach@1396: handler = factory.createContentHandler(contentType); jtulach@1396: if (handler == null) { jtulach@1396: try { jtulach@1396: handler = lookupContentHandlerClassFor(contentType); jtulach@1396: } catch(Exception e) { jtulach@1396: e.printStackTrace(); jtulach@1396: handler = UnknownContentHandler.INSTANCE; jtulach@1396: } jtulach@1396: handlers.put(contentType, handler); jtulach@1396: } jtulach@1396: return handler; jtulach@1396: } jtulach@1396: jtulach@1396: /* jtulach@1396: * Media types are in the format: type/subtype*(; parameter). jtulach@1396: * For looking up the content handler, we should ignore those jtulach@1396: * parameters. jtulach@1396: */ jtulach@1396: private String stripOffParameters(String contentType) jtulach@1396: { jtulach@1396: if (contentType == null) jtulach@1396: return null; jtulach@1396: int index = contentType.indexOf(';'); jtulach@1396: jtulach@1396: if (index > 0) jtulach@1396: return contentType.substring(0, index); jtulach@1396: else jtulach@1396: return contentType; jtulach@1396: } jtulach@1396: jtulach@1396: private static final String contentClassPrefix = "sun.net.www.content"; jtulach@1396: private static final String contentPathProp = "java.content.handler.pkgs"; jtulach@1396: jtulach@1396: /** jtulach@1396: * Looks for a content handler in a user-defineable set of places. jtulach@1396: * By default it looks in sun.net.www.content, but users can define a jtulach@1396: * vertical-bar delimited set of class prefixes to search through in jtulach@1396: * addition by defining the java.content.handler.pkgs property. jtulach@1396: * The class name must be of the form: jtulach@1396: *

jtulach@1396:      *     {package-prefix}.{major}.{minor}
jtulach@1396:      * e.g.
jtulach@1396:      *     YoyoDyne.experimental.text.plain
jtulach@1396:      * 
jtulach@1396: */ jtulach@1396: private ContentHandler lookupContentHandlerClassFor(String contentType) jtulach@1396: throws InstantiationException, IllegalAccessException, ClassNotFoundException { jtulach@1396: String contentHandlerClassName = typeToPackageName(contentType); jtulach@1396: jtulach@1396: String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes(); jtulach@1396: jtulach@1396: StringTokenizer packagePrefixIter = jtulach@1396: new StringTokenizer(contentHandlerPkgPrefixes, "|"); jtulach@1396: jtulach@1396: while (packagePrefixIter.hasMoreTokens()) { jtulach@1396: String packagePrefix = packagePrefixIter.nextToken().trim(); jtulach@1396: jtulach@1396: try { jtulach@1396: String clsName = packagePrefix + "." + contentHandlerClassName; jtulach@1396: Class cls = null; jtulach@1396: try { jtulach@1396: cls = Class.forName(clsName); jtulach@1396: } catch (ClassNotFoundException e) { jtulach@1396: ClassLoader cl = ClassLoader.getSystemClassLoader(); jtulach@1396: if (cl != null) { jtulach@1396: cls = cl.loadClass(clsName); jtulach@1396: } jtulach@1396: } jtulach@1396: if (cls != null) { jtulach@1396: ContentHandler handler = jtulach@1396: (ContentHandler)cls.newInstance(); jtulach@1396: return handler; jtulach@1396: } jtulach@1396: } catch(Exception e) { jtulach@1396: } jtulach@1396: } jtulach@1396: jtulach@1396: return UnknownContentHandler.INSTANCE; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Utility function to map a MIME content type into an equivalent jtulach@1396: * pair of class name components. For example: "text/html" would jtulach@1396: * be returned as "text.html" jtulach@1396: */ jtulach@1396: private String typeToPackageName(String contentType) { jtulach@1396: // make sure we canonicalize the class name: all lower case jtulach@1396: contentType = contentType.toLowerCase(); jtulach@1396: int len = contentType.length(); jtulach@1396: char nm[] = new char[len]; jtulach@1396: contentType.getChars(0, len, nm, 0); jtulach@1396: for (int i = 0; i < len; i++) { jtulach@1396: char c = nm[i]; jtulach@1396: if (c == '/') { jtulach@1396: nm[i] = '.'; jtulach@1396: } else if (!('A' <= c && c <= 'Z' || jtulach@1396: 'a' <= c && c <= 'z' || jtulach@1396: '0' <= c && c <= '9')) { jtulach@1396: nm[i] = '_'; jtulach@1396: } jtulach@1396: } jtulach@1396: return new String(nm); jtulach@1396: } jtulach@1396: jtulach@1396: jtulach@1396: /** jtulach@1396: * Returns a vertical bar separated list of package prefixes for potential jtulach@1396: * content handlers. Tries to get the java.content.handler.pkgs property jtulach@1396: * to use as a set of package prefixes to search. Whether or not jtulach@1396: * that property has been defined, the sun.net.www.content is always jtulach@1396: * the last one on the returned package list. jtulach@1396: */ jtulach@1396: private String getContentHandlerPkgPrefixes() { jaroslav@1398: String packagePrefixList = ""; jaroslav@1398: jtulach@1396: if (packagePrefixList != "") { jtulach@1396: packagePrefixList += "|"; jtulach@1396: } jtulach@1396: jtulach@1396: return packagePrefixList + contentClassPrefix; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Tries to determine the content type of an object, based jtulach@1396: * on the specified "file" component of a URL. jtulach@1396: * This is a convenience method that can be used by jtulach@1396: * subclasses that override the getContentType method. jtulach@1396: * jtulach@1396: * @param fname a filename. jtulach@1396: * @return a guess as to what the content type of the object is, jtulach@1396: * based upon its file name. jtulach@1396: * @see java.net.URLConnection#getContentType() jtulach@1396: */ jtulach@1396: public static String guessContentTypeFromName(String fname) { jtulach@1396: return getFileNameMap().getContentTypeFor(fname); jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Tries to determine the type of an input stream based on the jtulach@1396: * characters at the beginning of the input stream. This method can jtulach@1396: * be used by subclasses that override the jtulach@1396: * getContentType method. jtulach@1396: *

jtulach@1396: * Ideally, this routine would not be needed. But many jtulach@1396: * http servers return the incorrect content type; in jtulach@1396: * addition, there are many nonstandard extensions. Direct inspection jtulach@1396: * of the bytes to determine the content type is often more accurate jtulach@1396: * than believing the content type claimed by the http server. jtulach@1396: * jtulach@1396: * @param is an input stream that supports marks. jtulach@1396: * @return a guess at the content type, or null if none jtulach@1396: * can be determined. jtulach@1396: * @exception IOException if an I/O error occurs while reading the jtulach@1396: * input stream. jtulach@1396: * @see java.io.InputStream#mark(int) jtulach@1396: * @see java.io.InputStream#markSupported() jtulach@1396: * @see java.net.URLConnection#getContentType() jtulach@1396: */ jtulach@1396: static public String guessContentTypeFromStream(InputStream is) jtulach@1396: throws IOException { jtulach@1396: // If we can't read ahead safely, just give up on guessing jtulach@1396: if (!is.markSupported()) jtulach@1396: return null; jtulach@1396: jtulach@1396: is.mark(16); jtulach@1396: int c1 = is.read(); jtulach@1396: int c2 = is.read(); jtulach@1396: int c3 = is.read(); jtulach@1396: int c4 = is.read(); jtulach@1396: int c5 = is.read(); jtulach@1396: int c6 = is.read(); jtulach@1396: int c7 = is.read(); jtulach@1396: int c8 = is.read(); jtulach@1396: int c9 = is.read(); jtulach@1396: int c10 = is.read(); jtulach@1396: int c11 = is.read(); jtulach@1396: int c12 = is.read(); jtulach@1396: int c13 = is.read(); jtulach@1396: int c14 = is.read(); jtulach@1396: int c15 = is.read(); jtulach@1396: int c16 = is.read(); jtulach@1396: is.reset(); jtulach@1396: jtulach@1396: if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) { jtulach@1396: return "application/java-vm"; jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == 0xAC && c2 == 0xED) { jtulach@1396: // next two bytes are version number, currently 0x00 0x05 jtulach@1396: return "application/x-java-serialized-object"; jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == '<') { jtulach@1396: if (c2 == '!' jtulach@1396: || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' || jtulach@1396: c3 == 'e' && c4 == 'a' && c5 == 'd') || jtulach@1396: (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) || jtulach@1396: ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' || jtulach@1396: c3 == 'E' && c4 == 'A' && c5 == 'D') || jtulach@1396: (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) { jtulach@1396: return "text/html"; jtulach@1396: } jtulach@1396: jtulach@1396: if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') { jtulach@1396: return "application/xml"; jtulach@1396: } jtulach@1396: } jtulach@1396: jtulach@1396: // big and little (identical) endian UTF-8 encodings, with BOM jtulach@1396: if (c1 == 0xef && c2 == 0xbb && c3 == 0xbf) { jtulach@1396: if (c4 == '<' && c5 == '?' && c6 == 'x') { jtulach@1396: return "application/xml"; jtulach@1396: } jtulach@1396: } jtulach@1396: jtulach@1396: // big and little endian UTF-16 encodings, with byte order mark jtulach@1396: if (c1 == 0xfe && c2 == 0xff) { jtulach@1396: if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' && jtulach@1396: c7 == 0 && c8 == 'x') { jtulach@1396: return "application/xml"; jtulach@1396: } jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == 0xff && c2 == 0xfe) { jtulach@1396: if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 && jtulach@1396: c7 == 'x' && c8 == 0) { jtulach@1396: return "application/xml"; jtulach@1396: } jtulach@1396: } jtulach@1396: jtulach@1396: // big and little endian UTF-32 encodings, with BOM jtulach@1396: if (c1 == 0x00 && c2 == 0x00 && c3 == 0xfe && c4 == 0xff) { jtulach@1396: if (c5 == 0 && c6 == 0 && c7 == 0 && c8 == '<' && jtulach@1396: c9 == 0 && c10 == 0 && c11 == 0 && c12 == '?' && jtulach@1396: c13 == 0 && c14 == 0 && c15 == 0 && c16 == 'x') { jtulach@1396: return "application/xml"; jtulach@1396: } jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == 0xff && c2 == 0xfe && c3 == 0x00 && c4 == 0x00) { jtulach@1396: if (c5 == '<' && c6 == 0 && c7 == 0 && c8 == 0 && jtulach@1396: c9 == '?' && c10 == 0 && c11 == 0 && c12 == 0 && jtulach@1396: c13 == 'x' && c14 == 0 && c15 == 0 && c16 == 0) { jtulach@1396: return "application/xml"; jtulach@1396: } jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') { jtulach@1396: return "image/gif"; jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') { jtulach@1396: return "image/x-bitmap"; jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' && jtulach@1396: c5 == 'M' && c6 == '2') { jtulach@1396: return "image/x-pixmap"; jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == 137 && c2 == 80 && c3 == 78 && jtulach@1396: c4 == 71 && c5 == 13 && c6 == 10 && jtulach@1396: c7 == 26 && c8 == 10) { jtulach@1396: return "image/png"; jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) { jtulach@1396: if (c4 == 0xE0) { jtulach@1396: return "image/jpeg"; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * File format used by digital cameras to store images. jtulach@1396: * Exif Format can be read by any application supporting jtulach@1396: * JPEG. Exif Spec can be found at: jtulach@1396: * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF jtulach@1396: */ jtulach@1396: if ((c4 == 0xE1) && jtulach@1396: (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' && jtulach@1396: c11 == 0)) { jtulach@1396: return "image/jpeg"; jtulach@1396: } jtulach@1396: jtulach@1396: if (c4 == 0xEE) { jtulach@1396: return "image/jpg"; jtulach@1396: } jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 && jtulach@1396: c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) { jtulach@1396: jtulach@1396: /* Above is signature of Microsoft Structured Storage. jtulach@1396: * Below this, could have tests for various SS entities. jtulach@1396: * For now, just test for FlashPix. jtulach@1396: */ jtulach@1396: if (checkfpx(is)) { jtulach@1396: return "image/vnd.fpx"; jtulach@1396: } jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) { jtulach@1396: return "audio/basic"; // .au format, big endian jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) { jtulach@1396: return "audio/basic"; // .au format, little endian jtulach@1396: } jtulach@1396: jtulach@1396: if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') { jtulach@1396: /* I don't know if this is official but evidence jtulach@1396: * suggests that .wav files start with "RIFF" - brown jtulach@1396: */ jtulach@1396: return "audio/x-wav"; jtulach@1396: } jtulach@1396: return null; jtulach@1396: } jtulach@1396: jtulach@1396: /** jtulach@1396: * Check for FlashPix image data in InputStream is. Return true if jtulach@1396: * the stream has FlashPix data, false otherwise. Before calling this jtulach@1396: * method, the stream should have already been checked to be sure it jtulach@1396: * contains Microsoft Structured Storage data. jtulach@1396: */ jtulach@1396: static private boolean checkfpx(InputStream is) throws IOException { jtulach@1396: jtulach@1396: /* Test for FlashPix image data in Microsoft Structured Storage format. jtulach@1396: * In general, should do this with calls to an SS implementation. jtulach@1396: * Lacking that, need to dig via offsets to get to the FlashPix jtulach@1396: * ClassID. Details: jtulach@1396: * jtulach@1396: * Offset to Fpx ClsID from beginning of stream should be: jtulach@1396: * jtulach@1396: * FpxClsidOffset = rootEntryOffset + clsidOffset jtulach@1396: * jtulach@1396: * where: clsidOffset = 0x50. jtulach@1396: * rootEntryOffset = headerSize + sectorSize*sectDirStart jtulach@1396: * + 128*rootEntryDirectory jtulach@1396: * jtulach@1396: * where: headerSize = 0x200 (always) jtulach@1396: * sectorSize = 2 raised to power of uSectorShift, jtulach@1396: * which is found in the header at jtulach@1396: * offset 0x1E. jtulach@1396: * sectDirStart = found in the header at offset 0x30. jtulach@1396: * rootEntryDirectory = in general, should search for jtulach@1396: * directory labelled as root. jtulach@1396: * We will assume value of 0 (i.e., jtulach@1396: * rootEntry is in first directory) jtulach@1396: */ jtulach@1396: jtulach@1396: // Mark the stream so we can reset it. 0x100 is enough for the first jtulach@1396: // few reads, but the mark will have to be reset and set again once jtulach@1396: // the offset to the root directory entry is computed. That offset jtulach@1396: // can be very large and isn't know until the stream has been read from jtulach@1396: is.mark(0x100); jtulach@1396: jtulach@1396: // Get the byte ordering located at 0x1E. 0xFE is Intel, jtulach@1396: // 0xFF is other jtulach@1396: long toSkip = (long)0x1C; jtulach@1396: long posn; jtulach@1396: jtulach@1396: if ((posn = skipForward(is, toSkip)) < toSkip) { jtulach@1396: is.reset(); jtulach@1396: return false; jtulach@1396: } jtulach@1396: jtulach@1396: int c[] = new int[16]; jtulach@1396: if (readBytes(c, 2, is) < 0) { jtulach@1396: is.reset(); jtulach@1396: return false; jtulach@1396: } jtulach@1396: jtulach@1396: int byteOrder = c[0]; jtulach@1396: jtulach@1396: posn+=2; jtulach@1396: int uSectorShift; jtulach@1396: if (readBytes(c, 2, is) < 0) { jtulach@1396: is.reset(); jtulach@1396: return false; jtulach@1396: } jtulach@1396: jtulach@1396: if(byteOrder == 0xFE) { jtulach@1396: uSectorShift = c[0]; jtulach@1396: uSectorShift += c[1] << 8; jtulach@1396: } jtulach@1396: else { jtulach@1396: uSectorShift = c[0] << 8; jtulach@1396: uSectorShift += c[1]; jtulach@1396: } jtulach@1396: jtulach@1396: posn += 2; jtulach@1396: toSkip = (long)0x30 - posn; jtulach@1396: long skipped = 0; jtulach@1396: if ((skipped = skipForward(is, toSkip)) < toSkip) { jtulach@1396: is.reset(); jtulach@1396: return false; jtulach@1396: } jtulach@1396: posn += skipped; jtulach@1396: jtulach@1396: if (readBytes(c, 4, is) < 0) { jtulach@1396: is.reset(); jtulach@1396: return false; jtulach@1396: } jtulach@1396: jtulach@1396: int sectDirStart; jtulach@1396: if(byteOrder == 0xFE) { jtulach@1396: sectDirStart = c[0]; jtulach@1396: sectDirStart += c[1] << 8; jtulach@1396: sectDirStart += c[2] << 16; jtulach@1396: sectDirStart += c[3] << 24; jtulach@1396: } else { jtulach@1396: sectDirStart = c[0] << 24; jtulach@1396: sectDirStart += c[1] << 16; jtulach@1396: sectDirStart += c[2] << 8; jtulach@1396: sectDirStart += c[3]; jtulach@1396: } jtulach@1396: posn += 4; jtulach@1396: is.reset(); // Reset back to the beginning jtulach@1396: jtulach@1396: toSkip = 0x200L + (long)(1<= 0;) jaroslav@1398: if (keys[i] == null) jaroslav@1398: return values[i]; jaroslav@1398: } else jaroslav@1398: for (int i = nkeys; --i >= 0;) { jaroslav@1398: if (k.equalsIgnoreCase(keys[i])) jaroslav@1398: return values[i]; jaroslav@1398: } jaroslav@1398: return null; jaroslav@1398: } jaroslav@1398: jaroslav@1398: // return the location of the key jaroslav@1398: public synchronized int getKey(String k) { jaroslav@1398: for (int i = nkeys; --i >= 0;) jaroslav@1398: if ((keys[i] == k) || jaroslav@1398: (k != null && k.equalsIgnoreCase(keys[i]))) jaroslav@1398: return i; jaroslav@1398: return -1; jaroslav@1398: } jaroslav@1398: jaroslav@1398: public synchronized String getKey(int n) { jaroslav@1398: if (n < 0 || n >= nkeys) return null; jaroslav@1398: return keys[n]; jaroslav@1398: } jaroslav@1398: jaroslav@1398: public synchronized String getValue(int n) { jaroslav@1398: if (n < 0 || n >= nkeys) return null; jaroslav@1398: return values[n]; jaroslav@1398: } jaroslav@1398: jaroslav@1398: /** Deprecated: Use multiValueIterator() instead. jaroslav@1398: * jaroslav@1398: * Find the next value that corresponds to this key. jaroslav@1398: * It finds the first value that follows v. To iterate jaroslav@1398: * over all the values of a key use: jaroslav@1398: *

jaroslav@1398:      *          for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) {
jaroslav@1398:      *              ...
jaroslav@1398:      *          }
jaroslav@1398:      *  
jaroslav@1398: */ jaroslav@1398: public synchronized String findNextValue(String k, String v) { jaroslav@1398: boolean foundV = false; jaroslav@1398: if (k == null) { jaroslav@1398: for (int i = nkeys; --i >= 0;) jaroslav@1398: if (keys[i] == null) jaroslav@1398: if (foundV) jaroslav@1398: return values[i]; jaroslav@1398: else if (values[i] == v) jaroslav@1398: foundV = true; jaroslav@1398: } else jaroslav@1398: for (int i = nkeys; --i >= 0;) jaroslav@1398: if (k.equalsIgnoreCase(keys[i])) jaroslav@1398: if (foundV) jaroslav@1398: return values[i]; jaroslav@1398: else if (values[i] == v) jaroslav@1398: foundV = true; jaroslav@1398: return null; jaroslav@1398: } jaroslav@1398: jaroslav@1398: class HeaderIterator implements Iterator { jaroslav@1398: int index = 0; jaroslav@1398: int next = -1; jaroslav@1398: String key; jaroslav@1398: boolean haveNext = false; jaroslav@1398: Object lock; jaroslav@1398: jaroslav@1398: public HeaderIterator (String k, Object lock) { jaroslav@1398: key = k; jaroslav@1398: this.lock = lock; jaroslav@1398: } jaroslav@1398: public boolean hasNext () { jaroslav@1398: synchronized (lock) { jaroslav@1398: if (haveNext) { jaroslav@1398: return true; jaroslav@1398: } jaroslav@1398: while (index < nkeys) { jaroslav@1398: if (key.equalsIgnoreCase (keys[index])) { jaroslav@1398: haveNext = true; jaroslav@1398: next = index++; jaroslav@1398: return true; jaroslav@1398: } jaroslav@1398: index ++; jaroslav@1398: } jaroslav@1398: return false; jaroslav@1398: } jaroslav@1398: } jaroslav@1398: public String next() { jaroslav@1398: synchronized (lock) { jaroslav@1398: if (haveNext) { jaroslav@1398: haveNext = false; jaroslav@1398: return values [next]; jaroslav@1398: } jaroslav@1398: if (hasNext()) { jaroslav@1398: return next(); jaroslav@1398: } else { jaroslav@1398: throw new NoSuchElementException ("No more elements"); jaroslav@1398: } jaroslav@1398: } jaroslav@1398: } jaroslav@1398: public void remove () { jaroslav@1398: throw new UnsupportedOperationException ("remove not allowed"); jaroslav@1398: } jaroslav@1398: } jaroslav@1398: jaroslav@1398: /** jaroslav@1398: * return an Iterator that returns all values of a particular jaroslav@1398: * key in sequence jaroslav@1398: */ jaroslav@1398: public Iterator multiValueIterator (String k) { jaroslav@1398: return new HeaderIterator (k, this); jaroslav@1398: } jaroslav@1398: jaroslav@1398: public synchronized Map> getHeaders() { jaroslav@1398: return getHeaders(null); jaroslav@1398: } jaroslav@1398: jaroslav@1398: public synchronized Map> getHeaders(String[] excludeList) { jaroslav@1398: return filterAndAddHeaders(excludeList, null); jaroslav@1398: } jaroslav@1398: jaroslav@1398: public synchronized Map> filterAndAddHeaders(String[] excludeList, Map> include) { jaroslav@1398: boolean skipIt = false; jaroslav@1398: Map> m = new HashMap>(); jaroslav@1398: for (int i = nkeys; --i >= 0;) { jaroslav@1398: if (excludeList != null) { jaroslav@1398: // check if the key is in the excludeList. jaroslav@1398: // if so, don't include it in the Map. jaroslav@1398: for (int j = 0; j < excludeList.length; j++) { jaroslav@1398: if ((excludeList[j] != null) && jaroslav@1398: (excludeList[j].equalsIgnoreCase(keys[i]))) { jaroslav@1398: skipIt = true; jaroslav@1398: break; jaroslav@1398: } jaroslav@1398: } jaroslav@1398: } jaroslav@1398: if (!skipIt) { jaroslav@1398: List l = m.get(keys[i]); jaroslav@1398: if (l == null) { jaroslav@1398: l = new ArrayList(); jaroslav@1398: m.put(keys[i], l); jaroslav@1398: } jaroslav@1398: l.add(values[i]); jaroslav@1398: } else { jaroslav@1398: // reset the flag jaroslav@1398: skipIt = false; jaroslav@1398: } jaroslav@1398: } jaroslav@1398: jaroslav@1398: if (include != null) { jaroslav@1398: Iterator entries = include.entrySet().iterator(); jaroslav@1398: while (entries.hasNext()) { jaroslav@1398: Map.Entry entry = (Map.Entry)entries.next(); jaroslav@1398: List l = (List)m.get(entry.getKey()); jaroslav@1398: if (l == null) { jaroslav@1398: l = new ArrayList(); jaroslav@1398: m.put((String)entry.getKey(), l); jaroslav@1398: } jaroslav@1398: l.add(entry.getValue()); jaroslav@1398: } jaroslav@1398: } jaroslav@1398: jaroslav@1398: for (String key : m.keySet()) { jaroslav@1398: m.put(key, Collections.unmodifiableList(m.get(key))); jaroslav@1398: } jaroslav@1398: jaroslav@1398: return Collections.unmodifiableMap(m); jaroslav@1398: } jaroslav@1398: jaroslav@1398: /** Prints the key-value pairs represented by this jaroslav@1398: header. Also prints the RFC required blank line jaroslav@1398: at the end. Omits pairs with a null key. */ jaroslav@1398: public synchronized void print(PrintStream p) { jaroslav@1398: for (int i = 0; i < nkeys; i++) jaroslav@1398: if (keys[i] != null) { jaroslav@1398: p.print(keys[i] + jaroslav@1398: (values[i] != null ? ": "+values[i]: "") + "\r\n"); jaroslav@1398: } jaroslav@1398: p.print("\r\n"); jaroslav@1398: p.flush(); jaroslav@1398: } jaroslav@1398: jaroslav@1398: /** Adds a key value pair to the end of the jaroslav@1398: header. Duplicates are allowed */ jaroslav@1398: public synchronized void add(String k, String v) { jaroslav@1398: grow(); jaroslav@1398: keys[nkeys] = k; jaroslav@1398: values[nkeys] = v; jaroslav@1398: nkeys++; jaroslav@1398: } jaroslav@1398: jaroslav@1398: /** Prepends a key value pair to the beginning of the jaroslav@1398: header. Duplicates are allowed */ jaroslav@1398: public synchronized void prepend(String k, String v) { jaroslav@1398: grow(); jaroslav@1398: for (int i = nkeys; i > 0; i--) { jaroslav@1398: keys[i] = keys[i-1]; jaroslav@1398: values[i] = values[i-1]; jaroslav@1398: } jaroslav@1398: keys[0] = k; jaroslav@1398: values[0] = v; jaroslav@1398: nkeys++; jaroslav@1398: } jaroslav@1398: jaroslav@1398: /** Overwrite the previous key/val pair at location 'i' jaroslav@1398: * with the new k/v. If the index didn't exist before jaroslav@1398: * the key/val is simply tacked onto the end. jaroslav@1398: */ jaroslav@1398: jaroslav@1398: public synchronized void set(int i, String k, String v) { jaroslav@1398: grow(); jaroslav@1398: if (i < 0) { jaroslav@1398: return; jaroslav@1398: } else if (i >= nkeys) { jaroslav@1398: add(k, v); jaroslav@1398: } else { jaroslav@1398: keys[i] = k; jaroslav@1398: values[i] = v; jaroslav@1398: } jaroslav@1398: } jaroslav@1398: jaroslav@1398: jaroslav@1398: /** grow the key/value arrays as needed */ jaroslav@1398: jaroslav@1398: private void grow() { jaroslav@1398: if (keys == null || nkeys >= keys.length) { jaroslav@1398: String[] nk = new String[nkeys + 4]; jaroslav@1398: String[] nv = new String[nkeys + 4]; jaroslav@1398: if (keys != null) jaroslav@1398: System.arraycopy(keys, 0, nk, 0, nkeys); jaroslav@1398: if (values != null) jaroslav@1398: System.arraycopy(values, 0, nv, 0, nkeys); jaroslav@1398: keys = nk; jaroslav@1398: values = nv; jaroslav@1398: } jaroslav@1398: } jaroslav@1398: jaroslav@1398: /** jaroslav@1398: * Remove the key from the header. If there are multiple values under jaroslav@1398: * the same key, they are all removed. jaroslav@1398: * Nothing is done if the key doesn't exist. jaroslav@1398: * After a remove, the other pairs' order are not changed. jaroslav@1398: * @param k the key to remove jaroslav@1398: */ jaroslav@1398: public synchronized void remove(String k) { jaroslav@1398: if(k == null) { jaroslav@1398: for (int i = 0; i < nkeys; i++) { jaroslav@1398: while (keys[i] == null && i < nkeys) { jaroslav@1398: for(int j=i; j= 0;) jaroslav@1398: if (k.equalsIgnoreCase(keys[i])) { jaroslav@1398: values[i] = v; jaroslav@1398: return; jaroslav@1398: } jaroslav@1398: add(k, v); jaroslav@1398: } jaroslav@1398: jaroslav@1398: /** Set's the value of a key only if there is no jaroslav@1398: * key with that value already. jaroslav@1398: */ jaroslav@1398: jaroslav@1398: public synchronized void setIfNotSet(String k, String v) { jaroslav@1398: if (findValue(k) == null) { jaroslav@1398: add(k, v); jaroslav@1398: } jaroslav@1398: } jaroslav@1398: jaroslav@1398: /** Convert a message-id string to canonical form (strips off jaroslav@1398: leading and trailing <>s) */ jaroslav@1398: public static String canonicalID(String id) { jaroslav@1398: if (id == null) jaroslav@1398: return ""; jaroslav@1398: int st = 0; jaroslav@1398: int len = id.length(); jaroslav@1398: boolean substr = false; jaroslav@1398: int c; jaroslav@1398: while (st < len && ((c = id.charAt(st)) == '<' || jaroslav@1398: c <= ' ')) { jaroslav@1398: st++; jaroslav@1398: substr = true; jaroslav@1398: } jaroslav@1398: while (st < len && ((c = id.charAt(len - 1)) == '>' || jaroslav@1398: c <= ' ')) { jaroslav@1398: len--; jaroslav@1398: substr = true; jaroslav@1398: } jaroslav@1398: return substr ? id.substring(st, len) : id; jaroslav@1398: } jaroslav@1398: jaroslav@1398: /** Parse a MIME header from an input stream. */ jaroslav@1398: public void parseHeader(InputStream is) throws java.io.IOException { jaroslav@1398: synchronized (this) { jaroslav@1398: nkeys = 0; jaroslav@1398: } jaroslav@1398: mergeHeader(is); jaroslav@1398: } jaroslav@1398: jaroslav@1398: /** Parse and merge a MIME header from an input stream. */ jaroslav@1398: public void mergeHeader(InputStream is) throws java.io.IOException { jaroslav@1398: if (is == null) jaroslav@1398: return; jaroslav@1398: char s[] = new char[10]; jaroslav@1398: int firstc = is.read(); jaroslav@1398: while (firstc != '\n' && firstc != '\r' && firstc >= 0) { jaroslav@1398: int len = 0; jaroslav@1398: int keyend = -1; jaroslav@1398: int c; jaroslav@1398: boolean inKey = firstc > ' '; jaroslav@1398: s[len++] = (char) firstc; jaroslav@1398: parseloop:{ jaroslav@1398: while ((c = is.read()) >= 0) { jaroslav@1398: switch (c) { jaroslav@1398: case ':': jaroslav@1398: if (inKey && len > 0) jaroslav@1398: keyend = len; jaroslav@1398: inKey = false; jaroslav@1398: break; jaroslav@1398: case '\t': jaroslav@1398: c = ' '; jaroslav@1398: case ' ': jaroslav@1398: inKey = false; jaroslav@1398: break; jaroslav@1398: case '\r': jaroslav@1398: case '\n': jaroslav@1398: firstc = is.read(); jaroslav@1398: if (c == '\r' && firstc == '\n') { jaroslav@1398: firstc = is.read(); jaroslav@1398: if (firstc == '\r') jaroslav@1398: firstc = is.read(); jaroslav@1398: } jaroslav@1398: if (firstc == '\n' || firstc == '\r' || firstc > ' ') jaroslav@1398: break parseloop; jaroslav@1398: /* continuation */ jaroslav@1398: c = ' '; jaroslav@1398: break; jaroslav@1398: } jaroslav@1398: if (len >= s.length) { jaroslav@1398: char ns[] = new char[s.length * 2]; jaroslav@1398: System.arraycopy(s, 0, ns, 0, len); jaroslav@1398: s = ns; jaroslav@1398: } jaroslav@1398: s[len++] = (char) c; jaroslav@1398: } jaroslav@1398: firstc = -1; jaroslav@1398: } jaroslav@1398: while (len > 0 && s[len - 1] <= ' ') jaroslav@1398: len--; jaroslav@1398: String k; jaroslav@1398: if (keyend <= 0) { jaroslav@1398: k = null; jaroslav@1398: keyend = 0; jaroslav@1398: } else { jaroslav@1398: k = String.copyValueOf(s, 0, keyend); jaroslav@1398: if (keyend < len && s[keyend] == ':') jaroslav@1398: keyend++; jaroslav@1398: while (keyend < len && s[keyend] <= ' ') jaroslav@1398: keyend++; jaroslav@1398: } jaroslav@1398: String v; jaroslav@1398: if (keyend >= len) jaroslav@1398: v = new String(); jaroslav@1398: else jaroslav@1398: v = String.copyValueOf(s, keyend, len - keyend); jaroslav@1398: add(k, v); jaroslav@1398: } jaroslav@1398: } jaroslav@1398: jaroslav@1398: public synchronized String toString() { jaroslav@1398: String result = super.toString() + nkeys + " pairs: "; jaroslav@1398: for (int i = 0; i < keys.length && i < nkeys; i++) { jaroslav@1398: result += "{"+keys[i]+": "+values[i]+"}"; jaroslav@1398: } jaroslav@1398: return result; jaroslav@1398: } jaroslav@1398: } jaroslav@1398: jaroslav@1398: interface ContentHandlerFactory { jaroslav@1398: jaroslav@1398: public ContentHandler createContentHandler(String contentType); jaroslav@1398: } jaroslav@1398: jaroslav@1398: abstract class ContentHandler { jaroslav@1398: /** jaroslav@1398: * Given a URL connect stream positioned at the beginning of the jaroslav@1398: * representation of an object, this method reads that stream and jaroslav@1398: * creates an object from it. jaroslav@1398: * jaroslav@1398: * @param urlc a URL connection. jaroslav@1398: * @return the object read by the ContentHandler. jaroslav@1398: * @exception IOException if an I/O error occurs while reading the object. jaroslav@1398: */ jaroslav@1398: abstract public Object getContent(URLConnection urlc) throws IOException; jaroslav@1398: jaroslav@1398: /** jaroslav@1398: * Given a URL connect stream positioned at the beginning of the jaroslav@1398: * representation of an object, this method reads that stream and jaroslav@1398: * creates an object that matches one of the types specified. jaroslav@1398: * jaroslav@1398: * The default implementation of this method should call getContent() jaroslav@1398: * and screen the return type for a match of the suggested types. jaroslav@1398: * jaroslav@1398: * @param urlc a URL connection. jaroslav@1398: * @param classes an array of types requested jaroslav@1398: * @return the object read by the ContentHandler that is jaroslav@1398: * the first match of the suggested types. jaroslav@1398: * null if none of the requested are supported. jaroslav@1398: * @exception IOException if an I/O error occurs while reading the object. jaroslav@1398: * @since 1.3 jaroslav@1398: */ jaroslav@1398: public Object getContent(URLConnection urlc, Class[] classes) throws IOException { jaroslav@1398: Object obj = getContent(urlc); jaroslav@1398: jaroslav@1398: for (int i = 0; i < classes.length; i++) { jaroslav@1398: if (classes[i].isInstance(obj)) { jaroslav@1398: return obj; jaroslav@1398: } jaroslav@1398: } jaroslav@1398: return null; jaroslav@1398: } jaroslav@1398: jaroslav@1398: } jaroslav@1398: class UnknownServiceException extends IOException { jaroslav@1398: private static final long serialVersionUID = -4169033248853639508L; jaroslav@1398: jaroslav@1398: /** jaroslav@1398: * Constructs a new UnknownServiceException with no jaroslav@1398: * detail message. jaroslav@1398: */ jaroslav@1398: public UnknownServiceException() { jaroslav@1398: } jaroslav@1398: jaroslav@1398: /** jaroslav@1398: * Constructs a new UnknownServiceException with the jaroslav@1398: * specified detail message. jaroslav@1398: * jaroslav@1398: * @param msg the detail message. jaroslav@1398: */ jaroslav@1398: public UnknownServiceException(String msg) { jaroslav@1398: super(msg); jaroslav@1398: } jaroslav@1398: } jaroslav@1398: /** jaroslav@1398: * A simple interface which provides a mechanism to map jaroslav@1398: * between a file name and a MIME type string. jaroslav@1398: * jaroslav@1398: * @author Steven B. Byrne jaroslav@1398: * @since JDK1.1 jaroslav@1398: */ jaroslav@1398: interface FileNameMap { jaroslav@1398: jaroslav@1398: /** jaroslav@1398: * Gets the MIME type for the specified file name. jaroslav@1398: * @param fileName the specified file name jaroslav@1398: * @return a String indicating the MIME jaroslav@1398: * type for the specified file name. jaroslav@1398: */ jaroslav@1398: public String getContentTypeFor(String fileName); jaroslav@1398: }