DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT <http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16904>. ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND INSERTED IN THE BUG DATABASE.
http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16904 Input Stream closed, Output Stream valid, no detection by socket Summary: Input Stream closed, Output Stream valid, no detection by socket Product: Commons Version: 2.0 Alpha 2 Platform: PC OS/Version: Windows NT/2K Status: NEW Severity: Normal Priority: Other Component: HttpClient AssignedTo: [EMAIL PROTECTED] ReportedBy: [EMAIL PROTECTED] Before I say anything, I apologize if this is the wrong way to submit patches. I found this bug and wanted to upload the fix I made. Periodically after a timeout, I can attempt to make a request on a connection that is still open. The post is successfull, a tunnel host shows that the response is returned, but the HttpConnection class receives no data when trying to read from the socket input stream. This can be reproduced by creating a client connection, having the client be inactive for a short period of time (~30 sec) and accessing again. If the client waits too long, the socket is closed and recovery is done correctly. In the HttpMethodBase.readStatusLine method, I attempted to check all the new socket 1.4 flags before reading from the socket, but they all state that the stream is still valid. However, the first line it attempts to read is the response code and -1 is immediately returned from the stream. To put a hack in for this, I created a stream wrapper for the input stream that constantly looks for input data. It can set a boolean flag indicating if it is still physically connected to the server. Before any of the write routines actually write data to the output stream, they query this flag and throw an HttpRecoverableException if it is not connected. The query for still connected was inserted into the methods: HttpConnection.write(byte[] data, int offset, int length) HttpConnection.writeLine() HttpConnection.writeLine(byte[] data) The code snippet to check is ------------------ if (!_input.isConnected()) { log.debug("HttpConnection: InputStream is no longer connected to server"); throw new HttpRecoverableException("No longer connected to server"); } ----------------- The following is the code from the HttpInputStream class: package org.apache.commons.httpclient; import java.io.*; public class HttpInputStream extends InputStream { private InputStream in; private PipedInputStream pin; private PipedOutputStream pout; private IOException readingException; private boolean connected; private StreamTask task; private Thread thread; /** * Constructor */ public HttpInputStream(InputStream in) throws IOException { this.in = in; this.pin = new PipedInputStream(); this.pout = new PipedOutputStream(pin); this.connected = true; this.task = new StreamTask(); this.thread = new Thread(task, "HTTP InputStream Wrapper"); thread.setDaemon(true); thread.start(); } /** * Closes the input stream */ public void close() throws IOException { if (in == null) throw new IOException("Stream not open."); try{ // Kill thread if running IOException iox = readingException; if (thread.isAlive()) { thread.interrupt(); } // Throw any outstanding IO Exceptions if (iox != null) throw iox; // Try to close input stream normally InputStream tmp = in; in = null; tmp.close(); } catch(IOException iox){ throw iox; } finally { try{ if (in!=null) in.close(); } catch (Exception ignored){} try{ pin.close(); } catch (Exception ignored){} try{ pout.close(); } catch (Exception ignored){} } } /** * Executes the current task */ private void execute() { Thread t = new Thread(task, "HTTP InputStream Wrapper"); t.setDaemon(true); t.start(); } /** * Returns true if stream is connected to server */ public boolean isConnected() { return this.connected; } // Helper class private class StreamTask implements Runnable { public void run() { byte buffer[] = new byte[1024]; try { int ch = in.read(); while (ch >= 0) { pout.write(ch); int available = in.available(); if (available>0){ int toRead = (buffer.length < available) ? buffer.length : available; int read = in.read(buffer, 0, toRead); pout.write(buffer, 0, read); } ch = in.read(); } pin.close(); connected = false; } catch(IOException iox) { readingException = iox; } } } // -- InputStream functions delegated to PipedInputStream public int available() throws IOException { if (readingException != null) throw readingException; return pin.available(); } public int read() throws IOException { if (readingException != null) throw readingException; return pin.read(); } public int read(byte[] b) throws IOException { if (readingException != null) throw readingException; return pin.read(b); } public int read(byte[] b, int off, int len) throws IOException { if (readingException != null) throw readingException; return pin.read(b, off, len); } public void mark(int readlimit) { pin.mark(readlimit); } public boolean markSupported() { return pin.markSupported(); } public void reset() throws IOException { if (readingException != null) throw readingException; pin.reset(); } public long skip(long n) throws IOException { if (readingException != null) throw readingException; return pin.skip(n); } } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
