* java/lang/System.java (static): Set http.agent system property when
[official-gcc.git] / libjava / gnu / java / net / protocol / http / Connection.java
blob728d14a7e6b9d1329bb86fe69826315f6bd0253e
1 /* HttpURLConnection.java -- URLConnection class for HTTP protocol
2 Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA.
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 package gnu.java.net.protocol.http;
42 import java.io.BufferedInputStream;
43 import java.io.BufferedOutputStream;
44 import java.io.ByteArrayOutputStream;
45 import java.io.DataInputStream;
46 import java.io.InputStream;
47 import java.io.IOException;
48 import java.io.OutputStream;
49 import java.io.OutputStreamWriter;
50 import java.io.PrintWriter;
51 import java.net.HttpURLConnection;
52 import java.net.ProtocolException;
53 import java.net.Socket;
54 import java.net.URL;
55 import java.net.URLConnection;
56 import java.security.AccessController;
57 import java.security.PrivilegedAction;
58 import java.util.HashMap;
59 import java.util.Iterator;
60 import java.util.Map;
61 import gnu.java.net.HeaderFieldHelper;
63 /**
64 * This subclass of java.net.URLConnection models a URLConnection via
65 * the HTTP protocol.
67 * Status: Minimal subset of functionality. Proxies only partially
68 * handled; Redirects not yet handled. FileNameMap handling needs to
69 * be considered. useCaches, ifModifiedSince, and
70 * allowUserInteraction need consideration as well as doInput and
71 * doOutput.
73 * @author Aaron M. Renn <arenn@urbanophile.com>
74 * @author Warren Levy <warrenl@cygnus.com>
76 public final class Connection extends HttpURLConnection
78 /**
79 * The socket we are connected to
81 private Socket socket;
83 // Properties depeending on system properties settings
84 static int proxyPort = 80;
85 static boolean proxyInUse = false;
86 static String proxyHost = null;
87 static String userAgent;
89 static
91 // Make sure access control for system properties depends only on
92 // our class ProtectionDomain, not on any (indirect) callers.
93 AccessController.doPrivileged(new PrivilegedAction() {
94 public Object run()
96 // Recognize some networking properties listed at
97 // http://java.sun.com/j2se/1.4/docs/guide/net/properties.html.
98 String port = null;
99 proxyHost = System.getProperty("http.proxyHost");
100 if (proxyHost != null)
102 proxyInUse = true;
103 if ((port = System.getProperty("http.proxyPort")) != null)
107 proxyPort = Integer.parseInt(port);
109 catch (Throwable t)
111 // Nothing.
116 userAgent = System.getProperty("http.agent");
118 return null;
124 * The InputStream for this connection.
126 private DataInputStream inputStream;
129 * The OutputStream for this connection
131 private OutputStream outputStream;
134 * bufferedOutputStream is a buffer to contain content of the HTTP request,
135 * and will be written to outputStream all at once
137 private ByteArrayOutputStream bufferedOutputStream;
140 * This object holds the request properties.
142 private HashMap requestProperties = new HashMap();
145 * This is the object that holds the header field information
147 private HeaderFieldHelper headers = new HeaderFieldHelper();
150 * Calls superclass constructor to initialize
152 protected Connection(URL url)
154 super(url);
156 /* Set up some variables */
157 doOutput = false;
161 * Connects to the remote host, sends the request, and parses the reply
162 * code and header information returned
164 public void connect() throws IOException
166 // Call is ignored if already connected.
167 if (connected)
168 return;
170 // Get address and port number.
171 int port;
172 if (proxyInUse)
174 port = proxyPort;
175 socket = new Socket(proxyHost, port);
177 else
179 if ((port = url.getPort()) == -1)
180 port = 80;
181 // Open socket and output stream.
182 socket = new Socket(url.getHost(), port);
185 inputStream =
186 new DataInputStream(new BufferedInputStream(socket.getInputStream()));
187 outputStream = new BufferedOutputStream (socket.getOutputStream());
189 sendRequest();
190 receiveReply();
192 connected = true;
196 * Disconnects from the remote server.
198 public void disconnect()
200 if (socket != null)
204 socket.close();
206 catch (IOException e)
208 // Ignore errors in closing socket.
210 socket = null;
215 * Write HTTP request header and content to outputWriter.
217 void sendRequest() throws IOException
219 // Create PrintWriter for easier sending of headers.
220 PrintWriter outputWriter =
221 new PrintWriter(new OutputStreamWriter(outputStream, "8859_1"));
223 // Send request including any request properties that were set.
224 outputWriter.print (getRequestMethod() + " " + url.getFile()
225 + " HTTP/1.1\r\n");
227 // Set additional HTTP headers.
228 if (getRequestProperty ("Host") == null)
229 setRequestProperty ("Host", url.getHost());
231 if (getRequestProperty ("Connection") == null)
232 setRequestProperty ("Connection", "Close");
234 if (getRequestProperty ("user-agent") == null)
235 setRequestProperty ("user-agent", userAgent);
237 if (getRequestProperty ("accept") == null)
238 setRequestProperty ("accept", "*/*");
240 if (getRequestProperty ("Content-type") == null)
241 setRequestProperty ("Content-type", "application/x-www-form-urlencoded");
243 // Set correct content length.
244 if (bufferedOutputStream != null)
245 setRequestProperty ("Content-length", String.valueOf (bufferedOutputStream.size()));
247 // Write all req_props name-value pairs to the output writer.
248 Iterator itr = getRequestProperties().entrySet().iterator();
250 while (itr.hasNext())
252 Map.Entry e = (Map.Entry) itr.next();
253 outputWriter.print (e.getKey() + ": " + e.getValue() + "\r\n");
256 // One more CR-LF indicates end of header.
257 outputWriter.print ("\r\n");
258 outputWriter.flush();
260 // Write content
261 if (bufferedOutputStream != null)
263 bufferedOutputStream.writeTo (outputStream);
264 outputStream.flush();
269 * Read HTTP reply from inputStream.
271 private void receiveReply() throws IOException
273 // Parse the reply
274 String line = inputStream.readLine();
275 String saveline = line;
276 int idx = line.indexOf (" ");
278 if ((idx == -1)
279 || (line.length() < (idx + 6)))
280 throw new IOException ("Server reply was unparseable: " + saveline);
282 headers.addHeaderField (null, line);
284 line = line.substring (idx + 1);
285 String code = line.substring (0, 3);
289 responseCode = Integer.parseInt (code);
291 catch (NumberFormatException e)
293 throw new IOException ("Server reply was unparseable: " + saveline);
296 responseMessage = line.substring (4);
298 // Now read the header lines
299 String key = null, value = null;
301 while (true)
303 line = inputStream.readLine();
305 if (line.equals(""))
306 break;
308 // Check for folded lines
309 if (line.startsWith (" ")
310 || line.startsWith("\t"))
312 // Trim off leading space
315 if (line.length() == 1)
316 throw new IOException("Server header lines were unparseable: "
317 + line);
319 line = line.substring (1);
321 while (line.startsWith(" ")
322 || line.startsWith("\t"));
324 value = value + " " + line;
326 else
328 if (key != null)
330 headers.addHeaderField (key.toLowerCase(), value);
331 key = null;
332 value = null;
335 // Parse out key and value
336 idx = line.indexOf (":");
337 if ((idx == -1)
338 || (line.length() < (idx + 2)))
339 throw new IOException ("Server header lines were unparseable: "
340 + line);
342 key = line.substring (0, idx);
343 value = line.substring (idx + 1);
345 // Trim off leading space
346 while (value.startsWith (" ")
347 || value.startsWith ("\t"))
349 if (value.length() == 1)
350 throw new IOException ("Server header lines were unparseable: "
351 + line);
353 value = value.substring (1);
358 if (key != null)
360 headers.addHeaderField (key.toLowerCase(), value.toLowerCase());
365 * Return a boolean indicating whether or not this connection is
366 * going through a proxy
368 * @return true if using a proxy, false otherwise
370 public boolean usingProxy()
372 return proxyInUse;
376 * Returns an InputStream for reading from this connection. This stream
377 * will be "queued up" for reading just the contents of the requested file.
378 * Overrides URLConnection.getInputStream()
380 * @return An InputStream for this connection.
382 * @exception IOException If an error occurs
384 public InputStream getInputStream() throws IOException
386 if (!connected)
387 connect();
389 if (!doInput)
390 throw new ProtocolException("Can't open InputStream if doInput is false");
392 return inputStream;
396 * Returns on OutputStream for writing to this connection.
398 * @return An OutputStream for this connection.
400 * @exception IOException If an error occurs
402 public OutputStream getOutputStream() throws IOException
404 if (connected)
405 throw new ProtocolException
406 ("You cannot get an output stream for an existing http connection");
408 if (!doOutput)
409 throw new ProtocolException
410 ("Want output stream while haven't setDoOutput(true)");
412 if (bufferedOutputStream == null)
413 bufferedOutputStream = new ByteArrayOutputStream (256); //default is too small
415 return bufferedOutputStream;
419 * Overrides java.net.HttpURLConnection.setRequestMethod() in order to
420 * restrict the available methods to only those we support.
422 * @param method The RequestMethod to use
424 * @exception ProtocolException If the specified method is not valid
426 public void setRequestMethod (String method) throws ProtocolException
428 method = method.toUpperCase();
430 if (method.equals("GET")
431 || method.equals("HEAD")
432 || method.equals("POST"))
433 super.setRequestMethod (method);
434 else
435 throw new ProtocolException ("Unsupported or unknown request method " +
436 method);
439 public void addRequestProperty(String key, String value)
441 if (connected)
442 throw new IllegalStateException("Already connected");
444 String old = (String) requestProperties.put(key, value);
446 if (old != null)
447 requestProperties.put(key, old + "," + value);
450 public String getRequestProperty(String key)
452 if (connected)
453 throw new IllegalStateException("Already connected");
455 return (String) requestProperties.get(key);
458 public void setRequestProperty(String key, String value)
460 if (connected)
461 throw new IllegalStateException("Already connected");
463 requestProperties.put(key, value);
466 public Map getRequestProperties()
468 if (connected)
469 throw new IllegalStateException("Already connected");
471 return requestProperties;
474 public String getHeaderField(String name)
476 if (!connected)
479 connect();
481 catch (IOException x)
483 return null;
486 return (String) headers.getHeaderFieldValueByKey(name.toLowerCase());
489 public Map getHeaderFields()
491 if (!connected)
494 connect();
496 catch (IOException x)
498 return null;
501 return headers.getHeaderFields();
505 * This method returns the header field value at the specified numeric
506 * index.
508 * @param n The index into the header field array
510 * @return The value of the specified header field, or <code>null</code>
511 * if the specified index is not valid.
513 public String getHeaderField(int n)
515 if (!connected)
518 connect();
520 catch (IOException x)
522 return null;
525 return headers.getHeaderFieldValueByIndex (n);
529 * This method returns the header field key at the specified numeric
530 * index.
532 * @param n The index into the header field array
534 * @return The name of the header field key, or <code>null</code> if the
535 * specified index is not valid.
537 public String getHeaderFieldKey(int n)
539 if (!connected)
542 connect();
544 catch (IOException x)
546 return null;
549 return headers.getHeaderFieldKeyByIndex (n);