| // URLConnection.java - Superclass of all communications links between | |
| // an application and a URL. | |
| /* Copyright (C) 1999, 2000 Free Software Foundation | |
| This file is part of libgcj. | |
| This software is copyrighted work licensed under the terms of the | |
| Libgcj License. Please consult the file "LIBGCJ_LICENSE" for | |
| details. */ | |
| package java.net; | |
| import java.io.*; | |
| import java.text.ParsePosition; | |
| import java.text.SimpleDateFormat; | |
| import java.util.Date; | |
| import java.util.Locale; | |
| import java.util.Hashtable; | |
| import java.util.StringTokenizer; | |
| import gnu.gcj.io.MimeTypes; | |
| /** | |
| * @author Warren Levy <warrenl@cygnus.com> | |
| * @date March 5, 1999. | |
| */ | |
| /** | |
| * Written using on-line Java Platform 1.2 API Specification, as well | |
| * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). | |
| * Status: One guessContentTypeFrom... methods not implemented. | |
| * getContent method assumes content type from response; see comment there. | |
| */ | |
| public abstract class URLConnection | |
| { | |
| protected URL url; | |
| protected boolean doInput = true; | |
| protected boolean doOutput = false; | |
| protected boolean allowUserInteraction; | |
| protected boolean useCaches; | |
| protected long ifModifiedSince = 0L; | |
| protected boolean connected = false; | |
| private static boolean defaultAllowUserInteraction = false; | |
| private static boolean defaultUseCaches = true; | |
| private static FileNameMap fileNameMap; // Set by the URLConnection subclass. | |
| private static ContentHandlerFactory factory; | |
| private static ContentHandler contentHandler; | |
| private static Hashtable handlers = new Hashtable(); | |
| private static Locale locale; | |
| private static SimpleDateFormat dateFormat1, dateFormat2, dateFormat3; | |
| private static boolean dateformats_initialized = false; | |
| protected URLConnection(URL url) | |
| { | |
| this.url = url; | |
| allowUserInteraction = defaultAllowUserInteraction; | |
| useCaches = defaultUseCaches; | |
| } | |
| public abstract void connect() throws IOException; | |
| public URL getURL() | |
| { | |
| return url; | |
| } | |
| public int getContentLength() | |
| { | |
| return getHeaderFieldInt("content-length", -1); | |
| } | |
| public String getContentType() | |
| { | |
| return getHeaderField("content-type"); | |
| } | |
| public String getContentEncoding() | |
| { | |
| return getHeaderField("content-encoding"); | |
| } | |
| public long getExpiration() | |
| { | |
| return getHeaderFieldDate("expiration", 0L); | |
| } | |
| public long getDate() | |
| { | |
| return getHeaderFieldDate("date", 0L); | |
| } | |
| public long getLastModified() | |
| { | |
| return getHeaderFieldDate("last-modified", 0L); | |
| } | |
| public String getHeaderField(int n) | |
| { | |
| // Subclasses for specific protocols override this. | |
| return null; | |
| } | |
| public String getHeaderField(String name) | |
| { | |
| // Subclasses for specific protocols override this. | |
| return null; | |
| } | |
| public int getHeaderFieldInt(String name, int val) | |
| { | |
| String str = getHeaderField(name); | |
| try | |
| { | |
| if (str != null) | |
| val = Integer.parseInt(str); | |
| } | |
| catch (NumberFormatException e) | |
| { | |
| ; // Do nothing; val is the default. | |
| } | |
| return val; | |
| } | |
| public long getHeaderFieldDate(String name, long val) | |
| { | |
| if (! dateformats_initialized) | |
| initializeDateFormats(); | |
| String str = getHeaderField(name); | |
| if (str != null) | |
| { | |
| Date date; | |
| if ((date = dateFormat1.parse(str, new ParsePosition(0))) != null) | |
| val = date.getTime(); | |
| else if ((date = dateFormat2.parse(str, new ParsePosition(0))) != null) | |
| val = date.getTime(); | |
| else if ((date = dateFormat3.parse(str, new ParsePosition(0))) != null) | |
| val = date.getTime(); | |
| } | |
| return val; | |
| } | |
| public String getHeaderFieldKey(int n) | |
| { | |
| // Subclasses for specific protocols override this. | |
| return null; | |
| } | |
| public Object getContent() throws IOException | |
| { | |
| // FIXME: Doc indicates that other criteria should be applied as | |
| // heuristics to determine the true content type, e.g. see | |
| // guessContentTypeFromName() and guessContentTypeFromStream methods | |
| // as well as FileNameMap class & fileNameMap field & get/set methods. | |
| String cType = getContentType(); | |
| contentHandler = setContentHandler(cType); | |
| if (contentHandler == null) | |
| return getInputStream(); | |
| return contentHandler.getContent(this); | |
| } | |
| // TODO12: public Permission getPermission() throws IOException | |
| // { | |
| // // Subclasses may override this. | |
| // return java.security.AllPermission; | |
| // } | |
| public InputStream getInputStream() throws IOException | |
| { | |
| // Subclasses for specific protocols override this. | |
| throw new UnknownServiceException("Protocol " + url.getProtocol() + | |
| " does not support input."); | |
| } | |
| public OutputStream getOutputStream() throws IOException | |
| { | |
| // Subclasses for specific protocols override this. | |
| throw new UnknownServiceException("Protocol " + url.getProtocol() + | |
| " does not support output."); | |
| } | |
| public String toString() | |
| { | |
| return this.getClass().getName() + ":" + url.toString(); | |
| } | |
| public void setDoInput(boolean doinput) | |
| { | |
| if (connected) | |
| throw new IllegalAccessError("Already connected"); | |
| doInput = doinput; | |
| } | |
| public boolean getDoInput() | |
| { | |
| return doInput; | |
| } | |
| public void setDoOutput(boolean dooutput) | |
| { | |
| if (connected) | |
| throw new IllegalAccessError("Already connected"); | |
| doOutput = dooutput; | |
| } | |
| public boolean getDoOutput() | |
| { | |
| return doOutput; | |
| } | |
| public void setAllowUserInteraction(boolean allowuserinteraction) | |
| { | |
| if (connected) | |
| throw new IllegalAccessError("Already connected"); | |
| allowUserInteraction = allowuserinteraction; | |
| } | |
| public boolean getAllowUserInteraction() | |
| { | |
| return allowUserInteraction; | |
| } | |
| public static void | |
| setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) | |
| { | |
| defaultAllowUserInteraction = defaultallowuserinteraction; | |
| } | |
| public static boolean getDefaultAllowUserInteraction() | |
| { | |
| return defaultAllowUserInteraction; | |
| } | |
| public void setUseCaches(boolean usecaches) | |
| { | |
| if (connected) | |
| throw new IllegalAccessError("Already connected"); | |
| useCaches = usecaches; | |
| } | |
| public boolean getUseCaches() | |
| { | |
| return useCaches; | |
| } | |
| public void setIfModifiedSince(long ifmodifiedsince) | |
| { | |
| if (connected) | |
| throw new IllegalAccessError("Already connected"); | |
| ifModifiedSince = ifmodifiedsince; | |
| } | |
| public long getIfModifiedSince() | |
| { | |
| return ifModifiedSince; | |
| } | |
| public boolean getDefaultUseCaches() | |
| { | |
| return defaultUseCaches; | |
| } | |
| public void setDefaultUseCaches(boolean defaultusecaches) | |
| { | |
| defaultUseCaches = defaultusecaches; | |
| } | |
| public void setRequestProperty(String key, String value) | |
| { | |
| // Do nothing unless overridden by subclasses that support setting | |
| // header fields in the request. | |
| } | |
| public String getRequestProperty(String key) | |
| { | |
| // Overridden by subclasses that support reading header fields from the | |
| // request. | |
| return null; | |
| } | |
| public static void setDefaultRequestProperty(String key, String value) | |
| { | |
| // Do nothing unless overridden by subclasses that support setting | |
| // default request properties. | |
| } | |
| public static String getDefaultRequestProperty(String key) | |
| { | |
| // Overridden by subclasses that support default request properties. | |
| return null; | |
| } | |
| public static void setContentHandlerFactory(ContentHandlerFactory fac) | |
| { | |
| if (factory != null) | |
| throw new Error("ContentHandlerFactory already set"); | |
| // Throw an exception if an extant security mgr precludes | |
| // setting the factory. | |
| SecurityManager s = System.getSecurityManager(); | |
| if (s != null) | |
| s.checkSetFactory(); | |
| factory = fac; | |
| } | |
| protected static String guessContentTypeFromName(String fname) | |
| { | |
| int dot = fname.lastIndexOf ("."); | |
| if (dot != -1) | |
| { | |
| if (dot == fname.length()) | |
| return ("application/octet-stream"); | |
| else | |
| fname = fname.substring (dot + 1); | |
| } | |
| String type = MimeTypes.getMimeTypeFromExtension (fname); | |
| if (type == null) | |
| return("application/octet-stream"); | |
| return(type); | |
| } | |
| // TODO: public static String guessContentTypeFromStream(InputStream is) | |
| // throws IOException | |
| // { | |
| // } | |
| // TODO12: protected void parseURL(URL u, String spec, int start, int limit) | |
| // JDK1.2 | |
| public static FileNameMap getFileNameMap() | |
| { | |
| return fileNameMap; | |
| } | |
| // JDK1.2 | |
| public static void setFileNameMap(FileNameMap map) | |
| { | |
| // Throw an exception if an extant security mgr precludes | |
| // setting the factory. | |
| SecurityManager s = System.getSecurityManager(); | |
| if (s != null) | |
| s.checkSetFactory(); | |
| fileNameMap = map; | |
| } | |
| private ContentHandler setContentHandler(String contentType) | |
| { | |
| ContentHandler handler; | |
| // No content type so just handle it as the default. | |
| if (contentType == null || contentType == "") | |
| return null; | |
| // See if a handler has been cached for this content type. | |
| // For efficiency, if a content type has been searched for but not | |
| // found, it will be in the hash table but as the contentType String | |
| // instead of a ContentHandler. | |
| if ((handler = (ContentHandler) handlers.get(contentType)) != null) | |
| if (handler instanceof ContentHandler) | |
| return handler; | |
| else | |
| return null; | |
| // If a non-default factory has been set, use it to find the content type. | |
| if (factory != null) | |
| handler = factory.createContentHandler(contentType); | |
| // Non-default factory may have returned null or a factory wasn't set. | |
| // Use the default search algorithm to find a handler for this content type. | |
| if (handler == null) | |
| { | |
| // Get the list of packages to check and append our default handler | |
| // to it, along with the JDK specified default as a last resort. | |
| // Except in very unusual environments the JDK specified one shouldn't | |
| // ever be needed (or available). | |
| String propVal = System.getProperty("java.content.handler.pkgs"); | |
| propVal = (propVal == null) ? "" : (propVal + "|"); | |
| propVal = propVal + "gnu.gcj.content|sun.net.www.content"; | |
| // Replace the '/' character in the content type with '.' and | |
| // all other non-alphabetic, non-numeric characters with '_'. | |
| StringTokenizer pkgPrefix = new StringTokenizer(propVal, "|"); | |
| char[] cArray = contentType.toCharArray(); | |
| for (int i = 0; i < cArray.length; i++) | |
| { | |
| if (cArray[i] == '/') | |
| cArray[i] = '.'; | |
| else if (! ((cArray[i] >= 'A' && cArray[i] <= 'Z') || | |
| (cArray[i] >= 'a' && cArray[i] <= 'z') || | |
| (cArray[i] >= '0' && cArray[i] <= '9'))) | |
| cArray[i] = '_'; | |
| } | |
| String contentClass = new String(cArray); | |
| // See if a class of this content type exists in any of the packages. | |
| do | |
| { | |
| String facName = pkgPrefix.nextToken() + "." + contentClass; | |
| try | |
| { | |
| handler = | |
| (ContentHandler) Class.forName(facName).newInstance(); | |
| } | |
| catch (Exception e) | |
| { | |
| // Can't instantiate; handler still null, go on to next element. | |
| } | |
| } while ((handler == null || | |
| ! (handler instanceof ContentHandler)) && | |
| pkgPrefix.hasMoreTokens()); | |
| } | |
| // Update the hashtable with the new content handler. | |
| if (handler != null && handler instanceof ContentHandler) | |
| { | |
| handlers.put(contentType, handler); | |
| return handler; | |
| } | |
| // For efficiency on subsequent searches, put a dummy entry in the hash | |
| // table for content types that don't have a non-default ContentHandler. | |
| handlers.put(contentType, contentType); | |
| return null; | |
| } | |
| // We don't put these in a static initializer, because it creates problems | |
| // with initializer co-dependency: SimpleDateFormat's constructors eventually | |
| // depend on URLConnection (via the java.text.*Symbols classes). | |
| private synchronized void initializeDateFormats() | |
| { | |
| if (dateformats_initialized) | |
| return; | |
| locale = new Locale("En", "Us", "Unix"); | |
| dateFormat1 = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'", | |
| locale); | |
| dateFormat2 = new SimpleDateFormat("EEEE, dd-MMM-yy hh:mm:ss 'GMT'", | |
| locale); | |
| dateFormat3 = new SimpleDateFormat("EEE MMM d hh:mm:ss yyyy", locale); | |
| dateformats_initialized = true; | |
| } | |
| } |