1 /* HttpURLConnection.java -- URLConnection class for HTTP protocol
2 Copyright (C) 1998, 1999, 2000, 2002, 2003 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)
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., 59 Temple Place, Suite 330, Boston, MA
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
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
.BufferedInputStream
;
42 import java
.io
.InputStream
;
43 import java
.io
.IOException
;
44 import java
.io
.OutputStream
;
45 import java
.io
.PrintWriter
;
46 import java
.net
.HttpURLConnection
;
47 import java
.net
.ProtocolException
;
48 import java
.net
.Socket
;
50 import java
.net
.URLConnection
;
51 import java
.util
.Iterator
;
53 import java
.util
.Vector
;
54 import java
.util
.Hashtable
;
57 * This subclass of java.net.URLConnection models a URLConnection via
60 * Status: Minimal subset of functionality. Proxies only partially
61 * handled; Redirects not yet handled. FileNameMap handling needs to
62 * be considered. useCaches, ifModifiedSince, and
63 * allowUserInteraction need consideration as well as doInput and
66 * @author Aaron M. Renn <arenn@urbanophile.com>
67 * @author Warren Levy <warrenl@cygnus.com>
69 public final class Connection
extends HttpURLConnection
72 * The socket we are connected to
74 private Socket socket
;
75 private static int proxyPort
= 80;
76 private static boolean proxyInUse
= false;
77 private static String proxyHost
= null;
81 // Recognize some networking properties listed at
82 // http://java.sun.com/j2se/1.4/docs/guide/net/properties.html.
84 proxyHost
= System
.getProperty("http.proxyHost");
85 if (proxyHost
!= null)
88 if ((port
= System
.getProperty("http.proxyPort")) != null)
92 proxyPort
= Integer
.parseInt(port
);
103 * The InputStream for this connection.
105 private BufferedInputStream inputStream
;
108 * This is the object that holds the header field information
110 private Hashtable requestProperties
= new Hashtable();
111 private Hashtable hdrHash
= new Hashtable();
112 private Vector hdrVec
= new Vector();
115 * Calls superclass constructor to initialize
117 protected Connection(URL url
)
121 /* Set up some variables */
125 public void setRequestProperty(String key
, String value
)
128 throw new IllegalAccessError("Connection already established.");
130 requestProperties
.put(key
, value
);
133 public String
getRequestProperty(String key
)
136 throw new IllegalAccessError("Connection already established.");
138 return (String
) requestProperties
.get(key
);
142 * Connects to the remote host, sends the request, and parses the reply
143 * code and header information returned
145 public void connect() throws IOException
147 // Call is ignored if already connected.
151 // Get address and port number.
156 socket
= new Socket(proxyHost
, port
);
160 if ((port
= url
.getPort()) == -1)
162 // Open socket and output stream.
163 socket
= new Socket(url
.getHost(), port
);
166 // Originally tried using a BufferedReader here to take advantage of
167 // the readLine method and avoid the following, but the buffer read
168 // past the end of the headers so the first part of the content was lost.
169 // It is probably more robust than it needs to be, e.g. the byte[]
170 // is unlikely to overflow and a '\r' should always be followed by a '\n',
171 // but it is better to be safe just in case.
172 inputStream
= new BufferedInputStream(socket
.getInputStream());
180 * Disconnects from the remote server.
182 public void disconnect()
190 catch (IOException e
)
192 // Ignore errors in closing socket.
199 * Write HTTP request header and content to outputWriter.
201 void sendRequest() throws IOException
203 // Create PrintWriter for easier sending of headers.
204 PrintWriter outputWriter
= new PrintWriter(socket
.getOutputStream());
206 // Send request including any request properties that were set.
207 outputWriter
.print (getRequestMethod() + " " + url
.getFile()
210 // Set additional HTTP headers.
211 if (getRequestProperty ("Host") == null)
212 setRequestProperty ("Host", url
.getHost());
214 // Write all req_props name-value pairs to the output writer.
215 Iterator itr
= getRequestProperties().entrySet().iterator();
217 while (itr
.hasNext())
219 Map
.Entry e
= (Map
.Entry
) itr
.next();
220 outputWriter
.print (e
.getKey() + ": " + e
.getValue() + "\r\n");
223 // One more CR-LF indicates end of header.
224 outputWriter
.print ("\r\n");
225 outputWriter
.flush();
229 * Return a boolean indicating whether or not this connection is
230 * going through a proxy
232 * @return true if using a proxy, false otherwise
234 public boolean usingProxy()
240 * Returns an InputStream for reading from this connection. This stream
241 * will be "queued up" for reading just the contents of the requested file.
242 * Overrides URLConnection.getInputStream()
244 * @return An InputStream for this connection.
246 * @exception IOException If an error occurs
248 public InputStream
getInputStream() throws IOException
254 throw new ProtocolException("Can't open InputStream if doInput is false");
259 public OutputStream
getOutputStream() throws IOException
265 throw new ProtocolException("Can't open OutputStream if doOutput is false");
267 return socket
.getOutputStream();
271 * Overrides java.net.HttpURLConnection.setRequestMethod() in order to
272 * restrict the available methods to only those we support.
274 * @param method The RequestMethod to use
276 * @exception ProtocolException If the specified method is not valid
278 public void setRequestMethod (String method
) throws ProtocolException
280 method
= method
.toUpperCase();
282 if (method
.equals("GET"))
283 super.setRequestMethod (method
);
285 throw new ProtocolException ("Unsupported or unknown request method " +
289 public String
getHeaderField(String name
)
296 catch (IOException x
)
301 return (String
) hdrHash
.get(name
.toLowerCase());
304 public Map
getHeaderFields()
311 catch (IOException x
)
320 * This method returns the header field value at the specified numeric
323 * @param n The index into the header field array
325 * @return The value of the specified header field, or <code>null</code>
326 * if the specified index is not valid.
328 public String
getHeaderField(int n
)
335 catch (IOException x
)
340 if (n
< hdrVec
.size())
341 return getField ((String
) hdrVec
.elementAt(n
));
346 * This method returns the header field key at the specified numeric
349 * @param n The index into the header field array
351 * @return The name of the header field key, or <code>null</code> if the
352 * specified index is not valid.
354 public String
getHeaderFieldKey(int n
)
361 catch (IOException x
)
366 if (n
< hdrVec
.size())
367 return getKey ((String
) hdrVec
.elementAt(n
));
371 private String
getKey(String str
)
375 int index
= str
.indexOf(':');
377 return str
.substring(0, index
);
382 private String
getField(String str
)
386 int index
= str
.indexOf(':');
388 return str
.substring(index
+ 1).trim();
394 * Read HTTP reply from inputStream.
396 private void getHttpHeaders() throws IOException
399 byte[] buf
= new byte[buflen
];
401 boolean gotnl
= false;
402 byte[] ch
= new byte[1];
407 // Check for leftover byte from non-'\n' after a '\r'.
409 line
= line
+ '\r' + new String(ch
, 0, 1);
412 // FIXME: This is rather inefficient.
413 for (i
= 0; i
< buflen
; i
++)
415 buf
[i
] = (byte) inputStream
.read();
417 throw new IOException("Malformed HTTP header");
420 inputStream
.read(ch
, 0, 1);
426 line
= line
+ new String(buf
, 0, i
);
428 // A '\r' '\n' combo indicates the end of the header entry.
429 // If it wasn't found, cycle back through the loop and append
430 // to 'line' until one is found.
433 // A zero length entry signals the end of the headers.
434 if (line
.length() == 0)
437 // Store the header and reinitialize for next cycle.
438 hdrVec
.addElement(line
);
439 String key
= getKey(line
);
441 hdrHash
.put(key
.toLowerCase(), getField(line
));