398872 - SslConnection should not be notified of idle timeouts. First solution.

This commit is contained in:
Simone Bordet 2013-01-23 15:47:08 +01:00
parent b5df3a6b76
commit b2f3852fb3
6 changed files with 96 additions and 94 deletions

View File

@ -871,6 +871,16 @@ public class HttpClient extends ContainerLifeCycle
return encodingField;
}
protected HttpConnection newHttpConnection(HttpClient httpClient, EndPoint endPoint, HttpDestination destination)
{
return new HttpConnection(httpClient, endPoint, destination);
}
protected SslConnection newSslConnection(HttpClient httpClient, EndPoint endPoint, SSLEngine engine)
{
return new SslConnection(httpClient.getByteBufferPool(), httpClient.getExecutor(), endPoint, engine);
}
@Override
public void dump(Appendable out, String indent) throws IOException
{
@ -916,12 +926,9 @@ public class HttpClient extends ContainerLifeCycle
SSLEngine engine = sslContextFactory.newSSLEngine(endPoint.getRemoteAddress());
engine.setUseClientMode(true);
SslConnection sslConnection = new SslConnection(getByteBufferPool(), getExecutor(), endPoint, engine);
// TODO: configureConnection => implies we should use SslConnectionFactory to do it
SslConnection sslConnection = newSslConnection(HttpClient.this, endPoint, engine);
EndPoint appEndPoint = sslConnection.getDecryptedEndPoint();
HttpConnection connection = newHttpConnection(HttpClient.this, appEndPoint, destination);
// TODO: configureConnection, see above
appEndPoint.setConnection(connection);
callback.promise.succeeded(connection);
@ -932,7 +939,6 @@ public class HttpClient extends ContainerLifeCycle
else
{
HttpConnection connection = newHttpConnection(HttpClient.this, endPoint, destination);
// TODO: configureConnection, see above
callback.promise.succeeded(connection);
return connection;
}

View File

@ -23,6 +23,8 @@ import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.net.ssl.SSLEngine;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -34,10 +36,13 @@ import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.client.util.InputStreamContentProvider;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.ssl.SslConnection;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.toolchain.test.annotation.Slow;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
@ -223,6 +228,46 @@ public class HttpClientTimeoutTest extends AbstractHttpClientServerTest
}
}
@Test
public void testIdleTimeout() throws Throwable
{
long timeout = 1000;
start(new TimeoutHandler(2 * timeout));
client.stop();
final AtomicBoolean sslIdle = new AtomicBoolean();
client = new HttpClient(sslContextFactory)
{
@Override
protected SslConnection newSslConnection(HttpClient httpClient, EndPoint endPoint, SSLEngine engine)
{
return new SslConnection(httpClient.getByteBufferPool(), httpClient.getExecutor(), endPoint, engine)
{
@Override
protected boolean onReadTimeout()
{
sslIdle.set(true);
return super.onReadTimeout();
}
};
}
};
client.setIdleTimeout(timeout);
client.start();
try
{
client.newRequest("localhost", connector.getLocalPort())
.scheme(scheme)
.send();
Assert.fail();
}
catch (Exception x)
{
Assert.assertFalse(sslIdle.get());
Assert.assertThat(x.getCause(), Matchers.instanceOf(TimeoutException.class));
}
}
private class TimeoutHandler extends AbstractHandler
{
private final long timeout;

View File

@ -83,7 +83,7 @@ public abstract class IdleTimeout
if (old>0)
{
// if the old was less than or equal to the new timeout, then nothing more to do
if (old<=_idleTimeout)
if (old<=idleTimeout)
return;
// old timeout is too long, so cancel it.
@ -93,7 +93,7 @@ public abstract class IdleTimeout
}
// If we have a new timeout, then check and reschedule
if (_idleTimeout>0 && isOpen())
if (idleTimeout>0 && isOpen())
_idleTask.run();
}

View File

@ -220,9 +220,6 @@ public class SslConnection extends AbstractConnection
// the decrypted readInterest and/or writeFlusher so that they will attempt
// to do the fill and/or flush again and these calls will do the actually
// handle the cause.
super.onFillInterestedFailed(cause);
synchronized(_decryptedEndPoint)
{
_decryptedEndPoint.getFillInterest().onFail(cause);

View File

@ -20,11 +20,9 @@ package org.eclipse.jetty.io;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
@ -42,9 +40,7 @@ import org.junit.Test;
import static org.hamcrest.Matchers.greaterThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
@ -226,51 +222,6 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
super.testIdle();
}
@Override
public void testBlockedReadIdle() throws Exception
{
Socket client = newClient();
OutputStream clientOutputStream = client.getOutputStream();
client.setSoTimeout(5000);
SocketChannel server = _connector.accept();
server.configureBlocking(false);
_manager.accept(server);
// Write client to server
clientOutputStream.write("HelloWorld".getBytes("UTF-8"));
// Verify echo server to client
for (char c : "HelloWorld".toCharArray())
{
int b = client.getInputStream().read();
assertTrue(b>0);
assertEquals(c,(char)b);
}
assertTrue(_lastEndPointLatch.await(1, TimeUnit.SECONDS));
_lastEndPoint.setIdleTimeout(500);
// Write 8 and cause block waiting for 10
_blockAt=10;
clientOutputStream.write("12345678".getBytes("UTF-8"));
clientOutputStream.flush();
// read until idle shutdown received
long start=System.currentTimeMillis();
int b=client.getInputStream().read();
assertEquals(-1,b);
long idle=System.currentTimeMillis()-start;
assertTrue(idle>400);
assertTrue(idle<2000);
Thread.sleep(1000);
assertFalse(_lastEndPoint.isOpen());
}
@Test
@Override
@Stress("Requires a relatively idle (network wise) environment")

View File

@ -18,12 +18,6 @@
package org.eclipse.jetty.io;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
@ -52,6 +46,12 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class SelectChannelEndPointTest
{
private static final Logger LOG = Log.getLogger(SelectChannelEndPointTest.class);
@ -425,6 +425,7 @@ public class SelectChannelEndPointTest
public void testBlockedReadIdle() throws Exception
{
Socket client = newClient();
InputStream clientInputStream = client.getInputStream();
OutputStream clientOutputStream = client.getOutputStream();
client.setSoTimeout(5000);
@ -440,7 +441,7 @@ public class SelectChannelEndPointTest
// Verify echo server to client
for (char c : "HelloWorld".toCharArray())
{
int b = client.getInputStream().read();
int b = clientInputStream.read();
assertTrue(b > 0);
assertEquals(c, (char)b);
}
@ -456,7 +457,7 @@ public class SelectChannelEndPointTest
// read until idle shutdown received
long start = System.currentTimeMillis();
int b = client.getInputStream().read();
int b = clientInputStream.read();
assertEquals('E', b);
long idle = System.currentTimeMillis() - start;
assertTrue(idle > idleTimeout / 2);
@ -464,10 +465,12 @@ public class SelectChannelEndPointTest
for (char c : "E: 12345678".toCharArray())
{
b = client.getInputStream().read();
b = clientInputStream.read();
assertTrue(b > 0);
assertEquals(c, (char)b);
}
b = clientInputStream.read();
assertEquals(-1,b);
// But endpoint is still open.
if(_lastEndPoint.isOpen())