Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / gnu / java / net / protocol / http / HTTPURLConnection.java
blobd5da7d61ae4f623bab205bd0fde23f85c8aa2dc5
1 /* HTTPURLConnection.java --
2 Copyright (C) 2004, 2005 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)
9 any later version.
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., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
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
24 combination.
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. */
39 package gnu.java.net.protocol.http;
41 import java.io.ByteArrayOutputStream;
42 import java.io.FileNotFoundException;
43 import java.io.IOException;
44 import java.io.InputStream;
45 import java.io.OutputStream;
46 import java.net.ProtocolException;
47 import java.net.URL;
48 import java.security.AccessController;
49 import java.security.PrivilegedAction;
50 import java.security.cert.Certificate;
51 import java.util.Collections;
52 import java.util.Date;
53 import java.util.Iterator;
54 import java.util.LinkedHashMap;
55 import java.util.Map;
57 import javax.net.ssl.HandshakeCompletedEvent;
58 import javax.net.ssl.HandshakeCompletedListener;
59 import javax.net.ssl.HostnameVerifier;
60 import javax.net.ssl.HttpsURLConnection;
61 import javax.net.ssl.SSLPeerUnverifiedException;
62 import javax.net.ssl.SSLSocketFactory;
64 /**
65 * A URLConnection that uses the HTTPConnection class.
67 * @author Chris Burdess (dog@gnu.org)
69 public class HTTPURLConnection
70 extends HttpsURLConnection
71 implements HandshakeCompletedListener
74 /**
75 * Pool of reusable connections, used if keepAlive is true.
77 private static final LinkedHashMap connectionPool = new LinkedHashMap();
78 static int maxConnections;
81 * The underlying connection.
83 private HTTPConnection connection;
85 // These are package private for use in anonymous inner classes.
86 String proxyHostname;
87 int proxyPort;
88 String agent;
89 boolean keepAlive;
91 private Request request;
92 private Headers requestHeaders;
93 private ByteArrayOutputStream requestSink;
94 private boolean requestMethodSetExplicitly;
96 private Response response;
97 private InputStream responseSink;
98 private InputStream errorSink;
100 private HandshakeCompletedEvent handshakeEvent;
103 * Constructor.
104 * @param url the URL
106 public HTTPURLConnection(URL url)
107 throws IOException
109 super(url);
110 requestHeaders = new Headers();
111 AccessController.doPrivileged(this.new GetHTTPPropertiesAction());
114 class GetHTTPPropertiesAction
115 implements PrivilegedAction
118 public Object run()
120 proxyHostname = System.getProperty("http.proxyHost");
121 if (proxyHostname != null && proxyHostname.length() > 0)
123 String port = System.getProperty("http.proxyPort");
124 if (port != null && port.length() > 0)
126 proxyPort = Integer.parseInt(port);
128 else
130 proxyHostname = null;
131 proxyPort = -1;
134 agent = System.getProperty("http.agent");
135 String ka = System.getProperty("http.keepAlive");
136 keepAlive = !(ka != null && "false".equals(ka));
137 String mc = System.getProperty("http.maxConnections");
138 maxConnections = (mc != null && mc.length() > 0) ?
139 Math.max(Integer.parseInt(mc), 1) : 5;
140 return null;
145 public void connect()
146 throws IOException
148 if (connected)
150 return;
152 String protocol = url.getProtocol();
153 boolean secure = "https".equals(protocol);
154 String host = url.getHost();
155 int port = url.getPort();
156 if (port < 0)
158 port = secure ? HTTPConnection.HTTPS_PORT :
159 HTTPConnection.HTTP_PORT;
161 String file = url.getFile();
162 String username = url.getUserInfo();
163 String password = null;
164 if (username != null)
166 int ci = username.indexOf(':');
167 if (ci != -1)
169 password = username.substring(ci + 1);
170 username = username.substring(0, ci);
173 final Credentials creds = (username == null) ? null :
174 new Credentials (username, password);
176 boolean retry;
179 retry = false;
180 if (connection == null)
182 connection = getConnection(host, port, secure);
183 if (secure)
185 SSLSocketFactory factory = getSSLSocketFactory();
186 HostnameVerifier verifier = getHostnameVerifier();
187 if (factory != null)
189 connection.setSSLSocketFactory(factory);
191 connection.addHandshakeCompletedListener(this);
192 // TODO verifier
195 if (proxyHostname != null)
197 if (proxyPort < 0)
199 proxyPort = secure ? HTTPConnection.HTTPS_PORT :
200 HTTPConnection.HTTP_PORT;
202 connection.setProxy(proxyHostname, proxyPort);
206 request = connection.newRequest(method, file);
207 if (!keepAlive)
209 request.setHeader("Connection", "close");
211 if (agent != null)
213 request.setHeader("User-Agent", agent);
215 request.getHeaders().putAll(requestHeaders);
216 if (requestSink != null)
218 byte[] content = requestSink.toByteArray();
219 RequestBodyWriter writer = new ByteArrayRequestBodyWriter(content);
220 request.setRequestBodyWriter(writer);
222 if (creds != null)
224 request.setAuthenticator(new Authenticator() {
225 public Credentials getCredentials(String realm, int attempts)
227 return (attempts < 2) ? creds : null;
231 response = request.dispatch();
233 catch (IOException ioe)
235 if (connection.useCount > 0)
237 // Connection re-use failed: Try a new connection.
240 connection.close();
242 catch (IOException _)
244 // Ignore.
246 connection = null;
247 retry = true;
248 continue;
250 else
252 // First time the connection was used: Hard failure.
253 throw ioe;
257 if (response.getCodeClass() == 3 && getInstanceFollowRedirects())
259 // Follow redirect
260 String location = response.getHeader("Location");
261 if (location != null)
263 String connectionUri = connection.getURI();
264 int start = connectionUri.length();
265 if (location.startsWith(connectionUri) &&
266 location.charAt(start) == '/')
268 file = location.substring(start);
269 retry = true;
271 else if (location.startsWith("http:"))
273 connection.close();
274 connection = null;
275 secure = false;
276 start = 7;
277 int end = location.indexOf('/', start);
278 host = location.substring(start, end);
279 int ci = host.lastIndexOf(':');
280 if (ci != -1)
282 port = Integer.parseInt(host.substring (ci + 1));
283 host = host.substring(0, ci);
285 else
287 port = HTTPConnection.HTTP_PORT;
289 file = location.substring(end);
290 retry = true;
292 else if (location.startsWith("https:"))
294 connection.close();
295 connection = null;
296 secure = true;
297 start = 8;
298 int end = location.indexOf('/', start);
299 host = location.substring(start, end);
300 int ci = host.lastIndexOf(':');
301 if (ci != -1)
303 port = Integer.parseInt(host.substring (ci + 1));
304 host = host.substring(0, ci);
306 else
308 port = HTTPConnection.HTTPS_PORT;
310 file = location.substring(end);
311 retry = true;
313 else if (location.length() > 0)
315 // Malformed absolute URI, treat as file part of URI
316 if (location.charAt(0) == '/')
318 // Absolute path
319 file = location;
321 else
323 // Relative path
324 int lsi = file.lastIndexOf('/');
325 file = (lsi == -1) ? "/" : file.substring(0, lsi + 1);
326 file += location;
328 retry = true;
332 else
334 responseSink = response.getBody();
336 if (response.getCode() == 404)
338 errorSink = responseSink;
339 throw new FileNotFoundException(url.toString());
343 while (retry);
344 connected = true;
348 * Returns a connection, from the pool if necessary.
350 HTTPConnection getConnection(String host, int port, boolean secure)
351 throws IOException
353 HTTPConnection connection;
354 if (keepAlive)
356 Object key = HTTPConnection.getPoolKey(host, port, secure);
357 synchronized (connectionPool)
359 connection = (HTTPConnection) connectionPool.remove(key);
360 if (connection == null)
362 connection = new HTTPConnection(host, port, secure);
363 connection.setPool(connectionPool);
367 else
369 connection = new HTTPConnection(host, port, secure);
371 return connection;
374 public void disconnect()
376 if (connection != null)
380 connection.close();
382 catch (IOException e)
388 public boolean usingProxy()
390 return (proxyHostname != null);
394 * Overrides the corresponding method in HttpURLConnection to permit
395 * arbitrary methods, as long as they're valid ASCII alphabetic
396 * characters. This is to permit WebDAV and other HTTP extensions to
397 * function.
398 * @param method the method
400 public void setRequestMethod(String method)
401 throws ProtocolException
403 if (connected)
405 throw new ProtocolException("Already connected");
407 // Validate
408 method = method.toUpperCase();
409 int len = method.length();
410 if (len == 0)
412 throw new ProtocolException("Empty method name");
414 for (int i = 0; i < len; i++)
416 char c = method.charAt(i);
417 if (c < 0x41 || c > 0x5a)
419 throw new ProtocolException("Illegal character '" + c +
420 "' at index " + i);
423 // OK
424 this.method = method;
425 requestMethodSetExplicitly = true;
428 public String getRequestProperty(String key)
430 return requestHeaders.getValue(key);
433 public Map getRequestProperties()
435 return requestHeaders;
438 public void setRequestProperty(String key, String value)
440 requestHeaders.put(key, value);
443 public void addRequestProperty(String key, String value)
445 String old = requestHeaders.getValue(key);
446 if (old == null)
448 requestHeaders.put(key, value);
450 else
452 requestHeaders.put(key, old + "," + value);
456 public OutputStream getOutputStream()
457 throws IOException
459 if (connected)
461 throw new ProtocolException("Already connected");
463 if (!doOutput)
465 throw new ProtocolException("doOutput is false");
467 else if (!requestMethodSetExplicitly)
470 * Silently change the method to POST if no method was set
471 * explicitly. This is due to broken applications depending on this
472 * behaviour (Apache XMLRPC for one).
474 method = "POST";
476 if (requestSink == null)
478 requestSink = new ByteArrayOutputStream();
480 return requestSink;
483 // -- Response --
485 public InputStream getInputStream()
486 throws IOException
488 if (!connected)
490 connect();
492 if (!doInput)
494 throw new ProtocolException("doInput is false");
496 return responseSink;
499 public InputStream getErrorStream()
501 return errorSink;
504 public Map getHeaderFields()
506 if (!connected)
510 connect();
512 catch (IOException e)
514 return null;
517 Headers headers = response.getHeaders();
518 LinkedHashMap ret = new LinkedHashMap();
519 ret.put(null, Collections.singletonList(getStatusLine(response)));
520 for (Iterator i = headers.entrySet().iterator(); i.hasNext(); )
522 Map.Entry entry = (Map.Entry) i.next();
523 String key = (String) entry.getKey();
524 String value = (String) entry.getValue();
525 ret.put(key, Collections.singletonList(value));
527 return Collections.unmodifiableMap(ret);
530 String getStatusLine(Response response)
532 return "HTTP/" + response.getMajorVersion() +
533 "." + response.getMinorVersion() +
534 " " + response.getCode() +
535 " " + response.getMessage();
538 public String getHeaderField(int index)
540 if (!connected)
544 connect();
546 catch (IOException e)
548 return null;
551 if (index == 0)
553 return getStatusLine(response);
555 Iterator i = response.getHeaders().entrySet().iterator();
556 Map.Entry entry;
557 int count = 1;
560 if (!i.hasNext())
562 return null;
564 entry = (Map.Entry) i.next();
565 count++;
567 while (count <= index);
568 return (String) entry.getValue();
571 public String getHeaderFieldKey(int index)
573 if (!connected)
577 connect();
579 catch (IOException e)
581 return null;
584 if (index == 0)
586 return null;
588 Iterator i = response.getHeaders().entrySet().iterator();
589 Map.Entry entry;
590 int count = 1;
593 if (!i.hasNext())
595 return null;
597 entry = (Map.Entry) i.next();
598 count++;
600 while (count <= index);
601 return (String) entry.getKey();
604 public String getHeaderField(String name)
606 if (!connected)
610 connect();
612 catch (IOException e)
614 return null;
617 return (String) response.getHeader(name);
620 public long getHeaderFieldDate(String name, long def)
622 if (!connected)
626 connect();
628 catch (IOException e)
630 return def;
633 Date date = response.getDateHeader(name);
634 return (date == null) ? def : date.getTime();
637 public String getContentType()
639 return getHeaderField("Content-Type");
642 public int getResponseCode()
643 throws IOException
645 if (!connected)
647 connect();
649 return response.getCode();
652 public String getResponseMessage()
653 throws IOException
655 if (!connected)
657 connect();
659 return response.getMessage();
662 // -- HTTPS specific --
664 public String getCipherSuite()
666 if (!connected)
668 throw new IllegalStateException("not connected");
670 return handshakeEvent.getCipherSuite();
673 public Certificate[] getLocalCertificates()
675 if (!connected)
677 throw new IllegalStateException("not connected");
679 return handshakeEvent.getLocalCertificates();
682 public Certificate[] getServerCertificates()
683 throws SSLPeerUnverifiedException
685 if (!connected)
687 throw new IllegalStateException("not connected");
689 return handshakeEvent.getPeerCertificates();
692 // HandshakeCompletedListener
694 public void handshakeCompleted(HandshakeCompletedEvent event)
696 handshakeEvent = event;