364921 - FIN WAIT sockets.
Interim commit, as things are not working exactly right yet.
This commit is contained in:
parent
9fd155d36e
commit
70e6655ec5
|
@ -356,13 +356,8 @@ public class SslBytesClientTest extends SslBytesTest
|
|||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertNull(record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
server.close();
|
||||
}
|
||||
|
|
|
@ -72,7 +72,6 @@ import org.junit.After;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SslBytesServerTest extends SslBytesTest
|
||||
|
@ -87,6 +86,7 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
private SslContextFactory sslContextFactory;
|
||||
private SSLContext sslContext;
|
||||
private SimpleProxy proxy;
|
||||
private Runnable idleHook;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
|
@ -119,6 +119,15 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onReadTimeout()
|
||||
{
|
||||
final Runnable idleHook = SslBytesServerTest.this.idleHook;
|
||||
if (idleHook != null)
|
||||
idleHook.run();
|
||||
return super.onReadTimeout();
|
||||
}
|
||||
}, connector, endPoint);
|
||||
}
|
||||
};
|
||||
|
@ -165,7 +174,6 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
}
|
||||
};
|
||||
connector.setIdleTimeout(idleTimeout);
|
||||
// connector.setPort(5870);
|
||||
connector.setPort(0);
|
||||
|
||||
server.addConnector(connector);
|
||||
|
@ -209,7 +217,7 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
|
||||
proxy = new SimpleProxy(threadPool, "localhost", serverPort);
|
||||
proxy.start();
|
||||
logger.debug(":{} <==> :{}", proxy.getPort(), serverPort);
|
||||
logger.info("proxy:{} <==> server:{}", proxy.getPort(), serverPort);
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -377,13 +385,9 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Close Alert
|
||||
record = proxy.readFromServer();
|
||||
proxy.flushToClient(record);
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToClient(record);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -669,13 +673,9 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Close Alert
|
||||
record = proxy.readFromServer();
|
||||
proxy.flushToClient(record);
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToClient(record);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -728,22 +728,15 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Close Alert
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNotNull(record);
|
||||
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
|
||||
// We can't forward to the client, its socket is already closed
|
||||
Assert.assertNull(record);
|
||||
|
||||
// Check that we did not spin
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
Assert.assertThat(sslFills.get(), Matchers.lessThan(20));
|
||||
Assert.assertThat(sslFlushes.get(), Matchers.lessThan(20));
|
||||
Assert.assertThat(httpParses.get(), Matchers.lessThan(20));
|
||||
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToClient(record);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -803,11 +796,9 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Close Alert
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNotNull(record);
|
||||
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
|
||||
// We can't forward to the client, its socket is already closed
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
|
||||
// Check that we did not spin
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
|
@ -819,11 +810,6 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
record = proxy.readFromClient();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToClient(record);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -864,12 +850,9 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
// Close the raw socket, this generates a truncation attack
|
||||
proxy.flushToServer(null);
|
||||
|
||||
// Expect alert + raw close from server
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
|
||||
// Expect raw close from server
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Check that we did not spin
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
|
@ -917,12 +900,9 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Expect alert + raw close from server
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
|
||||
// Expect raw close from server
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Check that we did not spin
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
|
@ -1099,6 +1079,7 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
System.arraycopy(closeBytes, 0, bytes, dataBytes.length, closeBytes.length / 2);
|
||||
proxy.flushToServer(100, bytes);
|
||||
|
||||
// Send the other half of the close alert bytes
|
||||
bytes = new byte[closeBytes.length - closeBytes.length / 2];
|
||||
System.arraycopy(closeBytes, closeBytes.length / 2, bytes, 0, bytes.length);
|
||||
proxy.flushToServer(100, bytes);
|
||||
|
@ -1113,27 +1094,15 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Close Alert
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNotNull(record);
|
||||
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
|
||||
// We can't forward to the client, its socket is already closed
|
||||
Assert.assertNull(record);
|
||||
|
||||
// Check that we did not spin
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
Assert.assertThat(sslFills.get(), Matchers.lessThan(20));
|
||||
Assert.assertThat(sslFlushes.get(), Matchers.lessThan(20));
|
||||
Assert.assertThat(httpParses.get(), Matchers.lessThan(20));
|
||||
|
||||
// Socket close
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToClient(record);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1749,13 +1718,37 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
client.close();
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testRequestConcurrentWithIdleExpiration() throws Exception
|
||||
{
|
||||
final SSLSocket client = newClient();
|
||||
final OutputStream clientOutput = client.getOutputStream();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
idleHook = new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
if (latch.getCount()==0)
|
||||
return;
|
||||
try
|
||||
{
|
||||
// Send request
|
||||
clientOutput.write(("" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n").getBytes("UTF-8"));
|
||||
clientOutput.flush();
|
||||
latch.countDown();
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
// Latch won't trigger and test will fail
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
client.startHandshake();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
|
@ -1779,86 +1772,13 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
Assert.assertThat(sslFlushes.get(), Matchers.lessThan(20));
|
||||
Assert.assertThat(httpParses.get(), Matchers.lessThan(50));
|
||||
|
||||
completeClose(client);
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(record);
|
||||
|
||||
TimeUnit.MILLISECONDS.sleep(200);
|
||||
//System.err.println(((Dumpable)server.getConnectors()[0]).dump());
|
||||
Assert.assertThat(((Dumpable)server.getConnectors()[0]).dump(), Matchers.not(Matchers.containsString("SCEP@")));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
public void testRequestWriteBlockedWithPipelinedRequest() throws Exception
|
||||
{
|
||||
final SSLSocket client = newClient();
|
||||
final OutputStream clientOutput = client.getOutputStream();
|
||||
|
||||
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
client.startHandshake();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
|
||||
byte[] data = new byte[128 * 1024];
|
||||
Arrays.fill(data, (byte)'X');
|
||||
final String content = new String(data, "UTF-8");
|
||||
Future<Object> request = threadPool.submit(new Callable<Object>()
|
||||
{
|
||||
public Object call() throws Exception
|
||||
{
|
||||
clientOutput.write(("" +
|
||||
"POST /echo HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"Content-Length: " + content.length() + "\r\n" +
|
||||
"\r\n" +
|
||||
content).getBytes("UTF-8"));
|
||||
clientOutput.flush();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Nine TLSRecords will be generated for the request
|
||||
for (int i = 0; i < 9; ++i)
|
||||
{
|
||||
// Application data
|
||||
TLSRecord record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
|
||||
proxy.flushToServer(record, 0);
|
||||
}
|
||||
Assert.assertNull(request.get(5, TimeUnit.SECONDS));
|
||||
|
||||
// We do not read the big request to cause a write blocked on the server
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
|
||||
// Now send the pipelined request
|
||||
Future<Object> pipelined = threadPool.submit(new Callable<Object>()
|
||||
{
|
||||
public Object call() throws Exception
|
||||
{
|
||||
clientOutput.write(("" +
|
||||
"GET /pipelined HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n").getBytes("UTF-8"));
|
||||
clientOutput.flush();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
TLSRecord record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
|
||||
proxy.flushToServer(record, 0);
|
||||
Assert.assertNull(pipelined.get(5, TimeUnit.SECONDS));
|
||||
|
||||
// Check that we did not spin
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
Assert.assertThat(sslFills.get(), lessThan(20));
|
||||
Assert.assertThat(sslFlushes.get(), lessThan(20));
|
||||
Assert.assertThat(httpParses.get(), lessThan(50));
|
||||
|
||||
Thread.sleep(5000);
|
||||
|
||||
// closeClient(client);
|
||||
}
|
||||
*/
|
||||
private void assumeJavaVersionSupportsTLSRenegotiations()
|
||||
{
|
||||
// Due to a security bug, TLS renegotiations were disabled in JDK 1.6.0_19-21
|
||||
|
@ -1893,31 +1813,8 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Close Alert
|
||||
record = proxy.readFromServer();
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Socket close
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToClient(record);
|
||||
}
|
||||
|
||||
private void completeClose(SSLSocket client) throws Exception
|
||||
{
|
||||
client.close();
|
||||
|
||||
// Close Alert
|
||||
TLSRecord record = proxy.readFromClient();
|
||||
proxy.flushToServer(record);
|
||||
// Socket close
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertNull(String.valueOf(record), record);
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Close Alert
|
||||
record = proxy.readFromServer();
|
||||
proxy.flushToClient(record);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,12 +34,17 @@ import java.util.concurrent.ExecutorService;
|
|||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
|
||||
public abstract class SslBytesTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tracker = new TestTracker();
|
||||
|
||||
protected final Logger logger = Log.getLogger(getClass());
|
||||
|
||||
public static class TLSRecord
|
||||
|
@ -115,8 +120,7 @@ public abstract class SslBytesTest
|
|||
|
||||
public void start() throws Exception
|
||||
{
|
||||
serverSocket = new ServerSocket(47009);
|
||||
// serverSocket = new ServerSocket(0);
|
||||
serverSocket = new ServerSocket(0);
|
||||
Thread acceptor = new Thread(this);
|
||||
acceptor.start();
|
||||
server = new Socket(serverHost, serverPort);
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.io.IOException;
|
|||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.ReadPendingException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Executor;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
@ -426,7 +425,7 @@ public class SslConnection extends AbstractConnection
|
|||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (!isOutputShutdown())
|
||||
{
|
||||
// Normal readable callback
|
||||
// Get called back on onfillable when then is more data to fill
|
||||
|
@ -613,8 +612,21 @@ public class SslConnection extends AbstractConnection
|
|||
// maybe we will fill some more on a retry
|
||||
continue;
|
||||
}
|
||||
// we need to wait for more net data
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
if (isOutputShutdown())
|
||||
{
|
||||
// We have sent the SSL Close Alert, and we read 0 bytes:
|
||||
// it's a peer that it is not sending the FIN, so we just
|
||||
// return -1 as if we did, so the connection will be closed.
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we need to wait for more net data
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
case FINISHED:
|
||||
throw new IllegalStateException();
|
||||
|
@ -735,9 +747,11 @@ public class SslConnection extends AbstractConnection
|
|||
if (BufferUtil.hasContent(_encryptedOutput))
|
||||
return false;
|
||||
}
|
||||
|
||||
// otherwise we have written, and the caller will close the underlying connection
|
||||
getEndPoint().shutdownOutput();
|
||||
else
|
||||
{
|
||||
getEndPoint().shutdownOutput();
|
||||
}
|
||||
return allConsumed;
|
||||
|
||||
case BUFFER_UNDERFLOW:
|
||||
|
@ -834,11 +848,15 @@ public class SslConnection extends AbstractConnection
|
|||
@Override
|
||||
public void shutdownOutput()
|
||||
{
|
||||
if (isInputShutdown())
|
||||
boolean ishut = isInputShutdown();
|
||||
if (DEBUG)
|
||||
LOG.debug("{} shutdownOutput: oshut={}, ishut={}", SslConnection.this, isOutputShutdown(), ishut);
|
||||
if (ishut)
|
||||
{
|
||||
// Aggressively close because inbound close handshake already processed
|
||||
// and most impls are expecting a FIN rather than a reply. When a reply is sent, many impls will do
|
||||
// a RST.
|
||||
// Aggressively close, since inbound close alert has already been processed
|
||||
// and the TLS specification allows to close the connection directly, which
|
||||
// is what most other implementations expect: a FIN rather than a TLS close
|
||||
// reply. If a TLS close reply is sent, most implementation send a RST.
|
||||
getEndPoint().close();
|
||||
}
|
||||
else
|
||||
|
@ -847,20 +865,6 @@ public class SslConnection extends AbstractConnection
|
|||
{
|
||||
_sslEngine.closeOutbound();
|
||||
flush(BufferUtil.EMPTY_BUFFER);
|
||||
fillInterested(new Callback()
|
||||
{
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
getEndPoint().close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
getEndPoint().close();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue