|
|
|
|
@@ -497,7 +497,7 @@ private void prepareResponse(Response response) {
|
|
|
|
|
buffer = ByteBuffer.allocate(headerBytes.length > 2000 ? headerBytes.length : 2000);
|
|
|
|
|
buffer.put(headerBytes);
|
|
|
|
|
|
|
|
|
|
if(getWebServer().debug) {
|
|
|
|
|
if(getWebServer().debug()) {
|
|
|
|
|
//Test code...
|
|
|
|
|
ByteBuffer buffer2 = ByteBuffer.allocate(headerBytes.length);
|
|
|
|
|
buffer2.put(headerBytes);
|
|
|
|
|
@@ -744,9 +744,10 @@ private synchronized void internalProcessResponses() {
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
//If we finished sending the current response then load the next one.//
|
|
|
|
|
if(messageSent) {
|
|
|
|
|
if(messageSent || (currentOutboundMessage != null && currentOutboundMessage.isClosed())) {
|
|
|
|
|
//TODO: Queue up the next outbound message.
|
|
|
|
|
currentOutboundMessage = null;
|
|
|
|
|
lastOutboundMessage = null;
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
if(currentOutboundMessage == null) {
|
|
|
|
|
@@ -799,7 +800,7 @@ private boolean writeClientBoundMessage() {
|
|
|
|
|
boolean sendMore = true;
|
|
|
|
|
|
|
|
|
|
if(sslEngine != null) {
|
|
|
|
|
sendMore = writeClientBoundSslMessage();
|
|
|
|
|
sendMore = writeClientBoundSslMessage((SocketChannel) key.channel(), currentOutboundMessage);
|
|
|
|
|
}//if//
|
|
|
|
|
else {
|
|
|
|
|
sendMore = writeClientBoundPlainMessage();
|
|
|
|
|
@@ -811,7 +812,7 @@ private boolean writeClientBoundMessage() {
|
|
|
|
|
* Sends a response to the client.
|
|
|
|
|
* @return Whether the response could be fully sent. This will be false if there is still more data to be written when the call returns.
|
|
|
|
|
*/
|
|
|
|
|
private boolean writeClientBoundSslMessage() {
|
|
|
|
|
private boolean writeClientBoundSslMessage(SocketChannel channel, MessageBuffer currentOutboundMessage) {
|
|
|
|
|
boolean sendMore = true;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
@@ -820,10 +821,18 @@ private boolean writeClientBoundSslMessage() {
|
|
|
|
|
int remaining = encryptedWriteBuffer.remaining();
|
|
|
|
|
|
|
|
|
|
//Write the bytes to the stream.//
|
|
|
|
|
((SocketChannel) key.channel()).write(encryptedWriteBuffer);
|
|
|
|
|
channel.write(encryptedWriteBuffer);
|
|
|
|
|
|
|
|
|
|
if(getWebServer().debug()) {
|
|
|
|
|
Debug.log(this.getId() + "|" + System.nanoTime() + "|Wrote " + (remaining - encryptedWriteBuffer.remaining()) + " encrypted bytes to the stream. " + encryptedWriteBuffer.remaining() + " remain.");
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
//Check to see if we failed to send the whole frame.//
|
|
|
|
|
if(encryptedWriteBuffer.hasRemaining()) {
|
|
|
|
|
if(getWebServer().debug()) {
|
|
|
|
|
Debug.log(this.getId() + "|" + System.nanoTime() + "|Bytes remain in the encrypted write buffer. Flagging that more needs to be sent at a later time.");
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
sendMore = false;
|
|
|
|
|
}//if//
|
|
|
|
|
}//if//
|
|
|
|
|
@@ -831,6 +840,10 @@ private boolean writeClientBoundSslMessage() {
|
|
|
|
|
while(sendMore && sslNeedsWrap) {
|
|
|
|
|
SSLEngineResult handshakeResult;
|
|
|
|
|
|
|
|
|
|
if(getWebServer().debug()) {
|
|
|
|
|
Debug.log(this.getId() + "|" + System.nanoTime() + "|SSL handshaking with the client.");
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
//Reset the encrypted write buffer - note that since we will never read while waiting to write data, this should always be empty.//
|
|
|
|
|
encryptedWriteBuffer.position(0);
|
|
|
|
|
encryptedWriteBuffer.limit(encryptedWriteBuffer.capacity());
|
|
|
|
|
@@ -859,10 +872,8 @@ private boolean writeClientBoundSslMessage() {
|
|
|
|
|
Debug.log(new RuntimeException("Unexpected ssl engine task."));
|
|
|
|
|
}//if//
|
|
|
|
|
else if(encryptedWriteBuffer.hasRemaining()) {
|
|
|
|
|
int remaining = encryptedWriteBuffer.remaining();
|
|
|
|
|
|
|
|
|
|
//Write the bytes to the stream.//
|
|
|
|
|
((SocketChannel) key.channel()).write(encryptedWriteBuffer);
|
|
|
|
|
channel.write(encryptedWriteBuffer);
|
|
|
|
|
|
|
|
|
|
//If not all the bytes could be written then we will need to wait until we can write more.//
|
|
|
|
|
if(encryptedWriteBuffer.hasRemaining()) {
|
|
|
|
|
@@ -885,21 +896,15 @@ private boolean writeClientBoundSslMessage() {
|
|
|
|
|
}//else//
|
|
|
|
|
}//while//
|
|
|
|
|
|
|
|
|
|
if(sendMore && currentOutboundMessage != null) {
|
|
|
|
|
if(sendMore && currentOutboundMessage != null && !currentOutboundMessage.isClosed()) {
|
|
|
|
|
//Check to see if the outbound message is prepared to send more content. For chunked transfers the outbound message may be waiting for additional content from another stream and we should return later.//
|
|
|
|
|
if(!currentOutboundMessage.getBuffer().hasRemaining()) {
|
|
|
|
|
if(!currentOutboundMessage.loadBuffer()) {
|
|
|
|
|
if(currentOutboundMessage.getBuffer() == null && currentOutboundMessage.getNext() != null) {
|
|
|
|
|
currentOutboundMessage = currentOutboundMessage.getNext();
|
|
|
|
|
}//if//
|
|
|
|
|
else {
|
|
|
|
|
sendMore = false;
|
|
|
|
|
}//else//
|
|
|
|
|
sendMore = false;
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
if(currentOutboundMessage.getBuffer() == null) {
|
|
|
|
|
currentOutboundMessage = null;
|
|
|
|
|
lastOutboundMessage = null;
|
|
|
|
|
}//if//
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
@@ -928,18 +933,12 @@ private boolean writeClientBoundSslMessage() {
|
|
|
|
|
// Debug.log(new RuntimeException("Unexpected ssl engine closed."));
|
|
|
|
|
//TODO: Handle this closure without an infinate loop...
|
|
|
|
|
//Close the socket.//
|
|
|
|
|
try {key.channel().close();} catch(Throwable e2) {}
|
|
|
|
|
try {channel.close();} catch(Throwable e2) {}
|
|
|
|
|
}//else if//
|
|
|
|
|
else if(encryptResult.getStatus() == Status.OK) {
|
|
|
|
|
//Write the bytes to the stream.//
|
|
|
|
|
try {
|
|
|
|
|
int remaining = encryptedWriteBuffer.remaining();
|
|
|
|
|
|
|
|
|
|
((SocketChannel) key.channel()).write(encryptedWriteBuffer);
|
|
|
|
|
|
|
|
|
|
// if(getWebServer().debug) {
|
|
|
|
|
// debugBuffer.append("Sent " + (remaining - encryptedWriteBuffer.remaining()) + " encrypted bytes.\n");
|
|
|
|
|
// }//if//
|
|
|
|
|
channel.write(encryptedWriteBuffer);
|
|
|
|
|
}//try//
|
|
|
|
|
catch(IOException e) {
|
|
|
|
|
//Caught if the channel is forcably closed by the client. We will ignore it.//
|
|
|
|
|
@@ -949,10 +948,6 @@ private boolean writeClientBoundSslMessage() {
|
|
|
|
|
if(encryptedWriteBuffer.hasRemaining()) {
|
|
|
|
|
//Leave the data in the encrypted write buffer for the writing operation to send it.//
|
|
|
|
|
sendMore = false;
|
|
|
|
|
|
|
|
|
|
// if(getWebServer().debug) {
|
|
|
|
|
// debugBuffer.append("Pausing due to a partially sent packet. Bytes actually sent: " + encryptedWriteBuffer.position() + ". Bytes remaining: " + encryptedWriteBuffer.remaining() + ".\n");
|
|
|
|
|
// }//if//
|
|
|
|
|
}//if//
|
|
|
|
|
}//else if//
|
|
|
|
|
else {
|
|
|
|
|
@@ -962,22 +957,15 @@ private boolean writeClientBoundSslMessage() {
|
|
|
|
|
|
|
|
|
|
//Add more content to the buffer.//
|
|
|
|
|
//Note: Do this even if the last encrypted write buffer could not be fully sent - so that when it is sent there will be outbound message content.//
|
|
|
|
|
if(key.channel().isOpen() && currentOutboundMessage != null) {
|
|
|
|
|
if(channel.isOpen() && currentOutboundMessage != null) {
|
|
|
|
|
if(!currentOutboundMessage.loadBuffer()) {
|
|
|
|
|
//Load the next pending outbound message in the chain. This is currently only used for content being passed through to another process via a second socket.//
|
|
|
|
|
if(currentOutboundMessage.getBuffer() == null && currentOutboundMessage.getNext() != null) {
|
|
|
|
|
currentOutboundMessage = currentOutboundMessage.getNext();
|
|
|
|
|
}//if//
|
|
|
|
|
else {
|
|
|
|
|
//Wait until additional message bytes are available.//
|
|
|
|
|
sendMore = false;
|
|
|
|
|
}//else//
|
|
|
|
|
//Wait until additional message bytes are available.//
|
|
|
|
|
sendMore = false;
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
//If the message end has been reached then the buffer will be null.//
|
|
|
|
|
if(currentOutboundMessage.getBuffer() == null) {
|
|
|
|
|
currentOutboundMessage = null;
|
|
|
|
|
lastOutboundMessage = null;
|
|
|
|
|
}//if//
|
|
|
|
|
}//if//
|
|
|
|
|
}//while//
|
|
|
|
|
@@ -988,14 +976,14 @@ private boolean writeClientBoundSslMessage() {
|
|
|
|
|
close();
|
|
|
|
|
}//catch//
|
|
|
|
|
catch(SSLException e) {
|
|
|
|
|
if(getWebServer().debug) {
|
|
|
|
|
if(getWebServer().debug()) {
|
|
|
|
|
Debug.log(e);
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
close();
|
|
|
|
|
}//catch//
|
|
|
|
|
catch(IOException e) {
|
|
|
|
|
if(getWebServer().debug) {
|
|
|
|
|
if(getWebServer().debug()) {
|
|
|
|
|
Debug.log(e);
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
@@ -1067,14 +1055,14 @@ private boolean writeClientBoundPlainMessage() {
|
|
|
|
|
close();
|
|
|
|
|
}//catch//
|
|
|
|
|
catch(SSLException e) {
|
|
|
|
|
if(getWebServer().debug) {
|
|
|
|
|
if(getWebServer().debug()) {
|
|
|
|
|
Debug.log(e);
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
close();
|
|
|
|
|
}//catch//
|
|
|
|
|
catch(IOException e) {
|
|
|
|
|
if(getWebServer().debug) {
|
|
|
|
|
if(getWebServer().debug()) {
|
|
|
|
|
Debug.log(e);
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
@@ -1235,7 +1223,7 @@ protected void readIncomingMessages() throws IOException {
|
|
|
|
|
}//if//
|
|
|
|
|
else if(sslResult.getStatus() == Status.BUFFER_OVERFLOW) {
|
|
|
|
|
//Should never happen.//
|
|
|
|
|
// if(getWebServer().debug) Debug.log(new RuntimeException("Unexpected ssl engine buffer overflow."));
|
|
|
|
|
// if(getWebServer().debug())) Debug.log(new RuntimeException("Unexpected ssl engine buffer overflow."));
|
|
|
|
|
close();
|
|
|
|
|
}//else if//
|
|
|
|
|
else if(sslResult.getStatus() == Status.CLOSED) {
|
|
|
|
|
@@ -1712,7 +1700,7 @@ private boolean processClientRequest(ByteBuffer fragment, SelectionKey key) thro
|
|
|
|
|
if(isCompleteHeader(messageHeaderFragment)) {
|
|
|
|
|
IWebApplication application = webApplicationContainer != null ? webApplicationContainer.getWebApplication() : null;
|
|
|
|
|
|
|
|
|
|
// if(getWebServer().debug) {
|
|
|
|
|
// if(getWebServer().debug())) {
|
|
|
|
|
// context.debugBuffer.append("Processing:\r\n" + context.messageHeaderFragment.toString());
|
|
|
|
|
// }//if//
|
|
|
|
|
|
|
|
|
|
@@ -1720,8 +1708,8 @@ private boolean processClientRequest(ByteBuffer fragment, SelectionKey key) thro
|
|
|
|
|
try {
|
|
|
|
|
request = new Request(++lastRequestNumber, messageHeaderFragment.toString(), ((SocketChannel) key.channel()).socket().getInetAddress().getHostAddress(), this, this, isSsl());
|
|
|
|
|
|
|
|
|
|
//Log the request header if running in getWebServer().debug mode.//
|
|
|
|
|
if(getWebServer().debug) {
|
|
|
|
|
//Log the request header if running in getWebServer().debug() mode.//
|
|
|
|
|
if(getWebServer().debug()) {
|
|
|
|
|
Debug.log(request.toString());
|
|
|
|
|
}//if//
|
|
|
|
|
}//try//
|
|
|
|
|
@@ -1764,11 +1752,11 @@ private boolean processClientRequest(ByteBuffer fragment, SelectionKey key) thro
|
|
|
|
|
int contentLength = 0;
|
|
|
|
|
|
|
|
|
|
//TODO: Remove
|
|
|
|
|
if(getWebServer().debug) {
|
|
|
|
|
if(getWebServer().debug()) {
|
|
|
|
|
boolean sessionFound = application.getSession(request.getSessionId()) != null;
|
|
|
|
|
boolean canRecreate = request.getSessionId() != null;
|
|
|
|
|
|
|
|
|
|
Debug.log("SC: " + id + "; Req#: " + request.getRequestNumber() + "; ReqURI: " + request.getUri() + "\n\t(SessionId: " + request.getSessionId() + "; SecureSessionId: " + request.getSecureSessionId() + ")\n\tSession Found: " + sessionFound + (!sessionFound ? "; Can Recreate: " + canRecreate : ""));
|
|
|
|
|
Debug.log("SC: " + getId() + "; Req#: " + request.getRequestNumber() + "; ReqURI: " + request.getUri() + "\n\t(SessionId: " + request.getSessionId() + "; SecureSessionId: " + request.getSecureSessionId() + ")\n\tSession Found: " + sessionFound + (!sessionFound ? "; Can Recreate: " + canRecreate : ""));
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
request.setSession(application.getSession(request.getSessionId()));
|
|
|
|
|
@@ -1790,7 +1778,7 @@ private boolean processClientRequest(ByteBuffer fragment, SelectionKey key) thro
|
|
|
|
|
//This is a security mechanism because the client is SUPPOSED to keep the secure session ID very private and not allow access to it by other sites. It ensures that a recreated session actually comes from a client that had it created in the first place.//
|
|
|
|
|
if(request.getSecureSessionId() != null && request.getSession() != null && request.getSession().getSecureSessionId() != null) {
|
|
|
|
|
if(!Comparator.equals(request.getSecureSessionId(), request.getSession().getSecureSessionId())) {
|
|
|
|
|
Debug.log("SC: " + id + "Forcing connection closure.");
|
|
|
|
|
Debug.log("SC: " + getId() + "Forcing connection closure.");
|
|
|
|
|
//Force the connection to the client to be closed.//
|
|
|
|
|
try {key.channel().close();}catch(Throwable e2) {}
|
|
|
|
|
//Throw an exception that should not be logged. This might happen when an attacker tries to reuse stored session data on a client.//
|
|
|
|
|
@@ -2203,8 +2191,8 @@ private boolean processClientRequest(final Request request, SelectionKey key) th
|
|
|
|
|
|
|
|
|
|
if(session == null) {
|
|
|
|
|
//TODO: Remove
|
|
|
|
|
if(getWebServer().debug) {
|
|
|
|
|
Debug.log("SC: " + id + " Creating Session");
|
|
|
|
|
if(getWebServer().debug()) {
|
|
|
|
|
Debug.log("SC: " + getId() + " Creating Session");
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
request.setSession(session = application.createSession());
|
|
|
|
|
@@ -2225,13 +2213,13 @@ private boolean processClientRequest(final Request request, SelectionKey key) th
|
|
|
|
|
allowSecureAccess = true;
|
|
|
|
|
}//if//
|
|
|
|
|
else {
|
|
|
|
|
Debug.log(new RuntimeException("Error: The client did not send the correct secure session id with the request!"));
|
|
|
|
|
Debug.log(new RuntimeException("Error: The client did not send the correct secure session getId() with the request!"));
|
|
|
|
|
}//else//
|
|
|
|
|
}//if//
|
|
|
|
|
else if(session != null && session.getSecureSessionId() == null) {
|
|
|
|
|
//TODO: Remove
|
|
|
|
|
if(getWebServer().debug) {
|
|
|
|
|
Debug.log("SC: " + id + " Creating Secure Session");
|
|
|
|
|
if(getWebServer().debug()) {
|
|
|
|
|
Debug.log("SC: " + getId() + " Creating Secure Session");
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
application.createSecureSession(session);
|
|
|
|
|
|