60cfd76714f6300720d9d911ae95dfc4bf504e21
[gcc.git] / libjava / java / net / URLConnection.java
1 // URLConnection.java - Superclass of all communications links between
2 // an application and a URL.
3
4 /* Copyright (C) 1999 Red Hat, Inc.
5
6 This file is part of libgcj.
7
8 This software is copyrighted work licensed under the terms of the
9 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
10 details. */
11
12 package java.net;
13
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.StringTokenizer;
21 import gnu.gcj.io.MimeTypes;
22
23 /**
24 * @author Warren Levy <warrenl@cygnus.com>
25 * @date March 5, 1999.
26 */
27
28 /**
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.
33 */
34
35 public abstract class URLConnection
36 {
37 protected URL url;
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;
53
54 protected URLConnection(URL url)
55 {
56 this.url = url;
57 allowUserInteraction = defaultAllowUserInteraction;
58 useCaches = defaultUseCaches;
59 }
60
61 public abstract void connect() throws IOException;
62
63 public URL getURL()
64 {
65 return url;
66 }
67
68 public int getContentLength()
69 {
70 return getHeaderFieldInt("content-length", -1);
71 }
72
73 public String getContentType()
74 {
75 return getHeaderField("content-type");
76 }
77
78 public String getContentEncoding()
79 {
80 return getHeaderField("content-encoding");
81 }
82
83 public long getExpiration()
84 {
85 return getHeaderFieldDate("expiration", 0L);
86 }
87
88 public long getDate()
89 {
90 return getHeaderFieldDate("date", 0L);
91 }
92
93 public long getLastModified()
94 {
95 return getHeaderFieldDate("last-modified", 0L);
96 }
97
98 public String getHeaderField(int n)
99 {
100 // Subclasses for specific protocols override this.
101 return null;
102 }
103
104 public String getHeaderField(String name)
105 {
106 // Subclasses for specific protocols override this.
107 return null;
108 }
109
110 public int getHeaderFieldInt(String name, int val)
111 {
112 String str = getHeaderField(name);
113 try
114 {
115 if (str != null)
116 val = Integer.parseInt(str);
117 }
118 catch (NumberFormatException e)
119 {
120 ; // Do nothing; val is the default.
121 }
122 return val;
123 }
124
125 public long getHeaderFieldDate(String name, long val)
126 {
127 if (! dateformats_initialized)
128 initializeDateFormats();
129 String str = getHeaderField(name);
130 if (str != null)
131 {
132 Date date;
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();
139 }
140 return val;
141 }
142
143 public String getHeaderFieldKey(int n)
144 {
145 // Subclasses for specific protocols override this.
146 return null;
147 }
148
149 public Object getContent() throws IOException
150 {
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();
159
160 return contentHandler.getContent(this);
161 }
162
163 // TODO12: public Permission getPermission() throws IOException
164 // {
165 // // Subclasses may override this.
166 // return java.security.AllPermission;
167 // }
168
169 public InputStream getInputStream() throws IOException
170 {
171 // Subclasses for specific protocols override this.
172 throw new UnknownServiceException("Protocol " + url.getProtocol() +
173 " does not support input.");
174 }
175
176 public OutputStream getOutputStream() throws IOException
177 {
178 // Subclasses for specific protocols override this.
179 throw new UnknownServiceException("Protocol " + url.getProtocol() +
180 " does not support output.");
181 }
182
183 public String toString()
184 {
185 return this.getClass().getName() + ":" + url.toString();
186 }
187
188 public void setDoInput(boolean doinput)
189 {
190 if (connected)
191 throw new IllegalAccessError("Already connected");
192
193 doInput = doinput;
194 }
195
196 public boolean getDoInput()
197 {
198 return doInput;
199 }
200
201 public void setDoOutput(boolean dooutput)
202 {
203 if (connected)
204 throw new IllegalAccessError("Already connected");
205
206 doOutput = dooutput;
207 if (doOutput)
208 doInput = false;
209 }
210
211 public boolean getDoOutput()
212 {
213 return doOutput;
214 }
215
216 public void setAllowUserInteraction(boolean allowuserinteraction)
217 {
218 if (connected)
219 throw new IllegalAccessError("Already connected");
220
221 allowUserInteraction = allowuserinteraction;
222 }
223
224 public boolean getAllowUserInteraction()
225 {
226 return allowUserInteraction;
227 }
228
229 public static void
230 setDefaultAllowUserInteraction(boolean defaultallowuserinteraction)
231 {
232 defaultAllowUserInteraction = defaultallowuserinteraction;
233 }
234
235 public static boolean getDefaultAllowUserInteraction()
236 {
237 return defaultAllowUserInteraction;
238 }
239
240 public void setUseCaches(boolean usecaches)
241 {
242 if (connected)
243 throw new IllegalAccessError("Already connected");
244
245 useCaches = usecaches;
246 }
247
248 public boolean getUseCaches()
249 {
250 return useCaches;
251 }
252
253 public void setIfModifiedSince(long ifmodifiedsince)
254 {
255 if (connected)
256 throw new IllegalAccessError("Already connected");
257
258 ifModifiedSince = ifmodifiedsince;
259 }
260
261 public long getIfModifiedSince()
262 {
263 return ifModifiedSince;
264 }
265
266 public boolean getDefaultUseCaches()
267 {
268 return defaultUseCaches;
269 }
270
271 public void setDefaultUseCaches(boolean defaultusecaches)
272 {
273 defaultUseCaches = defaultusecaches;
274 }
275
276 public void setRequestProperty(String key, String value)
277 {
278 // Do nothing unless overridden by subclasses that support setting
279 // header fields in the request.
280 }
281
282 public String getRequestProperty(String key)
283 {
284 // Overridden by subclasses that support reading header fields from the
285 // request.
286 return null;
287 }
288
289 public static void setDefaultRequestProperty(String key, String value)
290 {
291 // Do nothing unless overridden by subclasses that support setting
292 // default request properties.
293 }
294
295 public static String getDefaultRequestProperty(String key)
296 {
297 // Overridden by subclasses that support default request properties.
298 return null;
299 }
300
301 public static void setContentHandlerFactory(ContentHandlerFactory fac)
302 {
303 if (factory != null)
304 throw new Error("ContentHandlerFactory already set");
305
306 // Throw an exception if an extant security mgr precludes
307 // setting the factory.
308 SecurityManager s = System.getSecurityManager();
309 if (s != null)
310 s.checkSetFactory();
311 factory = fac;
312 }
313
314 protected static String guessContentTypeFromName(String fname)
315 {
316 int dot = fname.lastIndexOf (".");
317
318 if (dot != -1)
319 {
320 if (dot == fname.length())
321 return ("application/octet-stream");
322 else
323 fname = fname.substring (dot + 1);
324 }
325
326 String type = MimeTypes.getMimeTypeFromExtension (fname);
327
328 if (type == null)
329 return("application/octet-stream");
330
331 return(type);
332 }
333
334 // TODO: public static String guessContentTypeFromStream(InputStream is)
335 // throws IOException
336 // {
337 // }
338
339 // TODO12: protected void parseURL(URL u, String spec, int start, int limit)
340
341 // JDK1.2
342 public static FileNameMap getFileNameMap()
343 {
344 return fileNameMap;
345 }
346
347 // JDK1.2
348 public static void setFileNameMap(FileNameMap map)
349 {
350 // Throw an exception if an extant security mgr precludes
351 // setting the factory.
352 SecurityManager s = System.getSecurityManager();
353 if (s != null)
354 s.checkSetFactory();
355
356 fileNameMap = map;
357 }
358
359 private ContentHandler setContentHandler(String contentType)
360 {
361 ContentHandler handler;
362
363 // No content type so just handle it as the default.
364 if (contentType == null || contentType == "")
365 return null;
366
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)
373 return handler;
374 else
375 return null;
376
377 // If a non-default factory has been set, use it to find the content type.
378 if (factory != null)
379 handler = factory.createContentHandler(contentType);
380
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.
383 if (handler == null)
384 {
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";
392
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++)
398 {
399 if (cArray[i] == '/')
400 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')))
404 cArray[i] = '_';
405 }
406 String contentClass = new String(cArray);
407
408 // See if a class of this content type exists in any of the packages.
409 do
410 {
411 String facName = pkgPrefix.nextToken() + "." + contentClass;
412 try
413 {
414 handler =
415 (ContentHandler) Class.forName(facName).newInstance();
416 }
417 catch (Exception e)
418 {
419 // Can't instantiate; handler still null, go on to next element.
420 }
421 } while ((handler == null ||
422 ! (handler instanceof ContentHandler)) &&
423 pkgPrefix.hasMoreTokens());
424 }
425
426 // Update the hashtable with the new content handler.
427 if (handler != null && handler instanceof ContentHandler)
428 {
429 handlers.put(contentType, handler);
430 return handler;
431 }
432
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);
436 return null;
437 }
438
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()
443 {
444 if (dateformats_initialized)
445 return;
446 locale = new Locale("En", "Us", "Unix");
447 dateFormat1 = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'",
448 locale);
449 dateFormat2 = new SimpleDateFormat("EEEE, dd-MMM-yy hh:mm:ss 'GMT'",
450 locale);
451 dateFormat3 = new SimpleDateFormat("EEE MMM d hh:mm:ss yyyy", locale);
452 dateformats_initialized = true;
453 }
454 }