Details
Description
When using Jetty HttpClient with NIO, if HttpGenerator.flush throws an exception (because the remote server has died, for example), the connection is leaked. Also, the connection remains selectable, and so the selector thread enters an infinite loop. Here's the stack trace (this repeats indefinitely):
116 [HttpClient-2] WARN o.m.log : EXCEPTION on HttpExchange@1714575288=POST//localhost:3456/ping#9
org.mortbay.jetty.EofException
at org.mortbay.jetty.HttpGenerator.flush(HttpGenerator.java:787)
at org.mortbay.jetty.client.HttpConnection.handle(HttpConnection.java:233)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:497)
Caused by: java.io.IOException: Broken pipe
at sun.nio.ch.FileDispatcher.write0(Native Method)
at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:29)
at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:104)
at sun.nio.ch.IOUtil.write(IOUtil.java:60)
at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:334)
at org.mortbay.io.nio.ChannelEndPoint.flush(ChannelEndPoint.java:169)
at org.mortbay.io.nio.SelectChannelEndPoint.flush(SelectChannelEndPoint.java:221)
at org.mortbay.jetty.HttpGenerator.flush(HttpGenerator.java:721)
... 3 common frames omitted
This happens because org.mortbay.jetty.client.HttpConnection.handle() eats the exception:
public void handle() throws IOException
{
// ...
try
{
// ...
catch (IOException e)
{
synchronized(this)
{
if (_exchange!=null)
}
// XXX exception eaten, when it should be propagated upwards
}
// ...
}
so
(sorry, incomplete description, saved too early)
The exception should be propagated upstream to SelectChannelEndPoint.run(), which would then close the connection:
public void run()
{ _connection.handle(); }{
try
catch (ClosedChannelException e)
{ Log.ignore(e); }catch (EofException e)
{close();}{
Log.debug("EOF", e);
try
catch(IOException e2){Log.ignore(e2);}
}
catch (HttpException e)
{
Log.debug("BAD", e);
try{close();}
catch(IOException e2)
{Log.ignore(e2);}}
catch (Throwable e)
{
Log.warn("handle failed", e);
try{close();}
catch(IOException e2){Log.ignore(e2);}
}
{ undispatch(); }finally
}