📄 httpresponse.java
字号:
* @see #getInputStream()
* @return an array containing the data (body) returned. If no data
* was returned then it's set to a zero-length array.
* @exception IOException If any io exception occured while reading
* the data
* @exception ModuleException if any module encounters an exception.
*/
public synchronized byte[] getData() throws IOException, ModuleException
{
if (!initialized) handleResponse();
if (Data == null)
{
try
{ readResponseData(inp_stream); }
catch (InterruptedIOException ie) // don't intercept
{
throw ie;
}
catch (IOException ioe)
{
Log.write(Log.RESP, "HResp: (\"" + method + " " +
OriginalURI.getPathAndQuery() + "\")");
Log.write(Log.RESP, " ", ioe);
try { inp_stream.close(); } catch (Exception e) { }
throw ioe;
}
inp_stream.close();
}
return Data;
}
/**
* Gets an input stream from which the returned data can be read. Note
* that if <code>getData()</code> had been previously invoked it will
* actually return a ByteArrayInputStream created from that data.
*
* @see #getData()
* @return the InputStream.
* @exception IOException If any exception occurs on the socket.
* @exception ModuleException if any module encounters an exception.
*/
public synchronized InputStream getInputStream()
throws IOException, ModuleException
{
if (!initialized) handleResponse();
if (Data == null)
return inp_stream;
else
{
getData(); // ensure complete data is read
return new ByteArrayInputStream(Data);
}
}
/**
* Should the request be retried by the application? If the application
* used an <var>HttpOutputStream</var> in the request then various
* modules (such as the redirection and authorization modules) are not
* able to resend the request themselves. Instead, it becomes the
* application's responsibility.
*
* <P>If the application resends the request then it <strong>must</strong>
* use the same <var>HttpOutputStream</var> instance. This is because the
* modules use this to recognize the retried request and to perform the
* necessary work on the request before it's sent.
*
* <P>Here is a skeleton example of usage:
* <PRE>
* OutputStream out = new HttpOutputStream(1234);
* do
* {
* rsp = con.Post("/cgi-bin/my_cgi", out);
* out.write(...);
* out.close();
* } while (rsp.retryRequest());
*
* if (rsp.getStatusCode() >= 300)
* ...
* </PRE>
*
* @return true if the request should be retried.
* @exception IOException If any exception occurs on the socket.
* @exception ModuleException if any module encounters an exception.
*/
public boolean retryRequest() throws IOException, ModuleException
{
if (!initialized)
{
try
{ handleResponse(); }
catch (RetryException re)
{ this.retry = response.retry; }
}
return retry;
}
/**
* produces a full list of headers and their values, one per line.
*
* @return a string containing the headers
*/
public String toString()
{
if (!initialized)
{
try
{ handleResponse(); }
catch (Exception e)
{
if (!(e instanceof InterruptedIOException))
{
Log.write(Log.RESP, "HResp: (\"" + method + " " +
OriginalURI.getPathAndQuery() + "\")");
Log.write(Log.RESP, " ", e);
}
return "Failed to read headers: " + e;
}
}
String nl = System.getProperty("line.separator", "\n");
StringBuffer str = new StringBuffer(Version);
str.append(' ');
str.append(StatusCode);
str.append(' ');
str.append(ReasonLine);
str.append(nl);
if (EffectiveURI != null)
{
str.append("Effective-URI: ");
str.append(EffectiveURI);
str.append(nl);
}
Enumeration hdr_list = Headers.keys();
while (hdr_list.hasMoreElements())
{
String hdr = (String) hdr_list.nextElement();
str.append(hdr);
str.append(": ");
str.append(Headers.get(hdr));
str.append(nl);
}
return str.toString();
}
// Helper Methods
HTTPClientModule[] getModules()
{
return modules;
}
/**
* Processes a Response. This is done by calling the response handler
* in each module. When all is done, the various fields of this instance
* are intialized from the last Response.
*
* @exception IOException if any handler throws an IOException.
* @exception ModuleException if any module encounters an exception.
* @return true if a new request was generated. This is used for internal
* subrequests only
*/
synchronized boolean handleResponse() throws IOException, ModuleException
{
if (initialized) return false;
/* first get the response if necessary */
if (out_stream != null)
{
response = out_stream.getResponse();
response.http_resp = this;
out_stream = null;
}
/* go through modules and handle them */
doModules: while (true)
{
Phase1: for (int idx=0; idx<modules.length && !aborted; idx++)
{
try
{ modules[idx].responsePhase1Handler(response, request); }
catch (RetryException re)
{
if (re.restart)
continue doModules;
else
throw re;
}
}
Phase2: for (int idx=0; idx<modules.length && !aborted; idx++)
{
int sts = modules[idx].responsePhase2Handler(response, request);
switch (sts)
{
case RSP_CONTINUE: // continue processing
break;
case RSP_RESTART: // restart response processing
idx = -1;
continue doModules;
case RSP_SHORTCIRC: // stop processing and return
break doModules;
case RSP_REQUEST: // go to phase 1
case RSP_NEWCON_REQ: // process the request using a new con
response.getInputStream().close();
if (handle_trailers) invokeTrailerHandlers(true);
if (request.internal_subrequest) return true;
request.getConnection().
handleRequest(request, this, response, true);
if (initialized) break doModules;
idx = -1;
continue doModules;
case RSP_SEND: // send the request immediately
case RSP_NEWCON_SND: // send the request using a new con
response.getInputStream().close();
if (handle_trailers) invokeTrailerHandlers(true);
if (request.internal_subrequest) return true;
request.getConnection().
handleRequest(request, this, response, false);
idx = -1;
continue doModules;
default: // not valid
throw new Error("HTTPClient Internal Error: invalid status"+
" " + sts + " returned by module " +
modules[idx].getClass().getName());
}
}
Phase3: for (int idx=0; idx<modules.length && !aborted; idx++)
{
modules[idx].responsePhase3Handler(response, request);
}
break doModules;
}
/* force a read on the response in case none of the modules did */
response.getStatusCode();
/* all done, so copy data */
if (!request.internal_subrequest)
init(response);
if (handle_trailers)
invokeTrailerHandlers(false);
return false;
}
/**
* Copies the relevant fields from Response and marks this as initialized.
*
* @param resp the Response class to copy from
*/
void init(Response resp)
{
if (initialized) return;
this.StatusCode = resp.StatusCode;
this.ReasonLine = resp.ReasonLine;
this.Version = resp.Version;
this.EffectiveURI = resp.EffectiveURI;
this.ContentLength = resp.ContentLength;
this.Headers = resp.Headers;
this.inp_stream = resp.inp_stream;
this.Data = resp.Data;
this.retry = resp.retry;
initialized = true;
// for HotJava (or anybody else)
try
{
if (pe != null && ContentLength != -1)
{
pe.setType(Util.getPath(request.getRequestURI()),
getHeader("Content-type"));
sun.net.ProgressData.pdata.register(pe);
pe.update(0, ContentLength);
}
}
catch (Throwable t)
{
Log.write(Log.RESP, "Resp: ", t);
}
}
private boolean handle_trailers = false;
private boolean trailers_handled = false;
/**
* This is invoked by the RespInputStream when it is close()'d. It
* just invokes the trailer handler in each module.
*
* @param force invoke the handlers even if not initialized yet?
* @exception IOException if thrown by any module
* @exception ModuleException if thrown by any module
*/
void invokeTrailerHandlers(boolean force)
throws IOException, ModuleException
{
if (trailers_handled) return;
if (!force && !initialized)
{
handle_trailers = true;
return;
}
for (int idx=0; idx<modules.length && !aborted; idx++)
{
modules[idx].trailerHandler(response, request);
}
trailers_handled = true;
}
ProgressEntry pe = null;
/**
* The ProgressEntry is used by HotJava to monitor the loading progress.
* HttpURLConnection sets this.
*
* @param pe a ProgressEntry
*/
void setProgressEntry(ProgressEntry pe)
{
this.pe = pe;
}
/**
* Unset and unregister any ProgressEntry.
*
* @see #setProgressEntry(sun.net.ProgressEntry)
*/
void unsetProgressEntry()
{
if (pe != null)
{
try
{ sun.net.ProgressData.pdata.unregister(pe); }
catch (Throwable t)
{ }
pe = null;
}
}
/**
* Mark this request as having been aborted. It's invoked by
* HTTPConnection.stop().
*/
void markAborted()
{
aborted = true;
}
/**
* Gets any trailers from the response if we haven't already done so.
*/
private synchronized void getTrailers() throws IOException, ModuleException
{
if (got_trailers) return;
if (!initialized) handleResponse();
response.getTrailer("Any");
Trailers = response.Trailers;
got_trailers = true;
invokeTrailerHandlers(false);
}
/**
* Reads the response data received. Does not return until either
* Content-Length bytes have been read or EOF is reached.
*
* @inp the input stream from which to read the data
* @exception IOException if any read on the input stream fails
*/
private void readResponseData(InputStream inp)
throws IOException, ModuleException
{
if (ContentLength == 0)
return;
if (Data == null)
Data = new byte[0];
// read response data
int off = Data.length;
try
{
// check Content-length header in case CE-Module removed it
if (getHeader("Content-Length") != null)
{
int rcvd = 0;
Data = new byte[ContentLength];
do
{
off += rcvd;
rcvd = inp.read(Data, off, ContentLength-off);
} while (rcvd != -1 && off+rcvd < ContentLength);
/* Don't do this!
* If we do, then getData() won't work after a getInputStream()
* because we'll never get all the expected data. Instead, let
* the underlying RespInputStream throw the EOF.
if (rcvd == -1) // premature EOF
{
throw new EOFException("Encountered premature EOF while " +
"reading headers: received " + off +
" bytes instead of the expected " +
ContentLength + " bytes");
}
*/
}
else
{
int inc = 1000,
rcvd = 0;
do
{
off += rcvd;
Data = Util.resizeArray(Data, off+inc);
} while ((rcvd = inp.read(Data, off, inc)) != -1);
Data = Util.resizeArray(Data, off);
}
}
catch (IOException ioe)
{
Data = Util.resizeArray(Data, off);
throw ioe;
}
finally
{
try
{ inp.close(); }
catch (IOException ioe)
{ }
}
}
int getTimeout()
{
return timeout;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -