HttpURLConnection.java
Upload User: demmber
Upload Date: 2007-12-22
Package Size: 717k
Code Size: 24k
Category:

Java Develop

Development Platform:

Java

  1. /*
  2.  * @(#)HttpURLConnection.java 0.3-3 18/06/1999
  3.  *
  4.  *  This file is part of the HTTPClient package
  5.  *  Copyright (C) 1996-2001 Ronald Tschal鋜
  6.  *
  7.  *  This library is free software; you can redistribute it and/or
  8.  *  modify it under the terms of the GNU Lesser General Public
  9.  *  License as published by the Free Software Foundation; either
  10.  *  version 2 of the License, or (at your option) any later version.
  11.  *
  12.  *  This library is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  *  Lesser General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU Lesser General Public
  18.  *  License along with this library; if not, write to the Free
  19.  *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20.  *  MA 02111-1307, USA
  21.  *
  22.  *  For questions, suggestions, bug-reports, enhancement-requests etc.
  23.  *  I may be contacted at:
  24.  *
  25.  *  ronald@innovation.ch
  26.  *
  27.  *  The HTTPClient's home page is located at:
  28.  *
  29.  *  http://www.innovation.ch/java/HTTPClient/ 
  30.  *
  31.  */
  32. package HTTPClient;
  33. import java.io.IOException;
  34. import java.io.InterruptedIOException;
  35. import java.io.InputStream;
  36. import java.io.OutputStream;
  37. import java.io.BufferedInputStream;
  38. import java.io.ByteArrayOutputStream;
  39. import java.net.URL;
  40. import java.net.ProtocolException;
  41. import java.util.Date;
  42. import java.util.Hashtable;
  43. import java.util.Enumeration;
  44. /**
  45.  * This class is a wrapper around HTTPConnection providing the interface
  46.  * defined by java.net.URLConnection and java.net.HttpURLConnection.
  47.  *
  48.  * <P>This class is a hacked version of the HttpURLConnection class for use
  49.  * with HotJava 1.1.x. It extends sun.net.www.protocol.http.HttpURLConnection
  50.  * instead of java.net.HttpURLConnection, because the HotJava uses the
  51.  * setInstanceFollowRedirect() method which is defined in the
  52.  * sun.*.HttpURLConnection class, but only if this is an instance of the
  53.  * sun.*.HttpURLConnection class (or a subclass).
  54.  *
  55.  * <P>One difference between Sun's HttpClient and this one is that this
  56.  * one will provide you with a real output stream if possible. This leads
  57.  * to two changes: you should set the request property "Content-Length",
  58.  * if possible, before invoking getOutputStream(); and in many cases
  59.  * getOutputStream() implies connect(). This should be transparent, though,
  60.  * apart from the fact that you can't change any headers or other settings
  61.  * anymore once you've gotten the output stream.
  62.  * So, for large data do:
  63.  * <PRE>
  64.  *   HttpURLConnection con = (HttpURLConnection) url.openConnection();
  65.  *
  66.  *   con.setDoOutput(true);
  67.  *   con.setRequestProperty("Content-Length", ...);
  68.  *   OutputStream out = con.getOutputStream();
  69.  *
  70.  *   out.write(...);
  71.  *   out.close();
  72.  *
  73.  *   if (con.getResponseCode() != 200)
  74.  *       ...
  75.  * </PRE>
  76.  *
  77.  * <P>The HTTPClient will send the request data using the chunked transfer
  78.  * encoding when no Content-Length is specified and the server is HTTP/1.1
  79.  * compatible. Because cgi-scripts can't usually handle this, you may
  80.  * experience problems trying to POST data. For this reason, whenever
  81.  * the Content-Type is application/x-www-form-urlencoded getOutputStream()
  82.  * will buffer the data before sending it so as prevent chunking. If you
  83.  * are sending requests with a different Content-Type and are experiencing
  84.  * problems then you may want to try setting the system property
  85.  * <var>HTTPClient.dontChunkRequests</var> to <var>true</var> (this needs
  86.  * to be done either on the command line or somewhere in the code before
  87.  * the first URLConnection.openConnection() is invoked).
  88.  *
  89.  * <P>A second potential incompatibility is that the HTTPClient aggresively
  90.  * resuses connections, and can do so more often that Sun's client. This
  91.  * can cause problems if you send multiple requests, and the first one has
  92.  * a long response. In this case (assuming the server allows the connection
  93.  * to be used for multiple requests) the responses to second, third, etc
  94.  * request won't be received until the first response has been completely
  95.  * read. With Sun's client on the other hand you may not experience this,
  96.  * as it may not be able to keep the connection open and there may create
  97.  * multiple connections for the requests. This allows the responses to the
  98.  * second, third, etc requests to be read before the first response has
  99.  * completed. <strong>Note:</strong> whether this will happen depends on
  100.  * details of the resource being requested and the server. In many cases
  101.  * the HTTPClient and Sun's client will exhibit the same behaviour. Also,
  102.  * applications which depend on being able to read the second response
  103.  * before the first one has completed must be considered broken, because
  104.  * A) this behaviour cannot be relied upon even in Sun's current client,
  105.  * and B) Sun's implementation will exhibit the same problem if they ever
  106.  * switch to HTTP/1.1.
  107.  *
  108.  * @version 0.3-3  18/06/1999
  109.  * @author Ronald Tschal鋜
  110.  * @since V0.3
  111.  */
  112. public class HttpURLConnection
  113. extends sun.net.www.protocol.http.HttpURLConnection
  114. implements GlobalConstants
  115. {
  116.     /** a list of HTTPConnections */
  117.     private static Hashtable  connections = new Hashtable();
  118.     /** the current connection */
  119.     private HTTPConnection    con;
  120.     /** the cached url.toString() */
  121.     private String            urlString;
  122.     /** the resource */
  123.     private String            resource;
  124.     /** the current method */
  125.     private String            method;
  126.     /** has the current method been set via setRequestMethod()? */
  127.     private boolean           method_set;
  128.     /** the default request headers */
  129.     private static NVPair[]   default_headers = new NVPair[0];
  130.     /** the request headers */
  131.     private NVPair[]          headers;
  132.     /** the response */
  133.     private HTTPResponse      resp;
  134.     /** is the redirection module activated for this instance? */
  135.     private boolean           do_redir;
  136.     /** the RedirectionModule class */
  137.     private static Class      redir_mod;
  138.     /** the output stream used for POST and PUT */
  139.     private OutputStream      output_stream;
  140.     /** HotJava hacks */
  141.     private static boolean    in_hotjava = false;
  142.     static
  143.     {
  144. try
  145. {
  146.     String browser = System.getProperty("browser");
  147.     if (browser != null  &&  browser.equals("HotJava"))
  148. in_hotjava = true;
  149. }
  150. catch (SecurityException se)
  151.     { }
  152. // The default allowUserAction in java.net.URLConnection is
  153. // false.
  154. try
  155. {
  156.     if (Boolean.getBoolean("HTTPClient.HttpURLConnection.AllowUI")  ||
  157. in_hotjava)
  158. setDefaultAllowUserInteraction(true);
  159. }
  160. catch (SecurityException se)
  161.     { }
  162. // get the RedirectionModule class
  163. try
  164.     { redir_mod = Class.forName("HTTPClient.RedirectionModule"); }
  165. catch (ClassNotFoundException cnfe)
  166.     { throw new NoClassDefFoundError(cnfe.getMessage()); }
  167. // Set the User-Agent if the http.agent property is set
  168. try
  169. {
  170.     String agent = System.getProperty("http.agent");
  171.     if (agent != null)
  172. setDefaultRequestProperty("User-Agent", agent);
  173. }
  174. catch (SecurityException se)
  175.     { }
  176.     }
  177.     // Constructors
  178.     private static String non_proxy_hosts = "";
  179.     private static String proxy_host = "";
  180.     private static int    proxy_port = -1;
  181.     /**
  182.      * Construct a connection to the specified url. A cache of
  183.      * HTTPConnections is used to maximize the reuse of these across
  184.      * multiple HttpURLConnections.
  185.      *
  186.      * <BR>The default method is "GET".
  187.      *
  188.      * @param url the url of the request
  189.      * @exception ProtocolNotSuppException if the protocol is not supported
  190.      */
  191.     public HttpURLConnection(URL url)
  192.     throws ProtocolNotSuppException, IOException
  193.     {
  194. super(url, null);
  195. // first read proxy properties and set
  196.         try
  197.         {
  198.             String hosts = System.getProperty("http.nonProxyHosts", "");
  199.     if (!hosts.equalsIgnoreCase(non_proxy_hosts))
  200.     {
  201. connections.clear();
  202. non_proxy_hosts = hosts;
  203. String[] list = Util.splitProperty(hosts);
  204. for (int idx=0; idx<list.length; idx++)
  205.     HTTPConnection.dontProxyFor(list[idx]);
  206.     }
  207.         }
  208.         catch (ParseException pe)
  209.     { throw new IOException(pe.toString()); }
  210.         catch (SecurityException se)
  211.             { }
  212. try
  213. {
  214.     String host = System.getProperty("http.proxyHost", "");
  215.     int port = Integer.getInteger("http.proxyPort", -1).intValue();
  216.     if (!host.equalsIgnoreCase(proxy_host)  ||  port != proxy_port)
  217.     {
  218. connections.clear();
  219. proxy_host = host;
  220. proxy_port = port;
  221. HTTPConnection.setProxyServer(host, port);
  222.     }
  223. }
  224. catch (SecurityException se)
  225.     { }
  226. // now setup stuff
  227. con           = getConnection(url);
  228. method        = "GET";
  229. method_set    = false;
  230. resource      = url.getFile();
  231. headers       = default_headers;
  232. do_redir      = getFollowRedirects();
  233. output_stream = null;
  234. urlString     = url.toString();
  235.     }
  236.     /**
  237.      * Returns an HTTPConnection. A cache of connections is kept and first
  238.      * consulted; only when the cache lookup fails is a new one created
  239.      * and added to the cache.
  240.      *
  241.      * @param url the url
  242.      * @return an HTTPConnection
  243.      * @exception ProtocolNotSuppException if the protocol is not supported
  244.      */
  245.     private HTTPConnection getConnection(URL url)
  246.     throws ProtocolNotSuppException
  247.     {
  248. // try the cache, using the host name
  249. String php = url.getProtocol() + ":" + url.getHost() + ":" +
  250.      ((url.getPort() != -1) ? url.getPort() :
  251. URI.defaultPort(url.getProtocol()));
  252. php = php.toLowerCase();
  253. HTTPConnection con = (HTTPConnection) connections.get(php);
  254. if (con != null)  return con;
  255. // Not in cache, so create new one and cache it
  256. con = new HTTPConnection(url);
  257. connections.put(php, con);
  258. return con;
  259.     }
  260.     // Methods
  261.     /**
  262.      * Sets the request method (e.g. "PUT" or "HEAD"). Can only be set
  263.      * before connect() is called.
  264.      *
  265.      * @param method the http method.
  266.      * @exception ProtocolException if already connected.
  267.      */
  268.     public void setRequestMethod(String method)  throws ProtocolException
  269.     {
  270. if (connected)
  271.     throw new ProtocolException("Already connected!");
  272. Log.write(Log.URLC, "URLC:  (" + urlString + ") Setting request method: " +
  273.     method);
  274. this.method = method.trim().toUpperCase();
  275. method_set  = true;
  276.     }
  277.     /**
  278.      * Return the request method used.
  279.      *
  280.      * @return the http method.
  281.      */
  282.     public String getRequestMethod()
  283.     {
  284. return method;
  285.     }
  286.     /**
  287.      * Get the response code. Calls connect() if not connected.
  288.      *
  289.      * @return the http response code returned.
  290.      */
  291.     public int getResponseCode()  throws IOException
  292.     {
  293. if (!connected)  connect();
  294. try
  295. {
  296.     if (in_hotjava  &&  resp.getStatusCode() >= 300)
  297.     {
  298. try
  299.     { resp.getData(); } // force response stream to be read
  300. catch (InterruptedIOException iioe)
  301.     { disconnect(); }
  302.     }
  303.     return resp.getStatusCode();
  304. }
  305. catch (ModuleException me)
  306.     { throw new IOException(me.toString()); }
  307.     }
  308.     /**
  309.      * Get the response message describing the response code. Calls connect()
  310.      * if not connected.
  311.      *
  312.      * @return the http response message returned with the response code.
  313.      */
  314.     public String getResponseMessage()  throws IOException
  315.     {
  316. if (!connected)  connect();
  317. try
  318.     { return resp.getReasonLine(); }
  319. catch (ModuleException me)
  320.     { throw new IOException(me.toString()); }
  321.     }
  322.     /**
  323.      * Get the value part of a header. Calls connect() if not connected.
  324.      *
  325.      * @param  name the of the header.
  326.      * @return the value of the header, or null if no such header was returned.
  327.      */
  328.     public String getHeaderField(String name)
  329.     {
  330. try
  331. {
  332.     if (!connected)  connect();
  333.     return resp.getHeader(name);
  334. }
  335. catch (Exception e)
  336.     { return null; }
  337.     }
  338.     /**
  339.      * Get the value part of a header and converts it to an int. If the
  340.      * header does not exist or if its value could not be converted to an
  341.      * int then the default is returned. Calls connect() if not connected.
  342.      *
  343.      * @param  name the of the header.
  344.      * @param  def  the default value to return in case of an error.
  345.      * @return the value of the header, or null if no such header was returned.
  346.      */
  347.     public int getHeaderFieldInt(String name, int def)
  348.     {
  349. try
  350. {
  351.     if (!connected)  connect();
  352.     return resp.getHeaderAsInt(name);
  353. }
  354. catch (Exception e)
  355.     { return def; }
  356.     }
  357.     /**
  358.      * Get the value part of a header, interprets it as a date and converts
  359.      * it to a long representing the number of milliseconds since 1970. If
  360.      * the header does not exist or if its value could not be converted to a
  361.      * date then the default is returned. Calls connect() if not connected.
  362.      *
  363.      * @param  name the of the header.
  364.      * @param  def  the default value to return in case of an error.
  365.      * @return the value of the header, or def in case of an error.
  366.      */
  367.     public long getHeaderFieldDate(String name, long def)
  368.     {
  369. try
  370. {
  371.     if (!connected)  connect();
  372.     return resp.getHeaderAsDate(name).getTime();
  373. }
  374. catch (Exception e)
  375.     { return def; }
  376.     }
  377.     private String[] hdr_keys, hdr_values;
  378.     /**
  379.      * Gets header name of the n-th header. Calls connect() if not connected.
  380.      * The name of the 0-th header is <var>null</var>, even though it the
  381.      * 0-th header has a value.
  382.      *
  383.      * @param n which header to return.
  384.      * @return the header name, or null if not that many headers.
  385.      */
  386.     public String getHeaderFieldKey(int n)
  387.     {
  388. if (hdr_keys == null)
  389.     fill_hdr_arrays();
  390. if (n >= 0  &&  n < hdr_keys.length)
  391.     return hdr_keys[n];
  392. else
  393.     return null;
  394.     }
  395.     /**
  396.      * Gets header value of the n-th header. Calls connect() if not connected.
  397.      * The value of 0-th header is the Status-Line (e.g. "HTTP/1.1 200 Ok").
  398.      *
  399.      * @param n which header to return.
  400.      * @return the header value, or null if not that many headers.
  401.      */
  402.     public String getHeaderField(int n)
  403.     {
  404. if (hdr_values == null)
  405.     fill_hdr_arrays();
  406. if (n >= 0  &&  n < hdr_values.length)
  407.     return hdr_values[n];
  408. else
  409.     return null;
  410.     }
  411.     /**
  412.      * Cache the list of headers.
  413.      */
  414.     private void fill_hdr_arrays()
  415.     {
  416. try
  417. {
  418.     if (!connected)  connect();
  419.     // count number of headers
  420.     int num = 1;
  421.     Enumeration enum = resp.listHeaders();
  422.     while (enum.hasMoreElements())
  423.     {
  424. num++;
  425. enum.nextElement();
  426.     }
  427.     // allocate arrays
  428.     hdr_keys   = new String[num];
  429.     hdr_values = new String[num];
  430.     // fill arrays
  431.     enum = resp.listHeaders();
  432.     for (int idx=1; idx<num; idx++)
  433.     {
  434. hdr_keys[idx]   = (String) enum.nextElement();
  435. hdr_values[idx] = resp.getHeader(hdr_keys[idx]);
  436.     }
  437.     // the 0'th field is special
  438.     hdr_values[0] = resp.getVersion() + " " + resp.getStatusCode() +
  439.     " " + resp.getReasonLine();
  440. }
  441. catch (Exception e)
  442.     { hdr_keys = hdr_values = new String[0]; }
  443.     }
  444.     /**
  445.      * Gets an input stream from which the data in the response may be read.
  446.      * Calls connect() if not connected.
  447.      *
  448.      * @return an InputStream
  449.      * @exception ProtocolException if input not enabled.
  450.      * @see java.net.URLConnection#setDoInput(boolean)
  451.      */
  452.     public InputStream getInputStream()  throws IOException
  453.     {
  454. if (!doInput)
  455.     throw new ProtocolException("Input not enabled! (use setDoInput(true))");
  456. if (!connected)  connect();
  457. InputStream stream;
  458. try
  459. {
  460.     stream = resp.getInputStream();
  461.     if (resp.pe != null  &&  resp.getHeader("Content-length") != null)
  462.     {
  463. try
  464.     { stream = new sun.net.www.MeteredStream(stream, resp.pe); }
  465. catch (Throwable t)
  466. {
  467.     Log.write(Log.URLC, "URLC:  (" + urlString +
  468. ") error trying to create metered stream: ", t);
  469. }
  470.     }
  471.     else
  472. // some things expect this stream to support mark/reset
  473. stream = new BufferedInputStream(stream);
  474. }
  475. catch (ModuleException e)
  476.     { throw new IOException(e.toString()); }
  477. return stream;
  478.     }
  479.     /**
  480.      * Returns the error stream if the connection failed
  481.      * but the server sent useful data nonetheless.
  482.      *
  483.      * <P>This method will not cause a connection to be initiated.
  484.      *
  485.      * @return an InputStream, or null if either the connection hasn't
  486.      *         been established yet or no error occured
  487.      * @see java.net.HttpURLConnection#getErrorStream()
  488.      * @since V0.3-1
  489.      */
  490.     public InputStream getErrorStream()
  491.     {
  492. try
  493. {
  494.     if (!doInput  ||  !connected  ||  resp.getStatusCode() < 300  ||
  495. resp.getHeaderAsInt("Content-length") <= 0)
  496. return null;
  497.     return resp.getInputStream();
  498. }
  499. catch (Exception e)
  500.     { return null; }
  501.     }
  502.     /**
  503.      * Gets an output stream which can be used send an entity with the
  504.      * request. Can be called multiple times, in which case always the
  505.      * same stream is returned.
  506.      *
  507.      * <P>The default request method changes to "POST" when this method is
  508.      * called. Cannot be called after connect().
  509.      *
  510.      * <P>If no Content-type has been set it defaults to
  511.      * <var>application/x-www-form-urlencoded</var>. Furthermore, if the
  512.      * Content-type is <var>application/x-www-form-urlencoded</var> then all
  513.      * output will be collected in a buffer before sending it to the server;
  514.      * otherwise an HttpOutputStream is used.
  515.      *
  516.      * @return an OutputStream
  517.      * @exception ProtocolException if already connect()'ed, if output is not
  518.      *                              enabled or if the request method does not
  519.      *                              support output.
  520.      * @see java.net.URLConnection#setDoOutput(boolean)
  521.      * @see HTTPClient.HttpOutputStream
  522.      */
  523.     public synchronized OutputStream getOutputStream()  throws IOException
  524.     {
  525. if (connected)
  526.     throw new ProtocolException("Already connected!");
  527. if (!doOutput)
  528.     throw new ProtocolException("Output not enabled! (use setDoOutput(true))");
  529. if (!method_set)
  530.     method = "POST";
  531. else if (method.equals("HEAD")  ||  method.equals("GET")  ||
  532.  method.equals("TRACE"))
  533.     throw new ProtocolException("Method "+method+" does not support output!");
  534. if (getRequestProperty("Content-type") == null)
  535.     setRequestProperty("Content-type", "application/x-www-form-urlencoded");
  536. if (output_stream == null)
  537. {
  538.     Log.write(Log.URLC, "URLC:  (" + urlString + ") creating output stream");
  539.     String cl = getRequestProperty("Content-Length");
  540.     if (cl != null)
  541. output_stream = new HttpOutputStream(Integer.parseInt(cl.trim()));
  542.     else
  543.     {
  544. // Hack: because of restrictions when using true output streams
  545. // and because form-data is usually quite limited in size, we
  546. // first collect all data before sending it if this is
  547. // form-data.
  548. if (getRequestProperty("Content-type").equals(
  549. "application/x-www-form-urlencoded"))
  550.     output_stream = new ByteArrayOutputStream(300);
  551. else
  552.     output_stream = new HttpOutputStream();
  553.     }
  554.     if (output_stream instanceof HttpOutputStream)
  555. connect();
  556. }
  557. return output_stream;
  558.     }
  559.     /**
  560.      * Gets the url for this connection. If we're connect()'d and the request
  561.      * was redirected then the url returned is that of the final request.
  562.      *
  563.      * @return the final url, or null if any exception occured.
  564.      */
  565.     public URL getURL()
  566.     {
  567. if (connected)
  568. {
  569.     try
  570.     {
  571. if (resp.getEffectiveURL() != null)
  572.     return resp.getEffectiveURL();
  573.     }
  574.     catch (Exception e)
  575. { return null; }
  576. }
  577. return url;
  578.     }
  579.     /**
  580.      * Sets the <var>If-Modified-Since</var> header.
  581.      *
  582.      * @param time the number of milliseconds since 1970.
  583.      */
  584.     public void setIfModifiedSince(long time)
  585.     {
  586. super.setIfModifiedSince(time);
  587. setRequestProperty("If-Modified-Since", Util.httpDate(new Date(time)));
  588.     }
  589.     /**
  590.      * Sets an arbitrary request header.
  591.      *
  592.      * @param name  the name of the header.
  593.      * @param value the value for the header.
  594.      */
  595.     public void setRequestProperty(String name, String value)
  596.     {
  597. Log.write(Log.URLC, "URLC:  (" + urlString + ") Setting request property: " +
  598.     name + " : " + value);
  599. int idx;
  600. for (idx=0; idx<headers.length; idx++)
  601. {
  602.     if (headers[idx].getName().equalsIgnoreCase(name))
  603. break;
  604. }
  605. if (idx == headers.length)
  606.     headers = Util.resizeArray(headers, idx+1);
  607. headers[idx] = new NVPair(name, value);
  608.     }
  609.     /**
  610.      * Gets the value of a given request header.
  611.      *
  612.      * @param name  the name of the header.
  613.      * @return the value part of the header, or null if no such header.
  614.      */
  615.     public String getRequestProperty(String name)
  616.     {
  617. for (int idx=0; idx<headers.length; idx++)
  618. {
  619.     if (headers[idx].getName().equalsIgnoreCase(name))
  620. return headers[idx].getValue();
  621. }
  622. return null;
  623.     }
  624.     /**
  625.      * Sets an arbitrary default request header. All headers set here are
  626.      * automatically sent with each request.
  627.      *
  628.      * @param name  the name of the header.
  629.      * @param value the value for the header.
  630.      */
  631.     public static void setDefaultRequestProperty(String name, String value)
  632.     {
  633. Log.write(Log.URLC, "URLC:  Setting default request property: " +
  634.     name + " : " + value);
  635. int idx;
  636. for (idx=0; idx<default_headers.length; idx++)
  637. {
  638.     if (default_headers[idx].getName().equalsIgnoreCase(name))
  639. break;
  640. }
  641. if (idx == default_headers.length)
  642.     default_headers = Util.resizeArray(default_headers, idx+1);
  643. default_headers[idx] = new NVPair(name, value);
  644.     }
  645.     /**
  646.      * Gets the value for a given default request header.
  647.      *
  648.      * @param name  the name of the header.
  649.      * @return the value part of the header, or null if no such header.
  650.      */
  651.     public static String getDefaultRequestProperty(String name)
  652.     {
  653. for (int idx=0; idx<default_headers.length; idx++)
  654. {
  655.     if (default_headers[idx].getName().equalsIgnoreCase(name))
  656. return default_headers[idx].getValue();
  657. }
  658. return null;
  659.     }
  660.     /**
  661.      * Enables or disables the automatic handling of redirection responses
  662.      * for this instance only. Cannot be called after <code>connect()</code>.
  663.      *
  664.      * @param set enables automatic redirection handling if true.
  665.      */
  666.     public void setInstanceFollowRedirects(boolean set)
  667.     {
  668. if (connected)
  669.     throw new IllegalStateException("Already connected!");
  670. do_redir = set;
  671.     }
  672.     /**
  673.      * @return true if automatic redirection handling for this instance is
  674.      *              enabled.
  675.      */
  676.     public boolean getInstanceFollowRedirects()
  677.     {
  678. return do_redir;
  679.     }
  680.     /**
  681.      * Connects to the server (if connection not still kept alive) and
  682.      * issues the request.
  683.      */
  684.     public synchronized void connect()  throws IOException
  685.     {
  686. if (connected)  return;
  687. Log.write(Log.URLC, "URLC:  (" + urlString + ") Connecting ...");
  688. // useCaches TBD!!!
  689. synchronized(con)
  690. {
  691.     con.setAllowUserInteraction(allowUserInteraction);
  692.     if (do_redir)
  693. con.addModule(redir_mod, 2);
  694.     else
  695. con.removeModule(redir_mod);
  696.     try
  697.     {
  698. if (output_stream instanceof ByteArrayOutputStream)
  699.     resp = con.ExtensionMethod(method, resource,
  700. ((ByteArrayOutputStream) output_stream).toByteArray(),
  701.      headers);
  702. else
  703.     resp = con.ExtensionMethod(method, resource,
  704.     (HttpOutputStream) output_stream, headers);
  705.     }
  706.     catch (ModuleException e)
  707. { throw new IOException(e.toString()); }
  708. }
  709. connected = true;
  710. try
  711.     { resp.setProgressEntry(new sun.net.ProgressEntry(url.getFile(), null)); }
  712. catch (Throwable t)
  713. {
  714.     Log.write(Log.URLC, "URLC:  (" + urlString +
  715. ") error trying to create and set progress entry: ", t);
  716. }
  717.     }
  718.     /**
  719.      * Closes all the connections to this server.
  720.      */
  721.     public void disconnect()
  722.     {
  723. Log.write(Log.URLC, "URLC:  (" + urlString + ") Disconnecting ...");
  724. con.stop();
  725. if (resp != null)
  726.     resp.unsetProgressEntry();
  727.     }
  728.     public void finalize()
  729.     {
  730. if (resp != null)
  731.     resp.unsetProgressEntry();
  732. super.finalize();
  733.     }
  734.     /**
  735.      * Shows if request are being made through an http proxy or directly.
  736.      *
  737.      * @return true if an http proxy is being used.
  738.      */
  739.     public boolean usingProxy()
  740.     {
  741. return (con.getProxyHost() != null);
  742.     }
  743.     /**
  744.      * produces a string.
  745.      * @return a string containing the HttpURLConnection
  746.      */
  747.     public String toString()
  748.     {
  749. return getClass().getName() + "[" + url + "]";
  750.     }
  751. }