FSF GCC merge 02/23/03
[official-gcc.git] / libjava / java / net / URLConnection.java
blob0b39fe88ea63b14293d8849b7721aab25e2bad21
1 // URLConnection.java - Superclass of all communications links between
2 // an application and a URL.
4 /* Copyright (C) 1999, 2000 Free Software Foundation
6 This file is part of libgcj.
8 This software is copyrighted work licensed under the terms of the
9 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
10 details. */
12 package java.net;
14 import java.io.*;
15 import java.text.ParsePosition;
16 import java.text.SimpleDateFormat;
17 import java.util.Date;
18 import java.util.Locale;
19 import java.util.Hashtable;
20 import java.util.Map;
21 import java.util.StringTokenizer;
22 import java.security.Permission;
23 import java.security.AllPermission;
24 import gnu.gcj.io.MimeTypes;
26 /**
27 * @author Warren Levy <warrenl@cygnus.com>
28 * @date March 5, 1999.
31 /**
32 * Written using on-line Java Platform 1.2 API Specification, as well
33 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
34 * Status: One guessContentTypeFrom... methods not implemented.
35 * getContent method assumes content type from response; see comment there.
38 public abstract class URLConnection
40 protected URL url;
41 protected boolean doInput = true;
42 protected boolean doOutput = false;
43 protected boolean allowUserInteraction;
44 protected boolean useCaches;
45 protected long ifModifiedSince = 0L;
46 protected boolean connected = false;
47 private static boolean defaultAllowUserInteraction = false;
48 private static boolean defaultUseCaches = true;
49 private static FileNameMap fileNameMap; // Set by the URLConnection subclass.
50 private static ContentHandlerFactory factory;
51 private static ContentHandler contentHandler;
52 private static Hashtable handlers = new Hashtable();
53 private static Locale locale;
54 private static SimpleDateFormat dateFormat1, dateFormat2, dateFormat3;
55 private static boolean dateformats_initialized = false;
57 /**
58 * Creates a URL connection to a given URL. A real connection is not made.
59 * Use #connect to do this.
61 * @param url The Object to create the URL connection to
63 * @see URLConnection:connect
65 protected URLConnection(URL url)
67 this.url = url;
68 allowUserInteraction = defaultAllowUserInteraction;
69 useCaches = defaultUseCaches;
72 /**
73 * Creates a real connection to the object references by the URL given
74 * to the constructor
76 * @exception IOException If an error occurs
78 public abstract void connect() throws IOException;
80 /**
81 * Returns ths URL to the object.
83 public URL getURL()
85 return url;
88 /**
89 * Returns the value of the content-length header field
91 public int getContentLength()
93 return getHeaderFieldInt("content-length", -1);
96 /**
97 * Returns the value of the content-type header field
99 public String getContentType()
101 return getHeaderField("content-type");
105 * Returns the value of the content-encoding header field
107 public String getContentEncoding()
109 return getHeaderField("content-encoding");
113 * Returns the value of the expires header field
115 public long getExpiration()
117 return getHeaderFieldDate("expiration", 0L);
121 * Returns the value of the date header field
123 public long getDate()
125 return getHeaderFieldDate("date", 0L);
129 * Returns the value of the last-modified header field
131 public long getLastModified()
133 return getHeaderFieldDate("last-modified", 0L);
137 * Returns the value of the n-th header field
139 * @param num The number of the header field
141 public String getHeaderField(int num)
143 // Subclasses for specific protocols override this.
144 return null;
148 * Returns the value of the header filed specified by name
150 * @param name The name of the header field
152 public String getHeaderField(String name)
154 // Subclasses for specific protocols override this.
155 return null;
159 * Returns a map of all sent header fields
161 * @since 1.4
163 public Map getHeaderFields()
165 // Subclasses for specific protocols override this.
166 return null;
170 * Returns the value of the header filed name as int.
172 * @param name The name of the header field
173 * @param val The default value
175 * @return Returns the value of the header filed or the default value
176 * if the field is missing or malformed
178 public int getHeaderFieldInt(String name, int val)
180 String str = getHeaderField(name);
183 if (str != null)
184 val = Integer.parseInt(str);
186 catch (NumberFormatException e)
188 ; // Do nothing; val is the default.
190 return val;
194 * Returns the value of a header field parsed as date. The result is then
195 * number of milliseconds since January 1st, 1970 GMT.
197 * @param name The name of the header field
198 * @param val The dafault date
200 * @return Returns the date value of the header filed or the default value
201 * if the field is missing or malformed
203 public long getHeaderFieldDate(String name, long val)
205 if (! dateformats_initialized)
206 initializeDateFormats();
207 String str = getHeaderField(name);
208 if (str != null)
210 Date date;
211 if ((date = dateFormat1.parse(str, new ParsePosition(0))) != null)
212 val = date.getTime();
213 else if ((date = dateFormat2.parse(str, new ParsePosition(0))) != null)
214 val = date.getTime();
215 else if ((date = dateFormat3.parse(str, new ParsePosition(0))) != null)
216 val = date.getTime();
218 return val;
222 * Returns the key of the n-th header field
224 * @param num The number of the header field
226 public String getHeaderFieldKey(int num)
228 // Subclasses for specific protocols override this.
229 return null;
233 * Retrieves the content of this URLConnection
235 * @exception IOException If an error occurs
236 * @exception UnknownServiceException If the protocol does not support the
237 * content type
239 public Object getContent() throws IOException
241 // FIXME: Doc indicates that other criteria should be applied as
242 // heuristics to determine the true content type, e.g. see
243 // guessContentTypeFromName() and guessContentTypeFromStream methods
244 // as well as FileNameMap class & fileNameMap field & get/set methods.
245 String cType = getContentType();
246 contentHandler = setContentHandler(cType);
247 if (contentHandler == null)
248 return getInputStream();
250 return contentHandler.getContent(this);
254 * Retrieves the content of this URLConnection
256 * @exception IOException If an error occurs
257 * @exception UnknownServiceException If the protocol does not support the
258 * content type
260 public Object getContent(Class[] classes) throws IOException
262 // FIXME: implement this
263 return getContent ();
267 * Returns a permission object representing the permission necessary to make
268 * the connection represented by this object. This method returns null if no
269 * permission is required to make the connection.
271 * @exception IOException If the computation of the permission requires
272 * network or file I/O and an exception occurs while computing it
274 public Permission getPermission() throws IOException
276 // Subclasses may override this.
277 return new java.security.AllPermission();
281 * Returns the input stream of the URL connection
283 * @exception IOException If an error occurs
284 * @exception UnknownServiceException If the protocol does not support input
286 public InputStream getInputStream() throws IOException
288 // Subclasses for specific protocols override this.
289 throw new UnknownServiceException("Protocol " + url.getProtocol() +
290 " does not support input.");
294 * Returns the output stream of the URL connection
296 * @exception IOException If an error occurs
297 * @exception UnknownServiceException If the protocol does not support output
299 public OutputStream getOutputStream() throws IOException
301 // Subclasses for specific protocols override this.
302 throw new UnknownServiceException("Protocol " + url.getProtocol() +
303 " does not support output.");
307 * Returns a string representation of the URL connection object
309 public String toString()
311 return this.getClass().getName() + ":" + url.toString();
315 * Sets tha value of the doInput field.
317 * @param doinput The new value of the doInput field
319 * @exception IllegalStateException If already connected
321 public void setDoInput(boolean doinput)
323 if (connected)
324 throw new IllegalStateException ("Already connected");
326 doInput = doinput;
330 * Returns the current value of the doInput field
332 public boolean getDoInput()
334 return doInput;
338 * Sets the value of the doOutput field
340 * @param dooutput The new value of the doOutput field
342 * @exception IllegalStateException If already connected
344 public void setDoOutput(boolean dooutput)
346 if (connected)
347 throw new IllegalStateException ("Already connected");
349 doOutput = dooutput;
353 * Returns the current value of the doOutput field
355 public boolean getDoOutput()
357 return doOutput;
361 * Sets a new value to the allowUserInteraction field
363 * @param allowed The new value
365 * @exception IllegalStateException If already connected
367 public void setAllowUserInteraction(boolean allowed)
369 if (connected)
370 throw new IllegalStateException ("Already connected");
372 allowUserInteraction = allowed;
376 * Returns the current value of the allowUserInteraction field
378 public boolean getAllowUserInteraction()
380 return allowUserInteraction;
384 * Sets the default value if the allowUserInteraction field
386 * @param allowed The new default value
388 public static void setDefaultAllowUserInteraction(boolean allowed)
390 defaultAllowUserInteraction = allowed;
394 * Returns the default value of the allowUserInteraction field
396 public static boolean getDefaultAllowUserInteraction()
398 return defaultAllowUserInteraction;
402 * Sets a new value to the useCaches field
404 * @param usecaches The new value
406 * @exception IllegalStateException If already connected
408 public void setUseCaches(boolean usecaches)
410 if (connected)
411 throw new IllegalStateException ("Already connected");
413 useCaches = usecaches;
417 * The current value of the useCaches field
419 public boolean getUseCaches()
421 return useCaches;
425 * Sets the value of the ifModifiedSince field
427 * @param ifmodifiedsince The new value in milliseconds
428 * since January 1, 1970 GMT
430 * @exception IllegalStateException If already connected
432 public void setIfModifiedSince(long ifmodifiedsince)
434 if (connected)
435 throw new IllegalStateException ("Already connected");
437 ifModifiedSince = ifmodifiedsince;
441 * Returns the current value of the ifModifiedSince field
443 public long getIfModifiedSince()
445 return ifModifiedSince;
449 * Returns the default value of the useCaches field
451 public boolean getDefaultUseCaches()
453 return defaultUseCaches;
457 * Sets the default value of the useCaches field
459 * @param defaultusecaches The new default value
461 public void setDefaultUseCaches(boolean defaultusecaches)
463 defaultUseCaches = defaultusecaches;
467 * Sets a property specified by key to value.
469 * @param key Key of the property to set
470 * @param value Value of the Property to set
472 * @exception IllegalStateException If already connected
473 * @exception NullPointerException If key is null
475 * @see URLConnection:getRequestProperty(String key)
476 * @see URLConnection:addRequestProperty(String key, String value)
478 public void setRequestProperty(String key, String value)
480 if (connected)
481 throw new IllegalStateException ("Already connected");
483 // Do nothing unless overridden by subclasses that support setting
484 // header fields in the request.
488 * Sets a property specified by key to value. If the property key already
489 * is assigned to a value it does nothing.
491 * @param key Key of the property to add
492 * @param value Value of the Property to add
494 * @exception IllegalStateException If already connected
495 * @exception NullPointerException If key is null
497 * @see URLConnection:getRequestProperty(String key)
498 * @see URLConnection:setRequestProperty(String key, String value)
500 * @since 1.4
502 public void addRequestProperty(String key, String value)
504 if (connected)
505 throw new IllegalStateException ("Already connected");
507 if (getRequestProperty (key) == null)
509 setRequestProperty (key, value);
514 * Returns a property value specified by key.
516 * @param key Key of the property to return
518 * @exception IllegalStateException If already connected
520 * @see URLConnection:setRequestProperty(String key, String value)
521 * @see URLConnection:addRequestProperty(String key, String value)
523 * @return Value of the property.
525 public String getRequestProperty(String key)
527 if (connected)
528 throw new IllegalStateException ("Already connected");
530 // Overridden by subclasses that support reading header fields from the
531 // request.
532 return null;
536 * Returns a map that contains all properties of the request
538 * @exception IllegalStateException If already connected
540 * @return The map of properties
542 public Map getRequestProperties()
544 // Overridden by subclasses that support reading header fields from the
545 // request.
546 return null;
550 * Defines a default request property
552 * @param key The key of the property
553 * @param value The value of the property
555 * @deprecated 1.3 The method setRequestProperty should be used instead
557 * @see URLConnection:setRequestProperty
559 public static void setDefaultRequestProperty(String key, String value)
561 // Do nothing unless overridden by subclasses that support setting
562 // default request properties.
566 * Returns the value of a default request property
568 * @param key The key of the default property
570 * @return The value of the default property or null if not available
572 * @deprecated 1.3 The method getRequestProperty should be used instead
574 * @see URLConnection:getRequestProperty
576 public static String getDefaultRequestProperty(String key)
578 // Overridden by subclasses that support default request properties.
579 return null;
583 * Sets a ContentHandlerFactory
585 * @param fac The ContentHandlerFactory
587 * @exception Error If the factory has already been defined
588 * @exception SecurityException If a security manager exists and its
589 * checkSetFactory method doesn't allow the operation
591 public static void setContentHandlerFactory(ContentHandlerFactory fac)
593 if (factory != null)
594 throw new Error("ContentHandlerFactory already set");
596 // Throw an exception if an extant security mgr precludes
597 // setting the factory.
598 SecurityManager s = System.getSecurityManager();
599 if (s != null)
600 s.checkSetFactory();
601 factory = fac;
605 * Tries to determine the content type of an object, based on the
606 * specified file name
608 * @param fname The filename to guess the content type from
610 * @specnote public since JDK 1.4
612 public static String guessContentTypeFromName(String fname)
614 int dot = fname.lastIndexOf (".");
616 if (dot != -1)
618 if (dot == fname.length())
619 return ("application/octet-stream");
620 else
621 fname = fname.substring (dot + 1);
624 String type = MimeTypes.getMimeTypeFromExtension (fname);
626 if (type == null)
627 return("application/octet-stream");
629 return(type);
633 * Tries to guess the content type of an object, based on the characters
634 * at the beginning of then input stream
636 * @param is The input stream to guess from
638 * @exception IOException If an error occurs
640 public static String guessContentTypeFromStream(InputStream is)
641 throws IOException
643 is.mark(1024);
644 // FIXME: Implement this. Use system mimetype informations (like "file").
645 is.reset();
646 return null;
650 * Returns a filename map (a mimetable)
652 * @since 1.2
654 public static FileNameMap getFileNameMap()
656 return fileNameMap;
660 * Sets a FileNameMap
662 * @param map The new FileNameMap
664 * @exception SecurityException If a security manager exists and its
665 * checkSetFactory method doesn't allow the operation
667 * @since 1.2
669 public static void setFileNameMap(FileNameMap map)
671 // Throw an exception if an extant security mgr precludes
672 // setting the factory.
673 SecurityManager s = System.getSecurityManager();
674 if (s != null)
675 s.checkSetFactory();
677 fileNameMap = map;
680 private ContentHandler setContentHandler(String contentType)
682 ContentHandler handler;
684 // No content type so just handle it as the default.
685 if (contentType == null || contentType == "")
686 return null;
688 // See if a handler has been cached for this content type.
689 // For efficiency, if a content type has been searched for but not
690 // found, it will be in the hash table but as the contentType String
691 // instead of a ContentHandler.
692 if ((handler = (ContentHandler) handlers.get(contentType)) != null)
693 if (handler instanceof ContentHandler)
694 return handler;
695 else
696 return null;
698 // If a non-default factory has been set, use it to find the content type.
699 if (factory != null)
700 handler = factory.createContentHandler(contentType);
702 // Non-default factory may have returned null or a factory wasn't set.
703 // Use the default search algorithm to find a handler for this content type.
704 if (handler == null)
706 // Get the list of packages to check and append our default handler
707 // to it, along with the JDK specified default as a last resort.
708 // Except in very unusual environments the JDK specified one shouldn't
709 // ever be needed (or available).
710 String propVal = System.getProperty("java.content.handler.pkgs");
711 propVal = (propVal == null) ? "" : (propVal + "|");
712 propVal = propVal + "gnu.gcj.content|sun.net.www.content";
714 // Replace the '/' character in the content type with '.' and
715 // all other non-alphabetic, non-numeric characters with '_'.
716 StringTokenizer pkgPrefix = new StringTokenizer(propVal, "|");
717 char[] cArray = contentType.toCharArray();
718 for (int i = 0; i < cArray.length; i++)
720 if (cArray[i] == '/')
721 cArray[i] = '.';
722 else if (! ((cArray[i] >= 'A' && cArray[i] <= 'Z') ||
723 (cArray[i] >= 'a' && cArray[i] <= 'z') ||
724 (cArray[i] >= '0' && cArray[i] <= '9')))
725 cArray[i] = '_';
727 String contentClass = new String(cArray);
729 // See if a class of this content type exists in any of the packages.
732 String facName = pkgPrefix.nextToken() + "." + contentClass;
735 handler =
736 (ContentHandler) Class.forName(facName).newInstance();
738 catch (Exception e)
740 // Can't instantiate; handler still null, go on to next element.
742 } while ((handler == null ||
743 ! (handler instanceof ContentHandler)) &&
744 pkgPrefix.hasMoreTokens());
747 // Update the hashtable with the new content handler.
748 if (handler != null && handler instanceof ContentHandler)
750 handlers.put(contentType, handler);
751 return handler;
754 // For efficiency on subsequent searches, put a dummy entry in the hash
755 // table for content types that don't have a non-default ContentHandler.
756 handlers.put(contentType, contentType);
757 return null;
760 // We don't put these in a static initializer, because it creates problems
761 // with initializer co-dependency: SimpleDateFormat's constructors eventually
762 // depend on URLConnection (via the java.text.*Symbols classes).
763 private synchronized void initializeDateFormats()
765 if (dateformats_initialized)
766 return;
767 locale = new Locale("En", "Us", "Unix");
768 dateFormat1 = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'",
769 locale);
770 dateFormat2 = new SimpleDateFormat("EEEE, dd-MMM-yy hh:mm:ss 'GMT'",
771 locale);
772 dateFormat3 = new SimpleDateFormat("EEE MMM d hh:mm:ss yyyy", locale);
773 dateformats_initialized = true;