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

Java Develop

Development Platform:

Java

  1. /*
  2.  * @(#)HTTPResponse.java 0.3-3 06/05/2001
  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.ByteArrayInputStream;
  37. import java.net.URL;
  38. import java.util.Date;
  39. import java.util.Enumeration;
  40. /**
  41.  * This defines the http-response class returned by the requests. It's
  42.  * basically a wrapper around the Response class which first lets all
  43.  * the modules handle the response before finally giving the info to
  44.  * the user.
  45.  *
  46.  * @version 0.3-3  06/05/2001
  47.  * @author Ronald Tschal鋜
  48.  * @since 0.3
  49.  */
  50. public class HTTPResponse implements HTTPClientModuleConstants
  51. {
  52.     /** the list of modules */
  53.     private HTTPClientModule[]  modules;
  54.     /** the timeout for reads */
  55.     private int          timeout;
  56.     /** the request */
  57.     private Request      request = null;
  58.     /** the current response */
  59.             Response     response = null;
  60.     /** the HttpOutputStream to synchronize on */
  61.     private HttpOutputStream out_stream = null;
  62.     /** our input stream from the stream demux */
  63.     private InputStream  inp_stream;
  64.     /** the status code returned. */
  65.     private int          StatusCode;
  66.     /** the reason line associated with the status code. */
  67.     private String       ReasonLine;
  68.     /** the HTTP version of the response. */
  69.     private String       Version;
  70.     /** the original URI used. */
  71.     private URI          OriginalURI = null;
  72.     /** the final URI of the document. */
  73.     private URI          EffectiveURI = null;
  74.     /** any headers which were received and do not fit in the above list. */
  75.     private CIHashtable  Headers = null;
  76.     /** any trailers which were received and do not fit in the above list. */
  77.     private CIHashtable  Trailers = null;
  78.     /** the ContentLength of the data. */
  79.     private int          ContentLength = -1;
  80.     /** the data (body) returned. */
  81.     private byte[]       Data = null;
  82.     /** signals if we have got and parsed the headers yet? */
  83.     private boolean      initialized = false;
  84.     /** signals if we have got the trailers yet? */
  85.     private boolean      got_trailers = false;
  86.     /** marks this response as aborted (stop() in HTTPConnection) */
  87.     private boolean      aborted = false;
  88.     /** should the request be retried by the application? */
  89.     private boolean      retry = false;
  90.     /** the method used in the request */
  91.     private String       method = null;
  92.     // Constructors
  93.     /**
  94.      * Creates a new HTTPResponse.
  95.      *
  96.      * @param modules the list of modules handling this response
  97.      * @param timeout the timeout to be used on stream read()'s
  98.      */
  99.     HTTPResponse(HTTPClientModule[] modules, int timeout, Request orig)
  100.     {
  101. this.modules = modules;
  102. this.timeout = timeout;
  103. try
  104. {
  105.     int qp = orig.getRequestURI().indexOf('?');
  106.     this.OriginalURI = new URI(orig.getConnection().getProtocol(),
  107.        null,
  108.        orig.getConnection().getHost(),
  109.        orig.getConnection().getPort(),
  110.        qp < 0 ? orig.getRequestURI() :
  111.  orig.getRequestURI().substring(0, qp),
  112.        qp < 0 ? null :
  113.  orig.getRequestURI().substring(qp+1),
  114.        null);
  115. }
  116. catch (ParseException pe)
  117.     { }
  118. this.method = orig.getMethod();
  119.     }
  120.     /**
  121.      * @param req the request
  122.      * @param resp the response
  123.      */
  124.     void set(Request req, Response resp)
  125.     {
  126. this.request   = req;
  127. this.response  = resp;
  128. resp.http_resp = this;
  129. resp.timeout   = timeout;
  130. this.aborted   = resp.final_resp;
  131.     }
  132.     /**
  133.      * @param req the request
  134.      * @param resp the response
  135.      */
  136.     void set(Request req, HttpOutputStream out_stream)
  137.     {
  138. this.request    = req;
  139. this.out_stream = out_stream;
  140.     }
  141.     // Methods
  142.     /**
  143.      * Give the status code for this request. These are grouped as follows:
  144.      * <UL>
  145.      *   <LI> 1xx - Informational (new in HTTP/1.1)
  146.      *   <LI> 2xx - Success
  147.      *   <LI> 3xx - Redirection
  148.      *   <LI> 4xx - Client Error
  149.      *   <LI> 5xx - Server Error
  150.      * </UL>
  151.      *
  152.      * @exception IOException if any exception occurs on the socket.
  153.      * @exception ModuleException if any module encounters an exception.
  154.      */
  155.     public final int getStatusCode()  throws IOException, ModuleException
  156.     {
  157. if (!initialized)  handleResponse();
  158. return StatusCode;
  159.     }
  160.     /**
  161.      * Give the reason line associated with the status code.
  162.      *
  163.      * @exception IOException If any exception occurs on the socket.
  164.      * @exception ModuleException if any module encounters an exception.
  165.      */
  166.     public final String getReasonLine()  throws IOException, ModuleException
  167.     {
  168. if (!initialized)  handleResponse();
  169. return ReasonLine;
  170.     }
  171.     /**
  172.      * Get the HTTP version used for the response.
  173.      *
  174.      * @exception IOException If any exception occurs on the socket.
  175.      * @exception ModuleException if any module encounters an exception.
  176.      */
  177.     public final String getVersion()  throws IOException, ModuleException
  178.     {
  179. if (!initialized)  handleResponse();
  180. return Version;
  181.     }
  182.     /**
  183.      * Get the name and type of server.
  184.      *
  185.      * @deprecated This method is a remnant of V0.1; use
  186.      *             <code>getHeader("Server")</code> instead.
  187.      * @see #getHeader(java.lang.String)
  188.      * @exception IOException If any exception occurs on the socket.
  189.      * @exception ModuleException if any module encounters an exception.
  190.      */
  191.     public final String getServer()  throws IOException, ModuleException
  192.     {
  193. if (!initialized)  handleResponse();
  194. return getHeader("Server");
  195.     }
  196.     /**
  197.      * Get the original URI used in the request.
  198.      *
  199.      * @return the URI used in primary request
  200.      */
  201.     public final URI getOriginalURI()
  202.     {
  203. return OriginalURI;
  204.     }
  205.     /**
  206.      * Get the final URL of the document. This is set if the original
  207.      * request was deferred via the "moved" (301, 302, or 303) return
  208.      * status.
  209.      *
  210.      * @return the effective URL, or null if no redirection occured
  211.      * @exception IOException If any exception occurs on the socket.
  212.      * @exception ModuleException if any module encounters an exception.
  213.      * @deprecated use getEffectiveURI() instead
  214.      * @see #getEffectiveURI
  215.      */
  216.     public final URL getEffectiveURL()  throws IOException, ModuleException
  217.     {
  218. if (!initialized)  handleResponse();
  219. if (EffectiveURI != null)
  220.     return EffectiveURI.toURL();
  221. return null;
  222.     }
  223.     /**
  224.      * Get the final URI of the document. If the request was redirected
  225.      * via the "moved" (301, 302, 303, or 307) return status this returns
  226.      * the URI used in the last redirection; otherwise it returns the
  227.      * original URI.
  228.      *
  229.      * @return the effective URI
  230.      * @exception IOException If any exception occurs on the socket.
  231.      * @exception ModuleException if any module encounters an exception.
  232.      */
  233.     public final URI getEffectiveURI()  throws IOException, ModuleException
  234.     {
  235. if (!initialized)  handleResponse();
  236. if (EffectiveURI != null)
  237.     return EffectiveURI;
  238. return OriginalURI;
  239.     }
  240.     /**
  241.      * Retrieves the value for a given header.
  242.      *
  243.      * @param  hdr the header name.
  244.      * @return the value for the header, or null if non-existent.
  245.      * @exception IOException If any exception occurs on the socket.
  246.      * @exception ModuleException if any module encounters an exception.
  247.      */
  248.     public String getHeader(String hdr)  throws IOException, ModuleException
  249.     {
  250. if (!initialized)  handleResponse();
  251. return (String) Headers.get(hdr.trim());
  252.     }
  253.     /**
  254.      * Retrieves the value for a given header. The value is parsed as an
  255.      * int.
  256.      *
  257.      * @param  hdr the header name.
  258.      * @return the value for the header if the header exists
  259.      * @exception NumberFormatException if the header's value is not a number
  260.      *                                  or if the header does not exist.
  261.      * @exception IOException if any exception occurs on the socket.
  262.      * @exception ModuleException if any module encounters an exception.
  263.      */
  264.     public int getHeaderAsInt(String hdr)
  265. throws IOException, ModuleException, NumberFormatException
  266.     {
  267. String val = getHeader(hdr);
  268. if (val == null)
  269.     throw new NumberFormatException("null");
  270. return Integer.parseInt(val);
  271.     }
  272.     /**
  273.      * Retrieves the value for a given header. The value is parsed as a
  274.      * date; if this fails it is parsed as a long representing the number
  275.      * of seconds since 12:00 AM, Jan 1st, 1970. If this also fails an
  276.      * exception is thrown.
  277.      * <br>Note: When sending dates use Util.httpDate().
  278.      *
  279.      * @param  hdr the header name.
  280.      * @return the value for the header, or null if non-existent.
  281.      * @exception IllegalArgumentException if the header's value is neither a
  282.      *            legal date nor a number.
  283.      * @exception IOException if any exception occurs on the socket.
  284.      * @exception ModuleException if any module encounters an exception.
  285.      */
  286.     public Date getHeaderAsDate(String hdr)
  287. throws IOException, IllegalArgumentException, ModuleException
  288.     {
  289. String raw_date = getHeader(hdr);
  290. if (raw_date == null) return null;
  291. // asctime() format is missing an explicit GMT specifier
  292. if (raw_date.toUpperCase().indexOf("GMT") == -1  &&
  293.     raw_date.indexOf(' ') > 0)
  294.     raw_date += " GMT";
  295. Date   date;
  296. try
  297.     { date = Util.parseHttpDate(raw_date); }
  298. catch (IllegalArgumentException iae)
  299. {
  300.     // some servers erroneously send a number, so let's try that
  301.     long time;
  302.     try
  303. { time = Long.parseLong(raw_date); }
  304.     catch (NumberFormatException nfe)
  305. { throw iae; } // give up
  306.     if (time < 0)  time = 0;
  307.     date = new Date(time * 1000L);
  308. }
  309. return date;
  310.     }
  311.     /**
  312.      * Returns an enumeration of all the headers available via getHeader().
  313.      *
  314.      * @exception IOException If any exception occurs on the socket.
  315.      * @exception ModuleException if any module encounters an exception.
  316.      */
  317.     public Enumeration listHeaders()  throws IOException, ModuleException
  318.     {
  319. if (!initialized)  handleResponse();
  320. return Headers.keys();
  321.     }
  322.     /**
  323.      * Retrieves the value for a given trailer. This should not be invoked
  324.      * until all response data has been read. If invoked before it will
  325.      * call <code>getData()</code> to force the data to be read.
  326.      *
  327.      * @param  trailer the trailer name.
  328.      * @return the value for the trailer, or null if non-existent.
  329.      * @exception IOException If any exception occurs on the socket.
  330.      * @exception ModuleException if any module encounters an exception.
  331.      * @see #getData()
  332.      */
  333.     public String getTrailer(String trailer) throws IOException, ModuleException
  334.     {
  335. if (!got_trailers)  getTrailers();
  336. return (String) Trailers.get(trailer.trim());
  337.     }
  338.     /**
  339.      * Retrieves the value for a given tailer. The value is parsed as an
  340.      * int.
  341.      *
  342.      * @param  trailer the tailer name.
  343.      * @return the value for the trailer if the trailer exists
  344.      * @exception NumberFormatException if the trailer's value is not a number
  345.      *                                  or if the trailer does not exist.
  346.      * @exception IOException if any exception occurs on the socket.
  347.      * @exception ModuleException if any module encounters an exception.
  348.      */
  349.     public int getTrailerAsInt(String trailer)
  350. throws IOException, ModuleException, NumberFormatException
  351.     {
  352. String val = getTrailer(trailer);
  353. if (val == null)
  354.     throw new NumberFormatException("null");
  355. return Integer.parseInt(val);
  356.     }
  357.     /**
  358.      * Retrieves the value for a given trailer. The value is parsed as a
  359.      * date; if this fails it is parsed as a long representing the number
  360.      * of seconds since 12:00 AM, Jan 1st, 1970. If this also fails an
  361.      * IllegalArgumentException is thrown.
  362.      * <br>Note: When sending dates use Util.httpDate().
  363.      *
  364.      * @param  trailer the trailer name.
  365.      * @return the value for the trailer, or null if non-existent.
  366.      * @exception IllegalArgumentException if the trailer's value is neither a
  367.      *            legal date nor a number.
  368.      * @exception IOException if any exception occurs on the socket.
  369.      * @exception ModuleException if any module encounters an exception.
  370.      */
  371.     public Date getTrailerAsDate(String trailer)
  372. throws IOException, IllegalArgumentException, ModuleException
  373.     {
  374. String raw_date = getTrailer(trailer);
  375. if (raw_date == null) return null;
  376. // asctime() format is missing an explicit GMT specifier
  377. if (raw_date.toUpperCase().indexOf("GMT") == -1  &&
  378.     raw_date.indexOf(' ') > 0)
  379.     raw_date += " GMT";
  380. Date   date;
  381. try
  382.     { date = Util.parseHttpDate(raw_date); }
  383. catch (IllegalArgumentException iae)
  384. {
  385.     // some servers erroneously send a number, so let's try that
  386.     long time;
  387.     try
  388. { time = Long.parseLong(raw_date); }
  389.     catch (NumberFormatException nfe)
  390. { throw iae; } // give up
  391.     if (time < 0)  time = 0;
  392.     date = new Date(time * 1000L);
  393. }
  394. return date;
  395.     }
  396.     /**
  397.      * Returns an enumeration of all the trailers available via getTrailer().
  398.      *
  399.      * @exception IOException If any exception occurs on the socket.
  400.      * @exception ModuleException if any module encounters an exception.
  401.      */
  402.     public Enumeration listTrailers()  throws IOException, ModuleException
  403.     {
  404. if (!got_trailers)  getTrailers();
  405. return Trailers.keys();
  406.     }
  407.     /**
  408.      * Reads all the response data into a byte array. Note that this method
  409.      * won't return until <em>all</em> the data has been received (so for
  410.      * instance don't invoke this method if the server is doing a server
  411.      * push). If <code>getInputStream()</code> had been previously invoked
  412.      * then this method only returns any unread data remaining on the stream
  413.      * and then closes it.
  414.      *
  415.      * <P>Note to the unwary: code like
  416.      *<PRE>
  417.      *     System.out.println("The data: " + resp.getData())
  418.      *</PRE>
  419.      * will probably not do what you want - use
  420.      *<PRE>
  421.      *     System.out.println("The data: " + resp.getText())
  422.      *</PRE>
  423.      * instead.
  424.      *
  425.      * @see #getInputStream()
  426.      * @return an array containing the data (body) returned. If no data
  427.      *         was returned then it's set to a zero-length array.
  428.      * @exception IOException If any io exception occured while reading
  429.      *       the data
  430.      * @exception ModuleException if any module encounters an exception.
  431.      */
  432.     public synchronized byte[] getData()  throws IOException, ModuleException
  433.     {
  434. if (!initialized)  handleResponse();
  435. if (Data == null)
  436. {
  437.     try
  438. { readResponseData(inp_stream); }
  439.     catch (InterruptedIOException ie) // don't intercept
  440. { throw ie; }
  441.     catch (IOException ioe)
  442.     {
  443. Log.write(Log.RESP, "HResp: ("" + method + " " +
  444.     OriginalURI.getPathAndQuery() + "")");
  445. Log.write(Log.RESP, "       ", ioe);
  446. try { inp_stream.close(); } catch (Exception e) { }
  447. throw ioe;
  448.     }
  449.     inp_stream.close();
  450. }
  451. return Data;
  452.     }
  453.     /**
  454.      * Reads all the response data into a buffer and turns it into a string
  455.      * using the appropriate character converter. Since this uses {@link
  456.      * #getData() getData()}, the caveats of that method apply here as well.
  457.      *
  458.      * @see #getData()
  459.      * @return the body as a String. If no data was returned then an empty
  460.      *         string is returned.
  461.      * @exception IOException If any io exception occured while reading
  462.      *       the data, or if the content is not text
  463.      * @exception ModuleException if any module encounters an exception.
  464.      * @exception ParseException if an error occured trying to parse the
  465.      *                           content-type header field
  466.      */
  467.     public synchronized String getText()
  468. throws IOException, ModuleException, ParseException
  469.     {
  470. String ct = getHeader("Content-Type");
  471. if (ct == null  ||  !ct.toLowerCase().startsWith("text/"))
  472.     throw new IOException("Content-Type `" + ct + "' is not a text type");
  473. String charset = Util.getParameter("charset", ct);
  474. if (charset == null)
  475.     charset = "ISO-8859-1";
  476. return new String(getData(), charset);
  477.     }
  478.     /**
  479.      * Gets an input stream from which the returned data can be read. Note
  480.      * that if <code>getData()</code> had been previously invoked it will
  481.      * actually return a ByteArrayInputStream created from that data.
  482.      *
  483.      * @see #getData()
  484.      * @return the InputStream.
  485.      * @exception IOException If any exception occurs on the socket.
  486.      * @exception ModuleException if any module encounters an exception.
  487.      */
  488.     public synchronized InputStream getInputStream()
  489.     throws IOException, ModuleException
  490.     {
  491. if (!initialized)  handleResponse();
  492. if (Data == null)
  493.     return inp_stream;
  494. else
  495. {
  496.     getData(); // ensure complete data is read
  497.     return new ByteArrayInputStream(Data);
  498. }
  499.     }
  500.     /**
  501.      * Should the request be retried by the application? If the application
  502.      * used an <var>HttpOutputStream</var> in the request then various
  503.      * modules (such as the redirection and authorization modules) are not
  504.      * able to resend the request themselves. Instead, it becomes the
  505.      * application's responsibility. The application can check this flag, and
  506.      * if it's set, resend the exact same request. The modules such as the
  507.      * RedirectionModule or AuthorizationModule will then recognize the resend
  508.      * and fix up or redirect the request as required (i.e. they defer their
  509.      * normal action until the resend).
  510.      *
  511.      * <P>If the application resends the request then it <strong>must</strong>
  512.      * use the same <var>HttpOutputStream</var> instance. This is because the
  513.      * modules use this to recognize the retried request and to perform the
  514.      * necessary work on the request before it's sent.
  515.      *
  516.      * <P>Here is a skeleton example of usage:
  517.      * <PRE>
  518.      *     OutputStream out = new HttpOutputStream(1234);
  519.      *     do
  520.      *     {
  521.      *         rsp = con.Post("/cgi-bin/my_cgi", out);
  522.      *         out.write(...);
  523.      *         out.close();
  524.      *     } while (rsp.retryRequest());
  525.      *
  526.      *     if (rsp.getStatusCode() >= 300)
  527.      *         ...
  528.      * </PRE>
  529.      *
  530.      * <P>Note that for this to ever return true, the java system property
  531.      * <var>HTTPClient.deferStreamed</var> must be set to true at the beginning
  532.      * of the application (before the HTTPConnection class is loaded). This
  533.      * prevents unwary applications from causing inadvertent memory leaks. If
  534.      * an application does set this, then it <em>must</em> resend any request
  535.      * whose response returns true here in order to prevent memory leaks (a
  536.      * switch to JDK 1.2 will allow us to use weak references and eliminate
  537.      * this problem).
  538.      *
  539.      * @return true if the request should be retried.
  540.      * @exception IOException If any exception occurs on the socket.
  541.      * @exception ModuleException if any module encounters an exception.
  542.      */
  543.     public boolean retryRequest()  throws IOException, ModuleException
  544.     {
  545. if (!initialized)
  546. {
  547.     try
  548. { handleResponse(); }
  549.     catch (RetryException re)
  550. { this.retry = response.retry; }
  551. }
  552. return retry;
  553.     }
  554.     /**
  555.      * produces a full list of headers and their values, one per line.
  556.      *
  557.      * @return a string containing the headers
  558.      */
  559.     public String toString()
  560.     {
  561. if (!initialized)
  562. {
  563.     try
  564. { handleResponse(); }
  565.     catch (Exception e)
  566.     {
  567. if (!(e instanceof InterruptedIOException))
  568. {
  569.     Log.write(Log.RESP, "HResp: ("" + method + " " +
  570.         OriginalURI.getPathAndQuery() + "")");
  571.     Log.write(Log.RESP, "       ", e);
  572. }
  573. return "Failed to read headers: " + e;
  574.     }
  575. }
  576. String nl = System.getProperty("line.separator", "n");
  577. StringBuffer str = new StringBuffer(Version);
  578. str.append(' ');
  579. str.append(StatusCode);
  580. str.append(' ');
  581. str.append(ReasonLine);
  582. str.append(nl);
  583. if (EffectiveURI != null)
  584. {
  585.     str.append("Effective-URI: ");
  586.     str.append(EffectiveURI);
  587.     str.append(nl);
  588. }
  589. Enumeration hdr_list = Headers.keys();
  590. while (hdr_list.hasMoreElements())
  591. {
  592.     String hdr = (String) hdr_list.nextElement();
  593.     str.append(hdr);
  594.     str.append(": ");
  595.     str.append(Headers.get(hdr));
  596.     str.append(nl);
  597. }
  598. return str.toString();
  599.     }
  600.     // Helper Methods
  601.     HTTPClientModule[] getModules()
  602.     {
  603. return modules;
  604.     }
  605.     /**
  606.      * Processes a Response. This is done by calling the response handler
  607.      * in each module. When all is done, the various fields of this instance
  608.      * are intialized from the last Response.
  609.      *
  610.      * @exception IOException if any handler throws an IOException.
  611.      * @exception ModuleException if any module encounters an exception.
  612.      * @return true if a new request was generated. This is used for internal
  613.      *         subrequests only
  614.      */
  615.     synchronized boolean handleResponse()  throws IOException, ModuleException
  616.     {
  617. if (initialized)  return false;
  618. /* first get the response if necessary */
  619. if (out_stream != null)
  620. {
  621.     response           = out_stream.getResponse();
  622.     response.http_resp = this;
  623.     out_stream         = null;
  624. }
  625. /* go through modules and handle them */
  626. doModules: while (true)
  627. {
  628. Phase1: for (int idx=0; idx<modules.length && !aborted; idx++)
  629. {
  630.     try
  631. { modules[idx].responsePhase1Handler(response, request); }
  632.     catch (RetryException re)
  633.     {
  634. if (re.restart)
  635.     continue doModules;
  636. else
  637.     throw re;
  638.     }
  639. }
  640. Phase2: for (int idx=0; idx<modules.length && !aborted; idx++)
  641. {
  642.             int sts = modules[idx].responsePhase2Handler(response, request);
  643.             switch (sts)
  644.             {
  645.                 case RSP_CONTINUE: // continue processing
  646.                     break;
  647.                 case RSP_RESTART: // restart response processing
  648.                     idx = -1;
  649.     continue doModules;
  650.                 case RSP_SHORTCIRC: // stop processing and return
  651.                     break doModules;
  652.                 case RSP_REQUEST: // go to phase 1
  653.                 case RSP_NEWCON_REQ: // process the request using a new con
  654.     response.getInputStream().close();
  655.     if (handle_trailers) invokeTrailerHandlers(true);
  656.     if (request.internal_subrequest)  return true;
  657.     request.getConnection().
  658. handleRequest(request, this, response, true);
  659.     if (initialized)  break doModules;
  660.                     idx = -1;
  661.     continue doModules;
  662.                 case RSP_SEND: // send the request immediately
  663.                 case RSP_NEWCON_SND: // send the request using a new con
  664.     response.getInputStream().close();
  665.     if (handle_trailers) invokeTrailerHandlers(true);
  666.     if (request.internal_subrequest)  return true;
  667.     request.getConnection().
  668. handleRequest(request, this, response, false);
  669.                     idx = -1;
  670.     continue doModules;
  671.                 default:                // not valid
  672.                     throw new Error("HTTPClient Internal Error: invalid status"+
  673.                                     " " + sts + " returned by module " +
  674.                                     modules[idx].getClass().getName());
  675.     }
  676. }
  677. Phase3: for (int idx=0; idx<modules.length && !aborted; idx++)
  678. {
  679.             modules[idx].responsePhase3Handler(response, request);
  680. }
  681. break doModules;
  682. }
  683. /* force a read on the response in case none of the modules did */
  684. response.getStatusCode();
  685. /* all done, so copy data */
  686. if (!request.internal_subrequest)
  687.     init(response);
  688. if (handle_trailers)
  689.     invokeTrailerHandlers(false);
  690. return false;
  691.     }
  692.     /**
  693.      * Copies the relevant fields from Response and marks this as initialized.
  694.      *
  695.      * @param resp the Response class to copy from
  696.      */
  697.     void init(Response resp)
  698.     {
  699. if (initialized)  return;
  700. this.StatusCode    = resp.StatusCode;
  701. this.ReasonLine    = resp.ReasonLine;
  702. this.Version       = resp.Version;
  703. this.EffectiveURI  = resp.EffectiveURI;
  704. this.ContentLength = resp.ContentLength;
  705. this.Headers       = resp.Headers;
  706. this.inp_stream    = resp.inp_stream;
  707. this.Data          = resp.Data;
  708. this.retry         = resp.retry;
  709. initialized        = true;
  710.     }
  711.     private boolean handle_trailers  = false;
  712.     private boolean trailers_handled = false;
  713.     /**
  714.      * This is invoked by the RespInputStream when it is close()'d. It
  715.      * just invokes the trailer handler in each module.
  716.      *
  717.      * @param force invoke the handlers even if not initialized yet?
  718.      * @exception IOException     if thrown by any module
  719.      * @exception ModuleException if thrown by any module
  720.      */
  721.     void invokeTrailerHandlers(boolean force)
  722.     throws IOException, ModuleException
  723.     {
  724. if (trailers_handled)  return;
  725. if (!force  &&  !initialized)
  726. {
  727.     handle_trailers = true;
  728.     return;
  729. }
  730. for (int idx=0; idx<modules.length && !aborted; idx++)
  731. {
  732.             modules[idx].trailerHandler(response, request);
  733. }
  734. trailers_handled = true;
  735.     }
  736.     /**
  737.      * Mark this request as having been aborted. It's invoked by
  738.      * HTTPConnection.stop().
  739.      */
  740.     void markAborted()
  741.     {
  742. aborted = true;
  743.     }
  744.     /**
  745.      * Gets any trailers from the response if we haven't already done so.
  746.      */
  747.     private synchronized void getTrailers()  throws IOException, ModuleException
  748.     {
  749. if (got_trailers)  return;
  750. if (!initialized)  handleResponse();
  751. response.getTrailer("Any");
  752. Trailers = response.Trailers;
  753. got_trailers = true;
  754. invokeTrailerHandlers(false);
  755.     }
  756.     /**
  757.      * Reads the response data received. Does not return until either
  758.      * Content-Length bytes have been read or EOF is reached.
  759.      *
  760.      * @inp       the input stream from which to read the data
  761.      * @exception IOException if any read on the input stream fails
  762.      */
  763.     private void readResponseData(InputStream inp)
  764.     throws IOException, ModuleException
  765.     {
  766. if (ContentLength == 0)
  767.     return;
  768. if (Data == null)
  769.     Data = new byte[0];
  770. // read response data
  771. int off = Data.length;
  772. try
  773. {
  774.     // check Content-length header in case CE-Module removed it
  775.     if (getHeader("Content-Length") != null)
  776.     {
  777. int rcvd = 0;
  778. Data = new byte[ContentLength];
  779. do
  780. {
  781.     off  += rcvd;
  782.     rcvd  = inp.read(Data, off, ContentLength-off);
  783. } while (rcvd != -1  &&  off+rcvd < ContentLength);
  784.                 /* Don't do this!
  785.  * If we do, then getData() won't work after a getInputStream()
  786.  * because we'll never get all the expected data. Instead, let
  787.  * the underlying RespInputStream throw the EOF.
  788. if (rcvd == -1) // premature EOF
  789. {
  790.     throw new EOFException("Encountered premature EOF while " +
  791.     "reading headers: received " + off +
  792.     " bytes instead of the expected " +
  793.     ContentLength + " bytes");
  794. }
  795. */
  796.     }
  797.     else
  798.     {
  799. int inc  = 1000,
  800.     rcvd = 0;
  801. do
  802. {
  803.     off  += rcvd;
  804.     Data  = Util.resizeArray(Data, off+inc);
  805. } while ((rcvd = inp.read(Data, off, inc)) != -1);
  806. Data = Util.resizeArray(Data, off);
  807.     }
  808. }
  809. catch (IOException ioe)
  810. {
  811.     Data = Util.resizeArray(Data, off);
  812.     throw ioe;
  813. }
  814. finally
  815. {
  816.     try
  817. { inp.close(); }
  818.     catch (IOException ioe)
  819. { }
  820. }
  821.     }
  822.     int getTimeout()
  823.     {
  824. return timeout;
  825.     }
  826. }