1 // URLConnection.java - Superclass of all communications links between
2 // an application and a URL.
4 /* Copyright (C) 1999 Red Hat, Inc.
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
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
.StringTokenizer
;
21 import gnu
.gcj
.io
.MimeTypes
;
24 * @author Warren Levy <warrenl@cygnus.com>
25 * @date March 5, 1999.
29 * Written using on-line Java Platform 1.2 API Specification, as well
30 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
31 * Status: One guessContentTypeFrom... methods not implemented.
32 * getContent method assumes content type from response; see comment there.
35 public abstract class URLConnection
38 protected boolean doInput
= true;
39 protected boolean doOutput
= false;
40 protected boolean allowUserInteraction
;
41 protected boolean useCaches
;
42 protected long ifModifiedSince
= 0L;
43 protected boolean connected
= false;
44 private static boolean defaultAllowUserInteraction
= false;
45 private static boolean defaultUseCaches
= true;
46 private static FileNameMap fileNameMap
; // Set by the URLConnection subclass.
47 private static ContentHandlerFactory factory
;
48 private static ContentHandler contentHandler
;
49 private static Hashtable handlers
= new Hashtable();
50 private static Locale locale
;
51 private static SimpleDateFormat dateFormat1
, dateFormat2
, dateFormat3
;
52 private static boolean dateformats_initialized
= false;
54 protected URLConnection(URL url
)
57 allowUserInteraction
= defaultAllowUserInteraction
;
58 useCaches
= defaultUseCaches
;
61 public abstract void connect() throws IOException
;
68 public int getContentLength()
70 return getHeaderFieldInt("content-length", -1);
73 public String
getContentType()
75 return getHeaderField("content-type");
78 public String
getContentEncoding()
80 return getHeaderField("content-encoding");
83 public long getExpiration()
85 return getHeaderFieldDate("expiration", 0L);
90 return getHeaderFieldDate("date", 0L);
93 public long getLastModified()
95 return getHeaderFieldDate("last-modified", 0L);
98 public String
getHeaderField(int n
)
100 // Subclasses for specific protocols override this.
104 public String
getHeaderField(String name
)
106 // Subclasses for specific protocols override this.
110 public int getHeaderFieldInt(String name
, int val
)
112 String str
= getHeaderField(name
);
116 val
= Integer
.parseInt(str
);
118 catch (NumberFormatException e
)
120 ; // Do nothing; val is the default.
125 public long getHeaderFieldDate(String name
, long val
)
127 if (! dateformats_initialized
)
128 initializeDateFormats();
129 String str
= getHeaderField(name
);
133 if ((date
= dateFormat1
.parse(str
, new ParsePosition(0))) != null)
134 val
= date
.getTime();
135 else if ((date
= dateFormat2
.parse(str
, new ParsePosition(0))) != null)
136 val
= date
.getTime();
137 else if ((date
= dateFormat3
.parse(str
, new ParsePosition(0))) != null)
138 val
= date
.getTime();
143 public String
getHeaderFieldKey(int n
)
145 // Subclasses for specific protocols override this.
149 public Object
getContent() throws IOException
151 // FIXME: Doc indicates that other criteria should be applied as
152 // heuristics to determine the true content type, e.g. see
153 // guessContentTypeFromName() and guessContentTypeFromStream methods
154 // as well as FileNameMap class & fileNameMap field & get/set methods.
155 String cType
= getContentType();
156 contentHandler
= setContentHandler(cType
);
157 if (contentHandler
== null)
158 return getInputStream();
160 return contentHandler
.getContent(this);
163 // TODO12: public Permission getPermission() throws IOException
165 // // Subclasses may override this.
166 // return java.security.AllPermission;
169 public InputStream
getInputStream() throws IOException
171 // Subclasses for specific protocols override this.
172 throw new UnknownServiceException("Protocol " + url
.getProtocol() +
173 " does not support input.");
176 public OutputStream
getOutputStream() throws IOException
178 // Subclasses for specific protocols override this.
179 throw new UnknownServiceException("Protocol " + url
.getProtocol() +
180 " does not support output.");
183 public String
toString()
185 return this.getClass().getName() + ":" + url
.toString();
188 public void setDoInput(boolean doinput
)
191 throw new IllegalAccessError("Already connected");
196 public boolean getDoInput()
201 public void setDoOutput(boolean dooutput
)
204 throw new IllegalAccessError("Already connected");
211 public boolean getDoOutput()
216 public void setAllowUserInteraction(boolean allowuserinteraction
)
219 throw new IllegalAccessError("Already connected");
221 allowUserInteraction
= allowuserinteraction
;
224 public boolean getAllowUserInteraction()
226 return allowUserInteraction
;
230 setDefaultAllowUserInteraction(boolean defaultallowuserinteraction
)
232 defaultAllowUserInteraction
= defaultallowuserinteraction
;
235 public static boolean getDefaultAllowUserInteraction()
237 return defaultAllowUserInteraction
;
240 public void setUseCaches(boolean usecaches
)
243 throw new IllegalAccessError("Already connected");
245 useCaches
= usecaches
;
248 public boolean getUseCaches()
253 public void setIfModifiedSince(long ifmodifiedsince
)
256 throw new IllegalAccessError("Already connected");
258 ifModifiedSince
= ifmodifiedsince
;
261 public long getIfModifiedSince()
263 return ifModifiedSince
;
266 public boolean getDefaultUseCaches()
268 return defaultUseCaches
;
271 public void setDefaultUseCaches(boolean defaultusecaches
)
273 defaultUseCaches
= defaultusecaches
;
276 public void setRequestProperty(String key
, String value
)
278 // Do nothing unless overridden by subclasses that support setting
279 // header fields in the request.
282 public String
getRequestProperty(String key
)
284 // Overridden by subclasses that support reading header fields from the
289 public static void setDefaultRequestProperty(String key
, String value
)
291 // Do nothing unless overridden by subclasses that support setting
292 // default request properties.
295 public static String
getDefaultRequestProperty(String key
)
297 // Overridden by subclasses that support default request properties.
301 public static void setContentHandlerFactory(ContentHandlerFactory fac
)
304 throw new Error("ContentHandlerFactory already set");
306 // Throw an exception if an extant security mgr precludes
307 // setting the factory.
308 SecurityManager s
= System
.getSecurityManager();
314 protected static String
guessContentTypeFromName(String fname
)
316 int dot
= fname
.lastIndexOf (".");
320 if (dot
== fname
.length())
321 return ("application/octet-stream");
323 fname
= fname
.substring (dot
+ 1);
326 String type
= MimeTypes
.getMimeTypeFromExtension (fname
);
329 return("application/octet-stream");
334 // TODO: public static String guessContentTypeFromStream(InputStream is)
335 // throws IOException
339 // TODO12: protected void parseURL(URL u, String spec, int start, int limit)
342 public static FileNameMap
getFileNameMap()
348 public static void setFileNameMap(FileNameMap map
)
350 // Throw an exception if an extant security mgr precludes
351 // setting the factory.
352 SecurityManager s
= System
.getSecurityManager();
359 private ContentHandler
setContentHandler(String contentType
)
361 ContentHandler handler
;
363 // No content type so just handle it as the default.
364 if (contentType
== null || contentType
== "")
367 // See if a handler has been cached for this content type.
368 // For efficiency, if a content type has been searched for but not
369 // found, it will be in the hash table but as the contentType String
370 // instead of a ContentHandler.
371 if ((handler
= (ContentHandler
) handlers
.get(contentType
)) != null)
372 if (handler
instanceof ContentHandler
)
377 // If a non-default factory has been set, use it to find the content type.
379 handler
= factory
.createContentHandler(contentType
);
381 // Non-default factory may have returned null or a factory wasn't set.
382 // Use the default search algorithm to find a handler for this content type.
385 // Get the list of packages to check and append our default handler
386 // to it, along with the JDK specified default as a last resort.
387 // Except in very unusual environments the JDK specified one shouldn't
388 // ever be needed (or available).
389 String propVal
= System
.getProperty("java.content.handler.pkgs");
390 propVal
= (propVal
== null) ?
"" : (propVal
+ "|");
391 propVal
= propVal
+ "gnu.gcj.content|sun.net.www.content";
393 // Replace the '/' character in the content type with '.' and
394 // all other non-alphabetic, non-numeric characters with '_'.
395 StringTokenizer pkgPrefix
= new StringTokenizer(propVal
, "|");
396 char[] cArray
= contentType
.toCharArray();
397 for (int i
= 0; i
< cArray
.length
; i
++)
399 if (cArray
[i
] == '/')
401 else if (! ((cArray
[i
] >= 'A' && cArray
[i
] <= 'Z') ||
402 (cArray
[i
] >= 'a' && cArray
[i
] <= 'z') ||
403 (cArray
[i
] >= '0' && cArray
[i
] <= '9')))
406 String contentClass
= new String(cArray
);
408 // See if a class of this content type exists in any of the packages.
411 String facName
= pkgPrefix
.nextToken() + "." + contentClass
;
415 (ContentHandler
) Class
.forName(facName
).newInstance();
419 // Can't instantiate; handler still null, go on to next element.
421 } while ((handler
== null ||
422 ! (handler
instanceof ContentHandler
)) &&
423 pkgPrefix
.hasMoreTokens());
426 // Update the hashtable with the new content handler.
427 if (handler
!= null && handler
instanceof ContentHandler
)
429 handlers
.put(contentType
, handler
);
433 // For efficiency on subsequent searches, put a dummy entry in the hash
434 // table for content types that don't have a non-default ContentHandler.
435 handlers
.put(contentType
, contentType
);
439 // We don't put these in a static initializer, because it creates problems
440 // with initializer co-dependency: SimpleDateFormat's constructors eventually
441 // depend on URLConnection (via the java.text.*Symbols classes).
442 private synchronized void initializeDateFormats()
444 if (dateformats_initialized
)
446 locale
= new Locale("En", "Us", "Unix");
447 dateFormat1
= new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'",
449 dateFormat2
= new SimpleDateFormat("EEEE, dd-MMM-yy hh:mm:ss 'GMT'",
451 dateFormat3
= new SimpleDateFormat("EEE MMM d hh:mm:ss yyyy", locale
);
452 dateformats_initialized
= true;