1 /* URLConnection.java -- Abstract superclass for reading from URL's
2 Copyright (C) 1998, 2002, 2003 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import java.io.InputStream;
42 import java.io.IOException;
43 import java.io.OutputStream;
44 import java.security.Permission;
45 import java.security.AllPermission;
46 import java.text.ParsePosition;
47 import java.text.SimpleDateFormat;
48 import java.util.Collections;
49 import java.util.Date;
50 import java.util.Hashtable;
51 import java.util.Locale;
53 import java.util.StringTokenizer;
54 import gnu.gcj.io.MimeTypes;
57 * Written using on-line Java Platform 1.2 API Specification, as well
58 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
59 * Status: One guessContentTypeFrom... methods not implemented.
60 * getContent method assumes content type from response; see comment there.
64 * This class models a connection that retrieves the information pointed
65 * to by a URL object. This is typically a connection to a remote node
66 * on the network, but could be a simple disk read.
68 * A URLConnection object is normally created by calling the openConnection()
69 * method of a URL object. This method is somewhat misnamed because it does
70 * not actually open the connection. Instead, it return an unconnected
71 * instance of this object. The caller then has the opportunity to set
72 * various connection options prior to calling the actual connect() method.
74 * After the connection has been opened, there are a number of methods in
75 * this class that access various attributes of the data, typically
76 * represented by headers sent in advance of the actual data itself.
78 * Also of note are the getInputStream and getContent() methods which allow
79 * the caller to retrieve the actual data from the connection. Note that
80 * for some types of connections, writing is also allowed. The setDoOutput()
81 * method must be called prior to connecing in order to enable this, then
82 * the getOutputStream method called after the connection in order to
83 * obtain a stream to write the output to.
85 * The getContent() method is of particular note. This method returns an
86 * Object that encapsulates the data returned. There is no way do determine
87 * the type of object that will be returned in advance. This is determined
88 * by the actual content handlers as described in the description of that
91 * @author Aaron M. Renn <arenn@urbanophile.com>
92 * @author Warren Levy <warrenl@cygnus.com>
94 public abstract class URLConnection
97 * This is an object that maps filenames to MIME types. The interface
98 * to do this is implemented by this class, so just create an empty
99 * instance and store it here.
101 private static FileNameMap fileNameMap;
104 * This is the ContentHandlerFactory set by the caller, if any
106 private static ContentHandlerFactory factory;
109 * This is the default value that will be used to determine whether or
110 * not user interaction should be allowed.
112 private static boolean defaultAllowUserInteraction = false;
115 * This is the default flag indicating whether or not to use caches to
116 * store the data returned from a server
118 private static boolean defaultUseCaches = true;
121 * This variable determines whether or not interaction is allowed with
122 * the user. For example, to prompt for a username and password.
124 protected boolean allowUserInteraction;
127 * Indicates whether or not a connection has been established to the
128 * destination specified in the URL
130 protected boolean connected = false;
133 * Indicates whether or not input can be read from this URL
135 protected boolean doInput = true;
138 * Indicates whether or not output can be sent to this URL
140 protected boolean doOutput = false;
143 * If this flag is set, the protocol is allowed to cache data whenever
144 * it can (caching is not guaranteed). If it is not set, the protocol
145 * must a get a fresh copy of the data.
147 * This field is set by the setUseCaches method and returned by the
148 * getUseCaches method.
150 * Its default value is that determined by the last invocation of
151 * setDefaultUseCaches
153 protected boolean useCaches;
156 * If this value is non-zero, then the connection will only attempt to
157 * fetch the document pointed to by the URL if the document has been
158 * modified more recently than the date set in this variable. That date
159 * should be specified as the number of seconds since 1/1/1970 GMT.
161 protected long ifModifiedSince = 0L;
164 * This is the URL associated with this connection
168 private static ContentHandler contentHandler;
169 private static Hashtable handlers = new Hashtable();
170 private static Locale locale;
171 private static SimpleDateFormat dateFormat1, dateFormat2, dateFormat3;
172 private static boolean dateformats_initialized = false;
175 * Creates a URL connection to a given URL. A real connection is not made.
176 * Use #connect to do this.
178 * @param url The Object to create the URL connection to
180 * @see URLConnection#connect()
182 protected URLConnection(URL url)
184 // Set up all our instance variables
186 allowUserInteraction = defaultAllowUserInteraction;
187 useCaches = defaultUseCaches;
191 * Establishes the actual connection to the URL associated with this
194 public abstract void connect() throws IOException;
197 * Returns the URL object associated with this connection
199 * @return The URL for this connection.
207 * Returns the value of the content-length header field or -1 if the value
208 * is not known or not present.
210 * @return The content-length field
212 public int getContentLength()
214 return getHeaderFieldInt("content-length", -1);
218 * Returns the the content-type of the data pointed to by the URL. This
219 * method first tries looking for a content-type header. If that is not
220 * present, it attempts to use the file name to determine the content's
221 * MIME type. If that is unsuccessful, the method returns null. The caller
222 * may then still attempt to determine the MIME type by a call to
223 * guessContentTypeFromStream()
225 * @return The content MIME type
227 public String getContentType()
229 return getHeaderField("content-type");
233 * Returns the value of the content-encoding field or null if it is not
234 * known or not present.
236 * @return The content-encoding field
238 public String getContentEncoding()
240 return getHeaderField("content-encoding");
244 * Returns the value of the expires header or 0 if not known or present.
245 * If populated, the return value is number of seconds since midnight
248 * @return The expiration time.
250 public long getExpiration()
252 return getHeaderFieldDate("expires", 0L);
256 * Returns the date of the document pointed to by the URL as reported in
257 * the date field of the header or 0 if the value is not present or not
258 * known. If populated, the return value is number of seconds since
259 * midnight on 1/1/1970 GMT.
261 * @return The document date
263 public long getDate()
265 return getHeaderFieldDate("date", 0L);
269 * Returns the value of the last-modified header field or 0 if not known known
270 * or not present. If populated, the return value is the number of seconds
271 * since midnight on 1/1/1970.
273 * @return The last modified time
275 public long getLastModified()
277 return getHeaderFieldDate("last-modified", 0L);
281 * Return a String representing the header value at the specified index.
282 * This allows the caller to walk the list of header fields. The analogous
283 * getHeaderFieldKey(int) method allows access to the corresponding key
284 * for this header field
286 * @param index The index into the header field list to retrieve the value for
288 * @return The header value or null if index is past the end of the headers
290 public String getHeaderField(int index)
292 // Subclasses for specific protocols override this.
297 * Returns a String representing the value of the header field having
298 * the named key. Returns null if the header field does not exist.
300 * @param The key of the header field
302 * @return The value of the header field as a String
304 public String getHeaderField(String name)
306 // Subclasses for specific protocols override this.
311 * Returns a map of all sent header fields
315 public Map getHeaderFields()
317 // Subclasses for specific protocols override this.
322 * Returns the value of the named header field as an int. If the field
323 * is not present or cannot be parsed as an integer, the default value
326 * @param name The header field key to lookup
327 * @param defaultValue The defaule value if the header field is not found
328 * or can't be parsed.
330 * @return The value of the header field or the default value if the field
331 * is missing or malformed
333 public int getHeaderFieldInt(String name, int defaultValue)
335 String value = getHeaderField (name);
342 return Integer.parseInt (value);
344 catch (NumberFormatException e)
351 * Returns the value of the named header field as a date. This date will
352 * be the number of seconds since midnight 1/1/1970 GMT or the default
353 * value if the field is not present or cannot be converted to a date.
355 * @param name The name of the header field
356 * @param defaultValue The default date if the header field is not found
357 * or can't be converted.
359 * @return Returns the date value of the header filed or the default value
360 * if the field is missing or malformed
362 public long getHeaderFieldDate (String name, long defaultValue)
364 if (! dateformats_initialized)
365 initializeDateFormats ();
367 long result = defaultValue;
368 String str = getHeaderField (name);
373 if ((date = dateFormat1.parse (str, new ParsePosition (0))) != null)
374 result = date.getTime ();
375 else if ((date = dateFormat2.parse (str, new ParsePosition (0))) != null)
376 result = date.getTime ();
377 else if ((date = dateFormat3.parse (str, new ParsePosition (0))) != null)
378 result = date.getTime ();
385 * Returns a String representing the header key at the specified index.
386 * This allows the caller to walk the list of header fields. The analogous
387 * getHeaderField(int) method allows access to the corresponding value for
390 * @param index The index into the header field list to retrieve the key for.
392 * @return The header field key or null if index is past the end
395 public String getHeaderFieldKey (int index)
397 // Subclasses for specific protocols override this.
402 * This method returns the content of the document pointed to by the URL
403 * as an Object. The type of object depends on the MIME type of the
404 * object and particular content hander loaded. Most text type content
405 * handlers will return a subclass of InputStream. Images usually return
406 * a class that implements ImageProducer. There is not guarantee what
407 * type of object will be returned, however.
409 * This class first determines the MIME type of the content, then creates
410 * a ContentHandler object to process the input. If the ContentHandlerFactory
411 * is set, then that object is called to load a content handler, otherwise
412 * a class called gnu.java.net.content.<content_type> is tried.
413 * The default class will also be used if the content handler factory returns
414 * a null content handler.
416 * @exception IOException If an error occurs
417 * @exception UnknownServiceException If the protocol does not support the
420 public Object getContent() throws IOException
422 // FIXME: Doc indicates that other criteria should be applied as
423 // heuristics to determine the true content type, e.g. see
424 // guessContentTypeFromName() and guessContentTypeFromStream methods
425 // as well as FileNameMap class & fileNameMap field & get/set methods.
426 String cType = getContentType();
427 contentHandler = setContentHandler(cType);
428 if (contentHandler == null)
429 return getInputStream();
431 return contentHandler.getContent(this);
435 * Retrieves the content of this URLConnection
437 * @exception IOException If an error occurs
438 * @exception UnknownServiceException If the protocol does not support the
441 public Object getContent(Class[] classes) throws IOException
443 // FIXME: implement this
444 return getContent ();
448 * This method returns a <code>Permission</code> object representing the
449 * permissions required to access this URL. This method returns
450 * <code>java.security.AllPermission</code> by default. Subclasses should
451 * override it to return a more specific permission. For example, an
452 * HTTP URL should return an instance of <code>SocketPermission</code>
453 * for the appropriate host and port.
455 * Note that because of items such as HTTP redirects, the permission
456 * object returned might be different before and after connecting.
458 * @return A Permission object
460 * @exception IOException If the computation of the permission requires
461 * network or file I/O and an exception occurs while computing it
463 public Permission getPermission() throws IOException
465 // Subclasses may override this.
466 return new java.security.AllPermission();
470 * Returns an InputStream for this connection. As this default
471 * implementation returns null, subclasses should override this method
473 * @return An InputStream for this connection
475 * @exception IOException If an error occurs
476 * @exception UnknownServiceException If the protocol does not support input
478 public InputStream getInputStream() throws IOException
480 // Subclasses for specific protocols override this.
481 throw new UnknownServiceException("Protocol " + url.getProtocol() +
482 " does not support input.");
486 * Returns an OutputStream for this connection. As this default
487 * implementation returns null, subclasses should override this method
489 * @return An OutputStream for this connection
491 * @exception IOException If an error occurs
492 * @exception UnknownServiceException If the protocol does not support output
494 public OutputStream getOutputStream() throws IOException
496 // Subclasses for specific protocols override this.
497 throw new UnknownServiceException("Protocol " + url.getProtocol() +
498 " does not support output.");
502 * The methods prints the value of this object as a String by calling the
503 * toString() method of its associated URL. Overrides Object.toString()
505 * @return A String representation of this object
507 public String toString()
509 return this.getClass().getName() + ":" + url.toString();
513 * Returns the value of a flag indicating whether or not input is going
514 * to be done for this connection. This default to true unless the
515 * doOutput flag is set to false, in which case this defaults to false.
517 * @param input <code>true</code> if input is to be done,
518 * <code>false</code> otherwise
520 * @exception IllegalStateException If already connected
522 public void setDoInput(boolean input)
525 throw new IllegalStateException ("Already connected");
531 * Returns the value of a flag indicating whether or not input is going
532 * to be done for this connection. This default to true unless the
533 * doOutput flag is set to false, in which case this defaults to false.
535 * @return true if input is to be done, false otherwise
537 public boolean getDoInput()
543 * Returns a boolean flag indicating whether or not output will be done
544 * on this connection. The default value is false, so this method can
545 * be used to override the default
547 * @param output ture if output is to be done, false otherwise
549 * @exception IllegalStateException If already connected
551 public void setDoOutput(boolean output)
554 throw new IllegalStateException ("Already connected");
560 * Returns a boolean flag indicating whether or not output will be done
561 * on this connection. This defaults to false.
563 * @return true if output is to be done, false otherwise
565 public boolean getDoOutput()
571 * Sets a boolean flag indicating whether or not user interaction is
572 * allowed for this connection. (For example, in order to prompt for
573 * username and password info.
575 * @param allow true if user interaction should be allowed, false otherwise.
577 * @exception IllegalStateException If already connected
579 public void setAllowUserInteraction(boolean allow)
581 allowUserInteraction = allow;
585 * Returns a boolean flag indicating whether or not user interaction is
586 * allowed for this connection. (For example, in order to prompt for
587 * username and password info.
589 * @return true if user interaction is allowed, false otherwise
591 public boolean getAllowUserInteraction()
593 return allowUserInteraction;
597 * Sets the default flag for whether or not interaction with a user
598 * is allowed. This will be used for all connections unless overridden
600 * @param allow true to allow user interaction, false otherwise
602 public static void setDefaultAllowUserInteraction(boolean allow)
604 defaultAllowUserInteraction = allow;
608 * Returns the default flag for whether or not interaction with a user
609 * is allowed. This will be used for all connections unless overridden
611 * @return true if user interaction is allowed, false otherwise
613 public static boolean getDefaultAllowUserInteraction()
615 return defaultAllowUserInteraction;
619 * Sets a boolean flag indicating whether or not caching will be used
620 * (if possible) to store data downloaded via the connection.
622 * @param usecaches The new value
624 * @exception IllegalStateException If already connected
626 public void setUseCaches(boolean usecaches)
629 throw new IllegalStateException ("Already connected");
631 useCaches = usecaches;
635 * Returns a boolean flag indicating whether or not caching will be used
636 * (if possible) to store data downloaded via the connection.
638 * @return true if caching should be used if possible, false otherwise
640 public boolean getUseCaches()
646 * Sets the ifModified since instance variable. If this value is non
647 * zero and the underlying protocol supports it, the actual document will
648 * not be fetched unless it has been modified since this time. The value
649 * passed should be 0 if this feature is to be disabled or the time expressed
650 * as the number of seconds since midnight 1/1/1970 GMT otherwise.
652 * @param ifmodifiedsince The new value in milliseconds
653 * since January 1, 1970 GMT
655 * @exception IllegalStateException If already connected
657 public void setIfModifiedSince(long ifmodifiedsince)
660 throw new IllegalStateException ("Already connected");
662 ifModifiedSince = ifmodifiedsince;
666 * Returns the ifModified since instance variable. If this value is non
667 * zero and the underlying protocol supports it, the actual document will
668 * not be fetched unless it has been modified since this time. The value
669 * returned will be 0 if this feature is disabled or the time expressed
670 * as the number of seconds since midnight 1/1/1970 GMT otherwise
672 * @return The ifModifiedSince value
674 public long getIfModifiedSince()
676 return ifModifiedSince;
680 * Returns the default value used to determine whether or not caching
681 * of documents will be done when possible.
683 * @return true if caches will be used, false otherwise
685 public boolean getDefaultUseCaches()
687 return defaultUseCaches;
691 * Sets the default value used to determine whether or not caching
692 * of documents will be done when possible.
694 * @param use true to use caches if possible by default, false otherwise
696 public void setDefaultUseCaches(boolean defaultusecaches)
698 defaultUseCaches = defaultusecaches;
702 * Sets the value of the named request property
704 * @param key The name of the property
705 * @param value The value of the property
707 * @exception IllegalStateException If already connected
708 * @exception NullPointerException If key is null
710 * @see URLConnection#getRequestProperty(String key)
711 * @see URLConnection#addRequestProperty(String key, String value)
715 public void setRequestProperty(String key, String value)
718 throw new IllegalStateException ("Already connected");
721 throw new NullPointerException ("key is null");
723 // Do nothing unless overridden by subclasses that support setting
724 // header fields in the request.
728 * Adds a new request property by a key/value pair.
729 * This method does not overwrite* existing properties with the same key.
731 * @param key Key of the property to add
732 * @param value Value of the Property to add
734 * @exception IllegalStateException If already connected
735 * @exception NullPointerException If key is null
737 * @see URLConnection#getRequestProperty(String key)
738 * @see URLConnection#setRequestProperty(String key, String value)
742 public void addRequestProperty(String key, String value)
745 throw new IllegalStateException ("Already connected");
748 throw new NullPointerException ("key is null");
750 // Do nothing unless overridden by subclasses that support adding
751 // header fields in the request.
755 * Returns the value of the named request property.
757 * @param key The name of the property
759 * @return Value of the property
761 * @exception IllegalStateException If already connected
763 * @see URLConnection#setRequestProperty(String key, String value)
764 * @see URLConnection#addRequestProperty(String key, String value)
766 public String getRequestProperty(String key)
769 throw new IllegalStateException ("Already connected");
771 // Overridden by subclasses that support reading header fields from the
777 * Returns an unmodifiable Map containing the request properties.
779 * @return The map of properties
781 * @exception IllegalStateException If already connected
785 public Map getRequestProperties()
788 throw new IllegalStateException ("Already connected");
790 // Overridden by subclasses that support reading header fields from the
792 return Collections.EMPTY_MAP;
796 * Sets the default value of a request property. This will be used
797 * for all connections unless the value of the property is manually
800 * @param key The request property name the default is being set for
801 * @param value The value to set the default to
803 * @deprecated 1.3 The method setRequestProperty should be used instead
805 * @see URLConnectionr#setRequestProperty(String key, String value)
807 public static void setDefaultRequestProperty(String key, String value)
809 // Do nothing unless overridden by subclasses that support setting
810 // default request properties.
814 * Returns the default value of a request property. This will be used
815 * for all connections unless the value of the property is manually
818 * @param key The request property to return the default value of
820 * @return The value of the default property or null if not available
822 * @deprecated 1.3 The method getRequestProperty should be used instead
824 * @see URLConnection#getRequestProperty(String key)
826 public static String getDefaultRequestProperty(String key)
828 // Overridden by subclasses that support default request properties.
833 * Set's the ContentHandlerFactory for an application. This can be called
834 * once and only once. If it is called again, then an Error is thrown.
835 * Unlike for other set factory methods, this one does not do a security
836 * check prior to setting the factory.
838 * @param factory The ContentHandlerFactory for this application
840 * @exception Error If the factory has already been defined
841 * @exception SecurityException If a security manager exists and its
842 * checkSetFactory method doesn't allow the operation
844 public static synchronized void setContentHandlerFactory
845 (ContentHandlerFactory fac)
848 throw new Error("ContentHandlerFactory already set");
850 // Throw an exception if an extant security mgr precludes
851 // setting the factory.
852 SecurityManager s = System.getSecurityManager();
860 * Returns the MIME type of a file based on the name of the file. This
861 * works by searching for the file's extension in a list of file extensions
862 * and returning the MIME type associated with it. If no type is found,
863 * then a MIME type of "application/octet-stream" will be returned.
865 * @param filename The filename to determine the MIME type for
867 * @return The MIME type String
869 * @specnote public since JDK 1.4
871 public static String guessContentTypeFromName(String filename)
873 int dot = filename.lastIndexOf (".");
877 if (dot == filename.length())
878 return ("application/octet-stream");
880 filename = filename.substring (dot + 1);
883 String type = MimeTypes.getMimeTypeFromExtension (filename);
886 return("application/octet-stream");
892 * Returns the MIME type of a stream based on the first few characters
893 * at the beginning of the stream. This routine can be used to determine
894 * the MIME type if a server is believed to be returning an incorrect
895 * MIME type. This method returns "application/octet-stream" if it
896 * cannot determine the MIME type.
898 * NOTE: Overriding MIME types sent from the server can be obnoxious
899 * to user's. See Internet Exploder 4 if you don't believe me.
901 * @param is The InputStream to determine the MIME type from
903 * @return The MIME type
905 * @exception IOException If an error occurs
907 public static String guessContentTypeFromStream(InputStream is)
911 // FIXME: Implement this. Use system mimetype informations (like "file").
917 * This method returns the <code>FileNameMap</code> object being used
918 * to decode MIME types by file extension.
920 * @return The <code>FileNameMap</code>.
924 public static FileNameMap getFileNameMap()
930 * This method set the <code>FileNameMap</code> object being used
931 * to decode MIME types by file extension.
933 * @param map The <code>FileNameMap</code>.
935 * @exception SecurityException If a security manager exists and its
936 * checkSetFactory method doesn't allow the operation
940 public static void setFileNameMap(FileNameMap map)
942 // Throw an exception if an extant security mgr precludes
943 // setting the factory.
944 SecurityManager s = System.getSecurityManager();
951 private ContentHandler setContentHandler(String contentType)
953 ContentHandler handler;
955 // No content type so just handle it as the default.
956 if (contentType == null || contentType == "")
959 // See if a handler has been cached for this content type.
960 // For efficiency, if a content type has been searched for but not
961 // found, it will be in the hash table but as the contentType String
962 // instead of a ContentHandler.
963 if ((handler = (ContentHandler) handlers.get(contentType)) != null)
964 if (handler instanceof ContentHandler)
969 // If a non-default factory has been set, use it to find the content type.
971 handler = factory.createContentHandler(contentType);
973 // Non-default factory may have returned null or a factory wasn't set.
974 // Use the default search algorithm to find a handler for this content type.
977 // Get the list of packages to check and append our default handler
978 // to it, along with the JDK specified default as a last resort.
979 // Except in very unusual environments the JDK specified one shouldn't
980 // ever be needed (or available).
981 String propVal = System.getProperty("java.content.handler.pkgs");
982 propVal = (propVal == null) ? "" : (propVal + "|");
983 propVal = propVal + "gnu.gcj.content|sun.net.www.content";
985 // Replace the '/' character in the content type with '.' and
986 // all other non-alphabetic, non-numeric characters with '_'.
987 StringTokenizer pkgPrefix = new StringTokenizer(propVal, "|");
988 char[] cArray = contentType.toCharArray();
989 for (int i = 0; i < cArray.length; i++)
991 if (cArray[i] == '/')
993 else if (! ((cArray[i] >= 'A' && cArray[i] <= 'Z') ||
994 (cArray[i] >= 'a' && cArray[i] <= 'z') ||
995 (cArray[i] >= '0' && cArray[i] <= '9')))
998 String contentClass = new String(cArray);
1000 // See if a class of this content type exists in any of the packages.
1003 String facName = pkgPrefix.nextToken() + "." + contentClass;
1007 (ContentHandler) Class.forName(facName).newInstance();
1011 // Can't instantiate; handler still null, go on to next element.
1013 } while ((handler == null ||
1014 ! (handler instanceof ContentHandler)) &&
1015 pkgPrefix.hasMoreTokens());
1018 // Update the hashtable with the new content handler.
1019 if (handler != null && handler instanceof ContentHandler)
1021 handlers.put(contentType, handler);
1025 // For efficiency on subsequent searches, put a dummy entry in the hash
1026 // table for content types that don't have a non-default ContentHandler.
1027 handlers.put(contentType, contentType);
1031 // We don't put these in a static initializer, because it creates problems
1032 // with initializer co-dependency: SimpleDateFormat's constructors eventually
1033 // depend on URLConnection (via the java.text.*Symbols classes).
1034 private synchronized void initializeDateFormats()
1036 if (dateformats_initialized)
1038 locale = new Locale("En", "Us", "Unix");
1039 dateFormat1 = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'",
1041 dateFormat2 = new SimpleDateFormat("EEEE, dd-MMM-yy hh:mm:ss 'GMT'",
1043 dateFormat3 = new SimpleDateFormat("EEE MMM d hh:mm:ss yyyy", locale);
1044 dateformats_initialized = true;
1046 } // class URLConnection