olegk 2003/11/05 12:45:34 Modified: httpclient/src/java/org/apache/commons/httpclient HttpConnection.java HttpMethodBase.java httpclient/src/test/org/apache/commons/httpclient TestHttpConnection.java Log: Changelog: - Socket input stream now wrapped with a wrapper class that re-throws certain type of generic IO exceptions as HttpClient specific exceptions. In particular java.io.InterruptedIOExceptions are re-thrown as IOTimeoutException - java.io.InterruptedIOExceptions in HttpConnection#open() re-thrown as ConnectTimeoutException - HttpConnection#write(byte[], int, int) changed to throw IllegalArgumentException in case of invalid input. Used to throw HttpRecoverableException. - 'Used' connection logic improved. Contributed by Oleg Kalnichevski Reviewed by Michael Becke Revision Changes Path 1.79 +105 -84 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnection.java Index: HttpConnection.java =================================================================== RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpConnection.java,v retrieving revision 1.78 retrieving revision 1.79 diff -u -r1.78 -r1.79 --- HttpConnection.java 1 Nov 2003 21:17:25 -0000 1.78 +++ HttpConnection.java 5 Nov 2003 20:45:34 -0000 1.79 @@ -495,7 +495,7 @@ socket.setSoTimeout(this.params.getSoTimeout()); } } - } catch (InterruptedIOException e) { + } catch (IOTimeoutException e) { // aha - the connection is NOT stale - continue on! } catch (IOException e) { // oops - the connection is stale, the read or soTimeout failed. @@ -659,12 +659,12 @@ public void open() throws IOException { LOG.trace("enter HttpConnection.open()"); + final String host = (proxyHostName == null) ? hostName : proxyHostName; + final int port = (proxyHostName == null) ? portNumber : proxyPortNumber; assertNotOpen(); try { if (null == socket) { - final String host = (null == proxyHostName) ? hostName : proxyHostName; - final int port = (null == proxyHostName) ? portNumber : proxyPortNumber; usingSecureSocket = isSecure() && !isProxied(); @@ -718,35 +718,32 @@ if (rcvBufSize >= 0) { socket.setReceiveBufferSize(rcvBufSize); } - inputStream = new PushbackInputStream(socket.getInputStream()); + inputStream = new PushbackInputStream( + new WrappedInputStream(socket.getInputStream())); outputStream = new BufferedOutputStream( new WrappedOutputStream(socket.getOutputStream()), socket.getSendBufferSize() ); isOpen = true; used = false; + } catch (InterruptedIOException e) { + closeSocketAndStreams(); + throw new ConnectTimeoutException("Open connection interrupted", e); } catch (IOException e) { // Connection wasn't opened properly // so close everything out closeSocketAndStreams(); throw e; } catch (TimeoutController.TimeoutException e) { - if (LOG.isWarnEnabled()) { - StringBuffer buffer = new StringBuffer(); - buffer.append("The host "); - buffer.append(hostName); - buffer.append(":"); - buffer.append(portNumber); - buffer.append(" (or proxy "); - buffer.append(proxyHostName); - buffer.append(":"); - buffer.append(proxyPortNumber); - buffer.append(") did not accept the connection within timeout of "); - buffer.append(this.params.getConnectionTimeout()); - buffer.append(" milliseconds"); - LOG.warn(buffer.toString()); - } - throw new ConnectionTimeoutException(); + StringBuffer buffer = new StringBuffer(); + buffer.append("The host "); + buffer.append(host); + buffer.append(":"); + buffer.append(port); + buffer.append(" did not accept the connection within timeout of "); + buffer.append(this.params.getConnectionTimeout()); + buffer.append(" milliseconds"); + throw new ConnectTimeoutException(buffer.toString()); } } @@ -893,7 +890,7 @@ } else { LOG.debug("Input data not available"); } - } catch (InterruptedIOException e) { + } catch (IOTimeoutException e) { if (LOG.isDebugEnabled()) { LOG.debug("Input data not available after " + timeout + " ms"); } @@ -915,13 +912,12 @@ * Writes the specified bytes to the output stream. * * @param data the data to be written - * @throws HttpRecoverableException if a SocketException occurs * @throws IllegalStateException if not connected * @throws IOException if an I/O problem occurs * @see #write(byte[],int,int) */ public void write(byte[] data) - throws IOException, IllegalStateException, HttpRecoverableException { + throws IOException, IllegalStateException { LOG.trace("enter HttpConnection.write(byte[])"); this.write(data, 0, data.length); } @@ -938,38 +934,24 @@ * @param data array containing the data to be written. * @param offset the start offset in the data. * @param length the number of bytes to write. - * @throws HttpRecoverableException if a SocketException occurs * @throws IllegalStateException if not connected * @throws IOException if an I/O problem occurs */ public void write(byte[] data, int offset, int length) - throws IOException, IllegalStateException, HttpRecoverableException { + throws IOException, IllegalStateException { LOG.trace("enter HttpConnection.write(byte[], int, int)"); + if (offset < 0) { + throw new IllegalArgumentException("Array offset may not be negative"); + } + if (length < 0) { + throw new IllegalArgumentException("Array length may not be negative"); + } if (offset + length > data.length) { - throw new HttpRecoverableException("Unable to write:" - + " offset=" + offset + " length=" + length - + " data.length=" + data.length); - } else if (data.length <= 0) { - throw new HttpRecoverableException( - "Unable to write:" + " data.length=" + data.length); + throw new IllegalArgumentException("Given offset and length exceed the array length"); } - assertOpen(); - - try { - outputStream.write(data, offset, length); - } catch (HttpRecoverableException hre) { - throw hre; - } catch (SocketException se) { - LOG.debug( - "HttpConnection: Socket exception while writing data", - se); - throw new HttpRecoverableException(se.toString()); - } catch (IOException ioe) { - LOG.debug("HttpConnection: Exception while writing data", ioe); - throw ioe; - } + this.outputStream.write(data, offset, length); } /** @@ -977,12 +959,11 @@ * output stream. * * @param data the bytes to be written - * @throws HttpRecoverableException when socket exceptions occur writing data * @throws IllegalStateException if the connection is not open * @throws IOException if an I/O problem occurs */ public void writeLine(byte[] data) - throws IOException, IllegalStateException, HttpRecoverableException { + throws IOException, IllegalStateException { LOG.trace("enter HttpConnection.writeLine(byte[])"); write(data); writeLine(); @@ -991,13 +972,11 @@ /** * Writes <tt>"\r\n".getBytes()</tt> to the output stream. * - * @throws HttpRecoverableException when socket exceptions occur writing - * data * @throws IllegalStateException if the connection is not open * @throws IOException if an I/O problem occurs */ public void writeLine() - throws IOException, IllegalStateException, HttpRecoverableException { + throws IOException, IllegalStateException { LOG.trace("enter HttpConnection.writeLine()"); write(CRLF); } @@ -1006,13 +985,11 @@ * Writes the specified String (as bytes) to the output stream. * * @param data the string to be written - * @throws HttpRecoverableException when socket exceptions occur writing - * data * @throws IllegalStateException if the connection is not open * @throws IOException if an I/O problem occurs */ public void print(String data) - throws IOException, IllegalStateException, HttpRecoverableException { + throws IOException, IllegalStateException { LOG.trace("enter HttpConnection.print(String)"); write(HttpConstants.getBytes(data)); } @@ -1022,13 +999,11 @@ * <tt>"\r\n".getBytes()</tt> to the output stream. * * @param data the data to be written - * @throws HttpRecoverableException when socket exceptions occur writing - * data * @throws IllegalStateException if the connection is not open * @throws IOException if an I/O problem occurs */ public void printLine(String data) - throws IOException, IllegalStateException, HttpRecoverableException { + throws IOException, IllegalStateException { LOG.trace("enter HttpConnection.printLine(String)"); writeLine(HttpConstants.getBytes(data)); } @@ -1036,13 +1011,11 @@ /** * Writes <tt>"\r\n".getBytes()</tt> to the output stream. * - * @throws HttpRecoverableException when socket exceptions occur writing - * data * @throws IllegalStateException if the connection is not open * @throws IOException if an I/O problem occurs */ public void printLine() - throws IOException, IllegalStateException, HttpRecoverableException { + throws IOException, IllegalStateException { LOG.trace("enter HttpConnection.printLine()"); writeLine(); } @@ -1115,10 +1088,6 @@ */ public void releaseConnection() { LOG.trace("enter HttpConnection.releaseConnection()"); - - // we are assuming that the connection will only be released once used - used = true; - if (locked) { LOG.debug("Connection is locked. Call to releaseConnection() ignored."); } else if (httpConnectionManager != null) { @@ -1248,17 +1217,6 @@ this.params.setSendBufferSize(sendBufferSize); } - // -- Timeout Exception - /** - * Signals that a timeout occured while opening the socket. - */ - public class ConnectionTimeoutException extends IOException { - /** Create an instance */ - public ConnectionTimeoutException() { - } - } - - /** * Helper class for wrapping socket based tasks. */ @@ -1301,8 +1259,8 @@ } /** - * A wrapper for output streams that closes the connection and converts to recoverable - * exceptions as appropriable when an IOException occurs. + * A wrapper for output streams that closes the connection and converts + * to HttpClient specific exceptions as appropriable when an IOException occurs. */ private class WrappedOutputStream extends OutputStream { @@ -1323,11 +1281,11 @@ */ private IOException handleException(IOException ioe) { // keep the original value of used, as it will be set to false by close(). - boolean tempUsed = used; + boolean isRecoverable = HttpConnection.this.used; HttpConnection.this.close(); if (ioe instanceof InterruptedIOException) { return new IOTimeoutException(ioe.getMessage()); - } else if (tempUsed) { + } else if (isRecoverable) { LOG.debug( "Output exception occurred on a used connection. Will treat as recoverable.", ioe @@ -1340,7 +1298,8 @@ public void write(int b) throws IOException { try { - out.write(b); + out.write(b); + HttpConnection.this.used = true; } catch (IOException ioe) { throw handleException(ioe); } @@ -1365,6 +1324,7 @@ public void write(byte[] b, int off, int len) throws IOException { try { out.write(b, off, len); + HttpConnection.this.used = true; } catch (IOException ioe) { throw handleException(ioe); } @@ -1373,6 +1333,67 @@ public void write(byte[] b) throws IOException { try { out.write(b); + HttpConnection.this.used = true; + } catch (IOException ioe) { + throw handleException(ioe); + } + } + + } + + /** + * A wrapper for input streams that converts to HTTPClient + * specific exceptions as appropriable when an IOException occurs. + */ + private class WrappedInputStream extends InputStream { + + /** the actual inpuit stream */ + private InputStream in; + + /** + * @param in the input stream to wrap + */ + public WrappedInputStream(InputStream in) { + this.in = in; + } + + /** + * Conditionally converts exception to HttpClient specific + * exception. + * @param ioe the exception that occurred + * @return the exception to be thrown + */ + private IOException handleException(IOException ioe) { + if (ioe instanceof InterruptedIOException) { + return new IOTimeoutException(ioe.getMessage()); + } else { + return ioe; + } + } + + public int read() throws IOException { + try { + return in.read(); + } catch (IOException ioe) { + throw handleException(ioe); + } + } + + public void close() throws IOException { + in.close(); + } + + public int read(byte[] b, int off, int len) throws IOException { + try { + return in.read(b, off, len); + } catch (IOException ioe) { + throw handleException(ioe); + } + } + + public int read(byte[] b) throws IOException { + try { + return in.read(b); } catch (IOException ioe) { throw handleException(ioe); } 1.189 +5 -6 jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java Index: HttpMethodBase.java =================================================================== RCS file: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v retrieving revision 1.188 retrieving revision 1.189 diff -u -r1.188 -r1.189 --- HttpMethodBase.java 3 Nov 2003 23:03:02 -0000 1.188 +++ HttpMethodBase.java 5 Nov 2003 20:45:34 -0000 1.189 @@ -67,7 +67,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InterruptedIOException; import java.util.Iterator; import org.apache.commons.httpclient.auth.AuthScheme; @@ -1949,7 +1948,7 @@ } else { return; } - } catch (InterruptedIOException e) { + } catch (IOTimeoutException e) { // Most probably Expect header is not recongnized // Remove the header to signal the method // that it's okay to go ahead with sending data 1.14 +2 -2 jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpConnection.java Index: TestHttpConnection.java =================================================================== RCS file: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpConnection.java,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- TestHttpConnection.java 26 Oct 2003 09:49:16 -0000 1.13 +++ TestHttpConnection.java 5 Nov 2003 20:45:34 -0000 1.14 @@ -137,7 +137,7 @@ fail("Should have timed out"); } catch(IOException e) { /* should fail */ - assertTrue(e instanceof HttpConnection.ConnectionTimeoutException); + assertTrue(e instanceof ConnectTimeoutException); assertTrue(connectionManager.isConnectionReleased()); } } @@ -162,7 +162,7 @@ conn.open(); fail("Should have timed out"); } catch(IOException e) { - assertTrue(e instanceof HttpConnection.ConnectionTimeoutException); + assertTrue(e instanceof ConnectTimeoutException); /* should fail */ } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]