SSL refactorings.
This commit is contained in:
parent
7f291e8831
commit
9e8b2f1aad
|
@ -76,14 +76,14 @@ public abstract class AbstractAsyncConnection implements AsyncConnection
|
|||
else
|
||||
_endp.shutdownOutput();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void scheduleOnReadable()
|
||||
{
|
||||
if (_readInterested.compareAndSet(false,true))
|
||||
getEndPoint().readable(null,_readCallback);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onReadFail(Throwable cause)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty.io.ssl;
|
||||
|
||||
enum ReadState
|
||||
{
|
||||
HANDSHAKING, HANDSHAKEN, IDLE, UNDERFLOW, DECRYPTED, CLOSED
|
||||
}
|
|
@ -0,0 +1,265 @@
|
|||
package org.eclipse.jetty.io.ssl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public abstract class SSLMachine
|
||||
{
|
||||
private static final Logger logger = Log.getLogger(SslConnection.class);
|
||||
private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
|
||||
private final Object wrapLock = new Object();
|
||||
private final SSLEngine engine;
|
||||
private boolean handshaken;
|
||||
private boolean remoteClosed;
|
||||
|
||||
public SSLMachine(SSLEngine engine)
|
||||
{
|
||||
this.engine = engine;
|
||||
}
|
||||
|
||||
public ReadState decrypt(ByteBuffer netInput, ByteBuffer appInput) throws SSLException
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
SSLEngineResult.HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
|
||||
logger.debug("Reading from {}, handshake status: {}", netInput, handshakeStatus);
|
||||
switch (handshakeStatus)
|
||||
{
|
||||
case NEED_UNWRAP:
|
||||
{
|
||||
ReadState result = unwrap(netInput, appInput);
|
||||
if (result == null)
|
||||
break;
|
||||
return result;
|
||||
}
|
||||
case NEED_TASK:
|
||||
{
|
||||
executeTasks();
|
||||
break;
|
||||
}
|
||||
case NEED_WRAP:
|
||||
{
|
||||
writeForDecrypt(EMPTY_BUFFER);
|
||||
break;
|
||||
}
|
||||
case NOT_HANDSHAKING:
|
||||
{
|
||||
ReadState result = unwrap(netInput, appInput);
|
||||
if (result == null)
|
||||
break;
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public WriteState encrypt(ByteBuffer appOutput, ByteBuffer netOutput) throws SSLException
|
||||
{
|
||||
return wrap(appOutput, netOutput);
|
||||
}
|
||||
|
||||
protected abstract void writeForDecrypt(ByteBuffer appOutput);
|
||||
|
||||
private ReadState unwrap(ByteBuffer netInput, ByteBuffer appInput) throws SSLException
|
||||
{
|
||||
boolean decrypted = false;
|
||||
while (netInput.hasRemaining())
|
||||
{
|
||||
logger.debug("Decrypting from {} to {}", netInput, appInput);
|
||||
SSLEngineResult result = unwrap(engine, netInput, appInput);
|
||||
logger.debug("Decrypted from {} to {}, result {}", netInput, appInput, result);
|
||||
switch (result.getStatus())
|
||||
{
|
||||
case OK:
|
||||
{
|
||||
SSLEngineResult.HandshakeStatus handshakeStatus = result.getHandshakeStatus();
|
||||
if (handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED)
|
||||
{
|
||||
if (engine.getUseClientMode())
|
||||
{
|
||||
logger.debug("Handshake finished (client), new SSL session");
|
||||
handshaken = true;
|
||||
return ReadState.HANDSHAKEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (handshaken)
|
||||
{
|
||||
logger.debug("Rehandshake finished (server)");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("Handshake finished (server), cached SSL session");
|
||||
handshaken = true;
|
||||
return ReadState.HANDSHAKEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.bytesProduced() > 0)
|
||||
{
|
||||
decrypted = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)
|
||||
continue;
|
||||
|
||||
if (handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED ||
|
||||
handshakeStatus == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
|
||||
break;
|
||||
|
||||
return null;
|
||||
}
|
||||
case BUFFER_UNDERFLOW:
|
||||
{
|
||||
return decrypted ? ReadState.DECRYPTED : ReadState.UNDERFLOW;
|
||||
}
|
||||
case CLOSED:
|
||||
{
|
||||
// We have read the SSL close message and updated the SSLEngine
|
||||
logger.debug("Close alert received from remote peer");
|
||||
remoteClosed = true;
|
||||
return decrypted ? ReadState.DECRYPTED : ReadState.CLOSED;
|
||||
}
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
SSLEngineResult.HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
|
||||
if (handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP ||
|
||||
engine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
|
||||
return ReadState.UNDERFLOW;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private SSLEngineResult unwrap(SSLEngine engine, ByteBuffer netInput, ByteBuffer appInput) throws SSLException
|
||||
{
|
||||
int position = BufferUtil.flipToFill(appInput);
|
||||
try
|
||||
{
|
||||
return engine.unwrap(netInput, appInput);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BufferUtil.flipToFlush(appInput, position);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeTasks()
|
||||
{
|
||||
Runnable task;
|
||||
while ((task = engine.getDelegatedTask()) != null)
|
||||
{
|
||||
task.run();
|
||||
logger.debug("Executed task: {}", task);
|
||||
}
|
||||
}
|
||||
|
||||
private WriteState wrap(ByteBuffer appOutput, ByteBuffer netOutput) throws SSLException
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Locking is important because application code may call handshake() (to rehandshake)
|
||||
// followed by encrypt(). In this case, the handshake() call may need to wrap, then
|
||||
// unwrap and then wrap again to perform the handshake, and the second wrap may be
|
||||
// concurrent with the wrap triggered by encrypt(), which would corrupt SSLEngine.
|
||||
// It is also important that wrap and write are atomic, because SSL packets needs to
|
||||
// be ordered (and therefore the packet created first must be written before the packet
|
||||
// created second).
|
||||
SSLEngineResult result;
|
||||
synchronized (wrapLock)
|
||||
{
|
||||
logger.debug("Encrypting from {} to {}", appOutput, netOutput);
|
||||
result = wrap(engine, appOutput, netOutput);
|
||||
logger.debug("Encrypted from {} to {}, result: {}", appOutput, netOutput, result);
|
||||
|
||||
/*
|
||||
if (result.bytesProduced() > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
netOutput.flip();
|
||||
write(netOutput);
|
||||
netOutput.clear();
|
||||
}
|
||||
catch (RuntimeIOException x)
|
||||
{
|
||||
// If we try to write the SSL close message but we cannot
|
||||
// because the other peer has already closed the connection,
|
||||
// then ignore the exception and continue
|
||||
if (result.getStatus() != SSLEngineResult.Status.CLOSED)
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (result.getStatus() == SSLEngineResult.Status.CLOSED)
|
||||
return WriteState.CLOSED;
|
||||
|
||||
SSLEngineResult.HandshakeStatus handshakeStatus = result.getHandshakeStatus();
|
||||
if (handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP)
|
||||
continue;
|
||||
|
||||
if (handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED)
|
||||
{
|
||||
if (engine.getUseClientMode())
|
||||
{
|
||||
if (handshaken)
|
||||
{
|
||||
logger.debug("Rehandshake finished (client)");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("Handshake finished (client), cached SSL session");
|
||||
handshaken = true;
|
||||
return WriteState.HANDSHAKEN;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("Handshake finished (server), new SSL session");
|
||||
assert !appOutput.hasRemaining();
|
||||
handshaken = true;
|
||||
return WriteState.HANDSHAKEN;
|
||||
}
|
||||
}
|
||||
|
||||
if (!appOutput.hasRemaining())
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private SSLEngineResult wrap(SSLEngine engine, ByteBuffer appOutput, ByteBuffer netOutput) throws SSLException
|
||||
{
|
||||
int position = BufferUtil.flipToFill(netOutput);
|
||||
try
|
||||
{
|
||||
return engine.wrap(appOutput, netOutput);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BufferUtil.flipToFlush(netOutput, position);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRemoteClosed()
|
||||
{
|
||||
return remoteClosed;
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,624 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2004-2011 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty.io.ssl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadPendingException;
|
||||
import java.nio.channels.WritePendingException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import org.eclipse.jetty.io.AbstractAsyncConnection;
|
||||
import org.eclipse.jetty.io.AbstractEndPoint;
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.io.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* An AsyncConnection that acts as an interceptor between and EndPoint and another
|
||||
* Connection, that implements TLS encryption using an {@link SSLEngine}.
|
||||
* <p>
|
||||
* The connector uses an {@link EndPoint} (like {@link SelectChannelEndPoint}) as
|
||||
* it's source/sink of encrypted data. It then provides {@link #getAppEndPoint()} to
|
||||
* expose a source/sink of unencrypted data to another connection (eg HttpConnection).
|
||||
*/
|
||||
public class SslConnection extends AbstractAsyncConnection
|
||||
{
|
||||
private static final Logger logger = Log.getLogger(SslConnection.class);
|
||||
private final ByteBufferPool byteBufferPool;
|
||||
private final SSLEngine sslEngine;
|
||||
private final SSLMachine sslMachine;
|
||||
private final AsyncEndPoint appEndPoint;
|
||||
private boolean direct = false;
|
||||
private ReadState readState = ReadState.HANDSHAKING;
|
||||
private WriteState writeState = WriteState.HANDSHAKING;
|
||||
private ByteBuffer appInput;
|
||||
private ByteBuffer netInput;
|
||||
private ByteBuffer netOutput;
|
||||
private Callback appReader;
|
||||
private Object readContext;
|
||||
|
||||
public SslConnection(ByteBufferPool byteBufferPool, Executor executor, AsyncEndPoint endPoint, SSLEngine sslEngine)
|
||||
{
|
||||
super(endPoint, executor);
|
||||
this.byteBufferPool = byteBufferPool;
|
||||
this.sslEngine = sslEngine;
|
||||
this.sslMachine = new ConnectionSSLMachine(sslEngine);
|
||||
this.appEndPoint = new ApplicationEndPoint();
|
||||
}
|
||||
|
||||
public SSLEngine getSSLEngine()
|
||||
{
|
||||
return sslEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
try
|
||||
{
|
||||
super.onOpen();
|
||||
scheduleOnReadable();
|
||||
sslEngine.beginHandshake();
|
||||
}
|
||||
catch (SSLException x)
|
||||
{
|
||||
throw new RuntimeIOException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public AsyncEndPoint getAppEndPoint()
|
||||
{
|
||||
return appEndPoint;
|
||||
}
|
||||
|
||||
private void updateReadState(ReadState newReadState)
|
||||
{
|
||||
ReadState oldReadState = readState;
|
||||
switch (oldReadState)
|
||||
{
|
||||
case HANDSHAKING:
|
||||
{
|
||||
if (newReadState != ReadState.HANDSHAKEN)
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
readState = newReadState;
|
||||
break;
|
||||
}
|
||||
case HANDSHAKEN:
|
||||
{
|
||||
switch (newReadState)
|
||||
{
|
||||
case IDLE:
|
||||
{
|
||||
if (BufferUtil.hasContent(netInput))
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
readState = newReadState;
|
||||
break;
|
||||
}
|
||||
case UNDERFLOW:
|
||||
{
|
||||
if (!BufferUtil.hasContent(netInput))
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
readState = newReadState;
|
||||
break;
|
||||
}
|
||||
case DECRYPTED:
|
||||
{
|
||||
if (!BufferUtil.hasContent(appInput))
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
readState = newReadState;
|
||||
break;
|
||||
}
|
||||
case CLOSED:
|
||||
{
|
||||
if (BufferUtil.hasContent(appInput))
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
readState = newReadState;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
}
|
||||
}
|
||||
}
|
||||
case IDLE:
|
||||
{
|
||||
switch (newReadState)
|
||||
{
|
||||
case UNDERFLOW:
|
||||
{
|
||||
if (!BufferUtil.hasContent(netInput))
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
readState = newReadState;
|
||||
break;
|
||||
}
|
||||
case DECRYPTED:
|
||||
{
|
||||
if (!BufferUtil.hasContent(appInput))
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
readState = newReadState;
|
||||
break;
|
||||
}
|
||||
case CLOSED:
|
||||
{
|
||||
if (BufferUtil.hasContent(appInput))
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
readState = newReadState;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
}
|
||||
}
|
||||
}
|
||||
case DECRYPTED:
|
||||
{
|
||||
switch (newReadState)
|
||||
{
|
||||
case IDLE:
|
||||
{
|
||||
if (BufferUtil.hasContent(netInput))
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
readState = newReadState;
|
||||
break;
|
||||
}
|
||||
case UNDERFLOW:
|
||||
{
|
||||
if (!BufferUtil.hasContent(netInput))
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
readState = newReadState;
|
||||
break;
|
||||
}
|
||||
case CLOSED:
|
||||
{
|
||||
if (BufferUtil.hasContent(appInput))
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
readState = newReadState;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw wrongReadStateUpdate(oldReadState, newReadState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IllegalStateException wrongReadStateUpdate(ReadState oldReadState, ReadState newReadState)
|
||||
{
|
||||
String message = String.format("Invalid read state update: %s => %s", oldReadState, newReadState);
|
||||
return new IllegalStateException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReadable()
|
||||
{
|
||||
if (appInput != null)
|
||||
throw new IllegalStateException();
|
||||
|
||||
switch (readState)
|
||||
{
|
||||
case HANDSHAKING:
|
||||
case IDLE:
|
||||
{
|
||||
if (netInput != null)
|
||||
throw new IllegalStateException();
|
||||
netInput = byteBufferPool.acquire(sslEngine.getSession().getPacketBufferSize(), direct);
|
||||
appInput = byteBufferPool.acquire(sslEngine.getSession().getApplicationBufferSize(), false);
|
||||
break;
|
||||
}
|
||||
case UNDERFLOW:
|
||||
{
|
||||
if (netInput == null)
|
||||
throw new IllegalStateException();
|
||||
BufferUtil.compact(netInput);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException("Unexpected read state " + readState);
|
||||
}
|
||||
}
|
||||
|
||||
AsyncEndPoint endPoint = getEndPoint();
|
||||
try
|
||||
{
|
||||
while (true) // TODO: writes can close the connection, check that also ?
|
||||
{
|
||||
BufferUtil.compact(netInput);
|
||||
int filled = endPoint.fill(netInput);
|
||||
if (filled == 0)
|
||||
{
|
||||
scheduleOnReadable();
|
||||
break;
|
||||
}
|
||||
else if (filled < 0)
|
||||
{
|
||||
updateReadState(ReadState.CLOSED);
|
||||
sslEngine.closeInbound();
|
||||
break;
|
||||
}
|
||||
else if (filled > 0)
|
||||
{
|
||||
boolean readMore = decrypt();
|
||||
if (!readMore)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
endPoint.close();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean decrypt() throws SSLException
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
updateReadState(sslMachine.decrypt(netInput, appInput));
|
||||
switch (readState)
|
||||
{
|
||||
case UNDERFLOW:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
case HANDSHAKEN:
|
||||
{
|
||||
getAppEndPoint().getAsyncConnection().onOpen();
|
||||
if (!netInput.hasRemaining())
|
||||
{
|
||||
updateReadState(ReadState.IDLE);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DECRYPTED:
|
||||
{
|
||||
appReader.completed(readContext);
|
||||
return false;
|
||||
}
|
||||
case CLOSED:
|
||||
{
|
||||
appReader.completed(readContext);
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException("Unexpected read state " + readState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setAllowRenegotiate(boolean allowRenegotiate)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
public class ApplicationEndPoint extends AbstractEndPoint implements AsyncEndPoint
|
||||
{
|
||||
private final AtomicBoolean writing = new AtomicBoolean();
|
||||
private boolean oshut;
|
||||
private Object context;
|
||||
private Callback callback;
|
||||
private ByteBuffer[] buffers;
|
||||
private AsyncConnection connection;
|
||||
|
||||
public ApplicationEndPoint()
|
||||
{
|
||||
super(getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void readable(C context, Callback<C> callback) throws IllegalStateException
|
||||
{
|
||||
if (appReader != null)
|
||||
throw new ReadPendingException();
|
||||
|
||||
switch (readState)
|
||||
{
|
||||
case IDLE:
|
||||
{
|
||||
if (BufferUtil.hasContent(netInput))
|
||||
throw new IllegalStateException();
|
||||
appReader = callback;
|
||||
readContext = context;
|
||||
scheduleOnReadable();
|
||||
break;
|
||||
}
|
||||
case UNDERFLOW:
|
||||
{
|
||||
if (!BufferUtil.hasContent(netInput))
|
||||
throw new IllegalStateException();
|
||||
appReader = callback;
|
||||
readContext = context;
|
||||
scheduleOnReadable();
|
||||
break;
|
||||
}
|
||||
case DECRYPTED:
|
||||
{
|
||||
if (!BufferUtil.hasContent(appInput))
|
||||
throw new IllegalStateException();
|
||||
callback.completed(context);
|
||||
break;
|
||||
}
|
||||
case CLOSED:
|
||||
{
|
||||
if (BufferUtil.hasContent(appInput))
|
||||
throw new IllegalStateException();
|
||||
callback.completed(context);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException("Unexpected read state " + readState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int fill(ByteBuffer buffer) throws IOException
|
||||
{
|
||||
switch (readState)
|
||||
{
|
||||
case IDLE:
|
||||
case UNDERFLOW:
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
case DECRYPTED:
|
||||
{
|
||||
if (!BufferUtil.hasContent(appInput))
|
||||
throw new IllegalStateException();
|
||||
|
||||
int filled = BufferUtil.append(appInput, buffer);
|
||||
if (!BufferUtil.hasContent(appInput))
|
||||
{
|
||||
byteBufferPool.release(appInput);
|
||||
appInput = null;
|
||||
updateReadState(BufferUtil.hasContent(netInput) ? ReadState.UNDERFLOW :
|
||||
sslMachine.isRemoteClosed() ? ReadState.CLOSED : ReadState.IDLE);
|
||||
}
|
||||
return filled;
|
||||
}
|
||||
case CLOSED:
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException("Unexpected read state " + readState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdownOutput()
|
||||
{
|
||||
oshut = true;
|
||||
sslMachine.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutputShutdown()
|
||||
{
|
||||
return oshut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
getEndPoint().close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen()
|
||||
{
|
||||
return getEndPoint().isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTransport()
|
||||
{
|
||||
return getEndPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInputShutdown()
|
||||
{
|
||||
return sslMachine.isRemoteClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int flush(ByteBuffer... appOutputs) throws IOException
|
||||
{
|
||||
switch (writeState)
|
||||
{
|
||||
case HANDSHAKING:
|
||||
{
|
||||
if (netOutput != null)
|
||||
throw new IllegalStateException();
|
||||
netOutput = byteBufferPool.acquire(sslEngine.getSession().getPacketBufferSize(), direct);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException("Unexpected write state " + readState);
|
||||
}
|
||||
}
|
||||
|
||||
ByteBuffer appOutput = appOutputs[0];
|
||||
if (!appOutput.hasRemaining() && appOutputs.length > 1)
|
||||
{
|
||||
for (int i = 1; i < appOutputs.length; ++i)
|
||||
{
|
||||
if (appOutputs[i].hasRemaining())
|
||||
{
|
||||
appOutput = appOutputs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int remaining = appOutput.remaining();
|
||||
sslMachine.encrypt(appOutput, netOutput);
|
||||
int result = remaining - appOutput.remaining();
|
||||
|
||||
getEndPoint().write(null, new Callback<Object>()
|
||||
{
|
||||
@Override
|
||||
public void completed(Object context)
|
||||
{
|
||||
completeWrite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Object context, Throwable x)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}, netOutput);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws IllegalStateException
|
||||
{
|
||||
if (!writing.compareAndSet(false, true))
|
||||
throw new WritePendingException();
|
||||
|
||||
boolean writePending = false;
|
||||
try
|
||||
{
|
||||
flush(buffers);
|
||||
|
||||
for (ByteBuffer buffer : buffers)
|
||||
{
|
||||
if (buffer.hasRemaining())
|
||||
{
|
||||
this.context = context;
|
||||
this.callback = callback;
|
||||
this.buffers = buffers;
|
||||
writePending = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
callback.completed(context);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
callback.failed(context, x);
|
||||
}
|
||||
finally
|
||||
{
|
||||
writing.set(writePending);
|
||||
}
|
||||
}
|
||||
|
||||
private void completeWrite()
|
||||
{
|
||||
if (buffers == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
flush(buffers);
|
||||
|
||||
for (ByteBuffer buffer : buffers)
|
||||
{
|
||||
if (buffer.hasRemaining())
|
||||
return;
|
||||
}
|
||||
|
||||
callback.completed(context);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
callback.failed(context, x);
|
||||
}
|
||||
finally
|
||||
{
|
||||
context = null;
|
||||
callback = null;
|
||||
buffers = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCheckForIdle(boolean check)
|
||||
{
|
||||
getEndPoint().setCheckForIdle(check);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckForIdle()
|
||||
{
|
||||
return getEndPoint().isCheckForIdle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncConnection getAsyncConnection()
|
||||
{
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsyncConnection(AsyncConnection connection)
|
||||
{
|
||||
this.connection = connection;
|
||||
}
|
||||
}
|
||||
|
||||
private class ConnectionSSLMachine extends SSLMachine
|
||||
{
|
||||
private ConnectionSSLMachine(SSLEngine engine)
|
||||
{
|
||||
super(engine);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeForDecrypt(ByteBuffer appOutput)
|
||||
{
|
||||
AsyncEndPoint endPoint = getAppEndPoint();
|
||||
try
|
||||
{
|
||||
endPoint.flush(appOutput);
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
endPoint.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty.io;
|
||||
package org.eclipse.jetty.io.ssl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -25,6 +25,12 @@ import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
|||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.eclipse.jetty.io.AbstractAsyncConnection;
|
||||
import org.eclipse.jetty.io.AbstractEndPoint;
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -39,7 +45,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* it's source/sink of encrypted data. It then provides {@link #getAppEndPoint()} to
|
||||
* expose a source/sink of unencrypted data to another connection (eg HttpConnection).
|
||||
*/
|
||||
public class SslConnection extends AbstractAsyncConnection
|
||||
public class SslConnectionOld extends AbstractAsyncConnection
|
||||
{
|
||||
static final Logger LOG = Log.getLogger("org.eclipse.jetty.io.ssl");
|
||||
|
||||
|
@ -102,16 +108,17 @@ public class SslConnection extends AbstractAsyncConnection
|
|||
_outNet=BufferUtil.allocateDirect(packetSize);
|
||||
_inApp=BufferUtil.allocate(appSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SslConnection(SSLEngine engine,AsyncEndPoint endp,Executor executor)
|
||||
public SslConnectionOld(SSLEngine engine,AsyncEndPoint endp,Executor executor)
|
||||
{
|
||||
this(engine,endp,System.currentTimeMillis(),executor);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public SslConnection(SSLEngine engine,AsyncEndPoint endp, long timeStamp,Executor executor)
|
||||
public SslConnectionOld(SSLEngine engine,AsyncEndPoint endp, long timeStamp,Executor executor)
|
||||
{
|
||||
super(endp, executor);
|
||||
_engine=engine;
|
|
@ -0,0 +1,19 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty.io.ssl;
|
||||
|
||||
enum WriteState
|
||||
{
|
||||
HANDSHAKING, HANDSHAKEN, IDLE, ENCRYPTED, CLOSED
|
||||
}
|
|
@ -10,9 +10,9 @@ import javax.net.ssl.SSLEngineResult;
|
|||
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
|
@ -22,7 +22,8 @@ import org.junit.Test;
|
|||
@Ignore
|
||||
public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
|
||||
{
|
||||
static SslContextFactory __sslCtxFactory=new SslContextFactory();
|
||||
private static SslContextFactory __sslCtxFactory=new SslContextFactory();
|
||||
private static ByteBufferPool __byteBufferPool = new StandardByteBufferPool();
|
||||
|
||||
@BeforeClass
|
||||
public static void initSslEngine() throws Exception
|
||||
|
@ -47,11 +48,11 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
|
|||
{
|
||||
SSLEngine engine = __sslCtxFactory.newSslEngine();
|
||||
engine.setUseClientMode(false);
|
||||
SslConnection connection = new SslConnection(engine,endpoint,_threadPool);
|
||||
SslConnection sslConnection = new SslConnection(__byteBufferPool, _threadPool, endpoint, engine);
|
||||
|
||||
AsyncConnection delegate = super.newConnection(channel,connection.getAppEndPoint());
|
||||
connection.getAppEndPoint().setAsyncConnection(delegate);
|
||||
return connection;
|
||||
AsyncConnection appConnection = super.newConnection(channel,sslConnection.getAppEndPoint());
|
||||
sslConnection.getAppEndPoint().setAsyncConnection(appConnection);
|
||||
return sslConnection;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -172,8 +173,6 @@ public class SelectChannelEndPointSslTest extends SelectChannelEndPointTest
|
|||
|
||||
Assert.assertEquals("HelloWorld",reply);
|
||||
|
||||
SslConnection.LOG.info("javax.net.ssl.SSLException: Inbound closed before... Expected as next line!");
|
||||
if (debug) System.err.println("\nSudden Death");
|
||||
client.socket().shutdownOutput();
|
||||
|
||||
filled=client.read(sslIn);
|
||||
|
|
|
@ -35,6 +35,7 @@ public class SelectChannelEndPointTest
|
|||
protected volatile AsyncEndPoint _lastEndp;
|
||||
protected ServerSocketChannel _connector;
|
||||
protected QueuedThreadPool _threadPool = new QueuedThreadPool();
|
||||
private int maxIdleTimeout = 600000; // TODO: use smaller value
|
||||
protected SelectorManager _manager = new SelectorManager()
|
||||
{
|
||||
@Override
|
||||
|
@ -51,6 +52,7 @@ public class SelectChannelEndPointTest
|
|||
@Override
|
||||
protected void endPointOpened(AsyncEndPoint endpoint)
|
||||
{
|
||||
endpoint.getAsyncConnection().onOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -67,7 +69,7 @@ public class SelectChannelEndPointTest
|
|||
@Override
|
||||
protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException
|
||||
{
|
||||
SelectChannelEndPoint endp = new SelectChannelEndPoint(channel,selectSet,key,2000);
|
||||
SelectChannelEndPoint endp = new SelectChannelEndPoint(channel,selectSet,key,maxIdleTimeout);
|
||||
endp.setAsyncConnection(selectSet.getManager().newConnection(channel,endp, key.attachment()));
|
||||
_lastEndp=endp;
|
||||
return endp;
|
||||
|
@ -104,9 +106,7 @@ public class SelectChannelEndPointTest
|
|||
|
||||
protected AsyncConnection newConnection(SocketChannel channel, AsyncEndPoint endpoint)
|
||||
{
|
||||
AbstractAsyncConnection connection = new TestConnection(endpoint);
|
||||
connection.scheduleOnReadable();
|
||||
return connection;
|
||||
return new TestConnection(endpoint);
|
||||
}
|
||||
|
||||
public class TestConnection extends AbstractAsyncConnection
|
||||
|
@ -120,6 +120,12 @@ public class SelectChannelEndPointTest
|
|||
super(endp,_threadPool);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
scheduleOnReadable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onReadable()
|
||||
{
|
||||
|
@ -233,7 +239,7 @@ public class SelectChannelEndPointTest
|
|||
{
|
||||
Socket client = newClient();
|
||||
|
||||
client.setSoTimeout(60000);
|
||||
client.setSoTimeout(600000); // TODO: restore to smaller value
|
||||
|
||||
SocketChannel server = _connector.accept();
|
||||
server.configureBlocking(false);
|
||||
|
@ -356,7 +362,7 @@ public class SelectChannelEndPointTest
|
|||
OutputStream clientOutputStream = client.getOutputStream();
|
||||
InputStream clientInputStream = client.getInputStream();
|
||||
|
||||
int specifiedTimeout = SslConnection.LOG.isDebugEnabled()?2000:400;
|
||||
int specifiedTimeout = 2000;
|
||||
client.setSoTimeout(specifiedTimeout);
|
||||
|
||||
// Write 8 and cause block waiting for 10
|
||||
|
|
|
@ -3,13 +3,11 @@ package org.eclipse.jetty.server.ssl;
|
|||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -55,7 +53,7 @@ public class SslCertificates
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -76,16 +74,14 @@ public class SslCertificates
|
|||
* client, the next is the one used to authenticate the first, and so on.
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param endpoint
|
||||
* The Socket the request arrived on. This should be a
|
||||
* {@link SocketEndPoint} wrapping a {@link SSLSocket}.
|
||||
*
|
||||
* @param request
|
||||
* HttpRequest to be customised.
|
||||
*/
|
||||
public static void customize(SSLSession sslSession, EndPoint endpoint, Request request) throws IOException
|
||||
public static void customize(SSLEngine sslEngine, Request request) throws IOException
|
||||
{
|
||||
request.setScheme(HttpScheme.HTTPS.asString());
|
||||
SSLSession sslSession = sslEngine.getSession();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -153,7 +149,7 @@ public class SslCertificates
|
|||
{
|
||||
return _keySize;
|
||||
}
|
||||
|
||||
|
||||
String getIdStr()
|
||||
{
|
||||
return _idStr;
|
||||
|
|
|
@ -15,18 +15,15 @@ package org.eclipse.jetty.server.ssl;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.io.SslConnection;
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
|
@ -51,7 +48,7 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Construct with explicit SslContextFactory.
|
||||
* The SslContextFactory passed is added via {@link #addBean(Object)} so that
|
||||
* The SslContextFactory passed is added via {@link #addBean(Object)} so that
|
||||
* it's lifecycle may be managed with {@link AggregateLifeCycle}.
|
||||
* @param sslContextFactory
|
||||
*/
|
||||
|
@ -82,9 +79,6 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
|||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param endpoint
|
||||
* The Socket the request arrived on. This should be a
|
||||
* {@link SocketEndPoint} wrapping a {@link SSLSocket}.
|
||||
* @param request
|
||||
* HttpRequest to be customised.
|
||||
*/
|
||||
|
@ -94,12 +88,9 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
|||
request.setScheme(HttpScheme.HTTPS.asString());
|
||||
super.customize(request);
|
||||
|
||||
EndPoint endpoint = request.getHttpChannel().getConnection().getEndPoint();
|
||||
SslConnection.AppEndPoint sslEndpoint=(SslConnection.AppEndPoint)endpoint;
|
||||
SSLEngine sslEngine=sslEndpoint.getSslEngine();
|
||||
SSLSession sslSession=sslEngine.getSession();
|
||||
|
||||
SslCertificates.customize(sslSession,endpoint,request);
|
||||
SslConnection sslConnection = (SslConnection)request.getHttpChannel().getConnection();
|
||||
SSLEngine sslEngine=sslConnection.getSSLEngine();
|
||||
SslCertificates.customize(sslEngine,request);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -563,7 +554,7 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
|||
|
||||
protected SslConnection newSslConnection(AsyncEndPoint endpoint, SSLEngine engine)
|
||||
{
|
||||
return new SslConnection(engine, endpoint,findExecutor());
|
||||
return new SslConnection(getByteBufferPool(), findExecutor(), endpoint, engine);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -624,5 +615,4 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
|||
{
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,10 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.matchers.JUnitMatchers.containsString;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -24,19 +20,22 @@ import java.net.Socket;
|
|||
import java.net.SocketException;
|
||||
import java.util.concurrent.Exchanger;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.SslConnection;
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.matchers.JUnitMatchers.containsString;
|
||||
|
||||
public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
||||
{
|
||||
protected static final int MAX_IDLE_TIME=250;
|
||||
|
@ -149,8 +148,8 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
|||
|
||||
// Get the server side endpoint
|
||||
EndPoint endp = endpoint.exchange(null,10,TimeUnit.SECONDS);
|
||||
if (endp instanceof SslConnection.AppEndPoint)
|
||||
endp=((SslConnection.AppEndPoint)endp).getEndpoint();
|
||||
if (endp instanceof SslConnection.ApplicationEndPoint)
|
||||
endp=((SslConnection.ApplicationEndPoint)endp).getEndpoint();
|
||||
|
||||
// read the response
|
||||
String result=IO.toString(is);
|
||||
|
|
|
@ -53,15 +53,29 @@ public class SPDYAsyncConnection extends AbstractAsyncConnection implements Cont
|
|||
BufferUtil.clear(buffer);
|
||||
read(buffer);
|
||||
bufferPool.release(buffer);
|
||||
scheduleOnReadable();
|
||||
}
|
||||
|
||||
protected void read(ByteBuffer buffer)
|
||||
{
|
||||
AsyncEndPoint endPoint = getEndPoint();
|
||||
int filled = fill(endPoint, buffer);
|
||||
if (filled < 0)
|
||||
close(false);
|
||||
parser.parse(buffer);
|
||||
while (true)
|
||||
{
|
||||
int filled = fill(endPoint, buffer);
|
||||
if (filled == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (filled < 0)
|
||||
{
|
||||
close(false);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
parser.parse(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int fill(AsyncEndPoint endPoint, ByteBuffer buffer)
|
||||
|
|
|
@ -47,8 +47,8 @@ import org.eclipse.jetty.io.AsyncEndPoint;
|
|||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.SelectChannelEndPoint;
|
||||
import org.eclipse.jetty.io.SelectorManager;
|
||||
import org.eclipse.jetty.io.SslConnection;
|
||||
import org.eclipse.jetty.io.StandardByteBufferPool;
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.npn.NextProtoNego;
|
||||
import org.eclipse.jetty.spdy.api.Session;
|
||||
import org.eclipse.jetty.spdy.api.SessionFrameListener;
|
||||
|
|
|
@ -36,8 +36,8 @@ import javax.net.ssl.SSLException;
|
|||
import org.eclipse.jetty.io.AsyncConnection;
|
||||
import org.eclipse.jetty.io.AsyncEndPoint;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.SslConnection;
|
||||
import org.eclipse.jetty.io.StandardByteBufferPool;
|
||||
import org.eclipse.jetty.io.ssl.SslConnection;
|
||||
import org.eclipse.jetty.npn.NextProtoNego;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.spdy.api.SPDY;
|
||||
|
|
Loading…
Reference in New Issue