|
|
|
|
@@ -99,7 +99,7 @@ public class WebServer {
|
|
|
|
|
/** Flag indicating whether the web server is active. The attributes cannot be changed in a thread unsafe manner when this is set. */
|
|
|
|
|
private volatile boolean isStarted = false;
|
|
|
|
|
/** Whether to report all errors. If false, many networking errors (usually results of browsers terminating connections) will not be reported. */
|
|
|
|
|
private boolean debug = true;
|
|
|
|
|
private boolean debug = false;
|
|
|
|
|
/** The handler called on to get a result for a bad request. */
|
|
|
|
|
private IWebServerErrorHandler errorHandler = null;
|
|
|
|
|
/** The maximum length of any request's content block. */
|
|
|
|
|
@@ -315,23 +315,16 @@ public class WebServer {
|
|
|
|
|
* Closes the socket context and cleans up.
|
|
|
|
|
*/
|
|
|
|
|
protected abstract void close();
|
|
|
|
|
protected AbstractSocketContext getRelatedSocketContext() {
|
|
|
|
|
return relatedSocketContext;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
protected void setFlags(int flags) {
|
|
|
|
|
this.flags = flags;
|
|
|
|
|
}
|
|
|
|
|
protected int getFlags() {
|
|
|
|
|
return flags;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Gets the socket context related to this one (when two are tied together such that data from one immediately is sent to the other).
|
|
|
|
|
* @return The related socket context, or null if none exists (data not forwarded to a remote server).
|
|
|
|
|
*/
|
|
|
|
|
protected AbstractSocketContext getRelatedSocketContext() {return relatedSocketContext;}
|
|
|
|
|
/**
|
|
|
|
|
* Updates the write flag status.
|
|
|
|
|
* @param requiresWrite Whether a write is required.
|
|
|
|
|
*/
|
|
|
|
|
protected void flagWrite(boolean requiresWrite) {
|
|
|
|
|
|
|
|
|
|
synchronized(key) {
|
|
|
|
|
int ops = key.interestOps();
|
|
|
|
|
boolean hasWrite = (ops & SelectionKey.OP_WRITE) != 0;
|
|
|
|
|
@@ -347,26 +340,12 @@ public class WebServer {
|
|
|
|
|
}//if//
|
|
|
|
|
}//else//
|
|
|
|
|
}//synchronized//
|
|
|
|
|
|
|
|
|
|
// boolean hasWrite = (flags & SelectionKey.OP_WRITE) != 0;
|
|
|
|
|
//
|
|
|
|
|
// if(requiresWrite) {
|
|
|
|
|
// if(!hasWrite) {
|
|
|
|
|
// flags |= SelectionKey.OP_WRITE;
|
|
|
|
|
// }//if//
|
|
|
|
|
// }//if//
|
|
|
|
|
// else {
|
|
|
|
|
// if(hasWrite) {
|
|
|
|
|
// flags ^= SelectionKey.OP_WRITE;
|
|
|
|
|
// }//if//
|
|
|
|
|
// }//else//
|
|
|
|
|
}//flagWrite()//
|
|
|
|
|
/**
|
|
|
|
|
* Updates the read flag status.
|
|
|
|
|
* @param requiresRead Whether a read is required.
|
|
|
|
|
*/
|
|
|
|
|
protected void flagRead(boolean requiresRead) {
|
|
|
|
|
|
|
|
|
|
synchronized(key) {
|
|
|
|
|
int ops = key.interestOps();
|
|
|
|
|
boolean hasRead = (ops & SelectionKey.OP_READ) != 0;
|
|
|
|
|
@@ -382,19 +361,6 @@ public class WebServer {
|
|
|
|
|
}//if//
|
|
|
|
|
}//else//
|
|
|
|
|
}//synchronized//
|
|
|
|
|
|
|
|
|
|
// boolean hasRead = (flags & SelectionKey.OP_READ) != 0;
|
|
|
|
|
//
|
|
|
|
|
// if(requiresRead) {
|
|
|
|
|
// if(!hasRead) {
|
|
|
|
|
// flags |= SelectionKey.OP_READ;
|
|
|
|
|
// }//if//
|
|
|
|
|
// }//if//
|
|
|
|
|
// else {
|
|
|
|
|
// if(hasRead) {
|
|
|
|
|
// flags ^= SelectionKey.OP_READ;
|
|
|
|
|
// }//if//
|
|
|
|
|
// }//else//
|
|
|
|
|
}//flagWrite()//
|
|
|
|
|
protected void flagReadWrite(boolean requiresRead, boolean requiresWrite) {
|
|
|
|
|
synchronized(key) {
|
|
|
|
|
@@ -431,19 +397,16 @@ public class WebServer {
|
|
|
|
|
synchronized(key) {
|
|
|
|
|
key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
|
|
|
|
|
}//synchronized//
|
|
|
|
|
// flags = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
|
|
|
|
|
}//flagReadWrite()//
|
|
|
|
|
protected void flagWriteOnly() {
|
|
|
|
|
synchronized(key) {
|
|
|
|
|
key.interestOps(SelectionKey.OP_WRITE);
|
|
|
|
|
}//synchronized//
|
|
|
|
|
// flags = SelectionKey.OP_WRITE;
|
|
|
|
|
}//flagWriteOnly()//
|
|
|
|
|
protected void flagReadOnly() {
|
|
|
|
|
synchronized(key) {
|
|
|
|
|
key.interestOps(SelectionKey.OP_READ);
|
|
|
|
|
}//synchronized//
|
|
|
|
|
// flags = SelectionKey.OP_READ;
|
|
|
|
|
}//flagReadOnly()//
|
|
|
|
|
}//AbstractSocketContext//
|
|
|
|
|
|
|
|
|
|
@@ -634,6 +597,7 @@ public class WebServer {
|
|
|
|
|
//Debug.log("Posting request content to Git.");
|
|
|
|
|
pendingMessageBuffer = lastAddedMessageBuffer = message;
|
|
|
|
|
flagReadWrite();
|
|
|
|
|
// flagWrite(true);
|
|
|
|
|
}//if//
|
|
|
|
|
else {
|
|
|
|
|
//TODO: Comment me.
|
|
|
|
|
@@ -1132,6 +1096,7 @@ public class WebServer {
|
|
|
|
|
writeClientResponse();
|
|
|
|
|
//Set the write flag if we have more to write.//
|
|
|
|
|
flagReadWrite(true, pendingOutboundMessage != null);
|
|
|
|
|
// flagWrite(pendingOutboundMessage != null);
|
|
|
|
|
}//synchronized//
|
|
|
|
|
}//if//
|
|
|
|
|
else {
|
|
|
|
|
@@ -1143,6 +1108,7 @@ public class WebServer {
|
|
|
|
|
}//if//
|
|
|
|
|
else {
|
|
|
|
|
flagReadWrite();
|
|
|
|
|
// flagWriteOnly();
|
|
|
|
|
}//else//
|
|
|
|
|
}//else//
|
|
|
|
|
}//processCurrentResponse()//
|
|
|
|
|
@@ -1309,7 +1275,6 @@ public class WebServer {
|
|
|
|
|
if(result && pendingOutboundMessage != null) {
|
|
|
|
|
//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(result && !pendingOutboundMessage.getBuffer().hasRemaining()) {
|
|
|
|
|
/*
|
|
|
|
|
if(!pendingOutboundMessage.loadBuffer()) {
|
|
|
|
|
if(pendingOutboundMessage.getNext() != null) {
|
|
|
|
|
pendingOutboundMessage = pendingOutboundMessage.getNext();
|
|
|
|
|
@@ -1323,7 +1288,7 @@ public class WebServer {
|
|
|
|
|
pendingOutboundMessage = null;
|
|
|
|
|
lastAddedMessageBuffer = null;
|
|
|
|
|
}//if//
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
//Attempt to load additional message bytes into the buffer.//
|
|
|
|
|
boolean couldLoadAdditionalBytes = pendingOutboundMessage.loadBuffer();
|
|
|
|
|
@@ -1346,6 +1311,7 @@ public class WebServer {
|
|
|
|
|
//Wait until additional message bytes are available.//
|
|
|
|
|
result = false;
|
|
|
|
|
}//else if//
|
|
|
|
|
*/
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
//If we have an application response pending then send it now.//
|
|
|
|
|
@@ -1418,6 +1384,7 @@ public class WebServer {
|
|
|
|
|
//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() && pendingOutboundMessage != null) {
|
|
|
|
|
/*
|
|
|
|
|
//Attempt to load additional message bytes into the buffer.//
|
|
|
|
|
boolean couldLoadAdditionalBytes = pendingOutboundMessage.loadBuffer();
|
|
|
|
|
|
|
|
|
|
@@ -1439,6 +1406,24 @@ public class WebServer {
|
|
|
|
|
//Wait until additional message bytes are available.//
|
|
|
|
|
result = false;
|
|
|
|
|
}//else if//
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if(!pendingOutboundMessage.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(pendingOutboundMessage.getNext() != null) {
|
|
|
|
|
pendingOutboundMessage = pendingOutboundMessage.getNext();
|
|
|
|
|
}//if//
|
|
|
|
|
else {
|
|
|
|
|
//Wait until additional message bytes are available.//
|
|
|
|
|
result = false;
|
|
|
|
|
}//else//
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
//If the message end has been reached then the buffer will be null.//
|
|
|
|
|
if(pendingOutboundMessage.getBuffer() == null) {
|
|
|
|
|
pendingOutboundMessage = null;
|
|
|
|
|
lastAddedMessageBuffer = null;
|
|
|
|
|
}//if//
|
|
|
|
|
}//if//
|
|
|
|
|
}//while//
|
|
|
|
|
}//if//
|
|
|
|
|
@@ -1458,21 +1443,23 @@ public class WebServer {
|
|
|
|
|
result = false;
|
|
|
|
|
}//if//
|
|
|
|
|
else {
|
|
|
|
|
/*
|
|
|
|
|
if(!pendingOutboundMessage.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(pendingOutboundMessage.getNext() != null) {
|
|
|
|
|
pendingOutboundMessage = pendingOutboundMessage.getNext();
|
|
|
|
|
}//if//
|
|
|
|
|
else {
|
|
|
|
|
//Wait until additional message bytes are available.//
|
|
|
|
|
result = false;
|
|
|
|
|
}//else//
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
//If the message end has been reached then the buffer will be null.//
|
|
|
|
|
if(pendingOutboundMessage.getBuffer() == null) {
|
|
|
|
|
pendingOutboundMessage = null;
|
|
|
|
|
lastAddedMessageBuffer = null;
|
|
|
|
|
}//if//
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
//Attempt to load additional message bytes into the buffer.//
|
|
|
|
|
boolean couldLoadAdditionalBytes = pendingOutboundMessage.loadBuffer();
|
|
|
|
|
@@ -1495,6 +1482,7 @@ public class WebServer {
|
|
|
|
|
//Wait until additional message bytes are available.//
|
|
|
|
|
result = false;
|
|
|
|
|
}//else if//
|
|
|
|
|
*/
|
|
|
|
|
}//else//
|
|
|
|
|
}//while//
|
|
|
|
|
}//else//
|
|
|
|
|
@@ -1792,6 +1780,7 @@ public class WebServer {
|
|
|
|
|
}//if//
|
|
|
|
|
else {
|
|
|
|
|
flagReadWrite();
|
|
|
|
|
// flagWriteOnly();
|
|
|
|
|
}//else//
|
|
|
|
|
}//processRequest()//
|
|
|
|
|
}//SocketContext//
|
|
|
|
|
@@ -2060,10 +2049,6 @@ public class WebServer {
|
|
|
|
|
if(channel != null && !socketClosed && channel.isOpen() && key != null && context != null) {
|
|
|
|
|
requiresWakeup = true;
|
|
|
|
|
|
|
|
|
|
// //Set the flags (either READ/WRITE) for the socket.//
|
|
|
|
|
// synchronized(key) {
|
|
|
|
|
// key.interestOps(((AbstractSocketContext) context).getFlags());
|
|
|
|
|
// }//synchronized//
|
|
|
|
|
}//if//
|
|
|
|
|
else if(channel != null && (!channel.isOpen() || socketClosed) && channel instanceof SocketChannel && context instanceof SocketContext) {
|
|
|
|
|
cleanupClientChannel((SocketContext) context, (SocketChannel) channel);
|
|
|
|
|
@@ -2074,12 +2059,10 @@ public class WebServer {
|
|
|
|
|
if(activeThreadCount-- != maxThreadCount) {
|
|
|
|
|
loop = false;
|
|
|
|
|
|
|
|
|
|
// if(requiresWakeup) {
|
|
|
|
|
// selector.wakeup();
|
|
|
|
|
// }//if//
|
|
|
|
|
}//if//
|
|
|
|
|
|
|
|
|
|
if(requiresWakeup) {
|
|
|
|
|
selector.wakeup();
|
|
|
|
|
}//if//
|
|
|
|
|
}//if//
|
|
|
|
|
}//synchronized//
|
|
|
|
|
}//finally//
|
|
|
|
|
}//else if//
|
|
|
|
|
@@ -3304,7 +3287,7 @@ private boolean processClientRequest(SocketContext context, final Request reques
|
|
|
|
|
|
|
|
|
|
//Save the session immediately since the requested resource might not indicate to the application that the session was updated.//
|
|
|
|
|
//Note: We shouldn't have any problems with multiple threads from the same client each creating their own session data since every browser should start with a single thread requesting a single resource before multiple threads are used to download all the child resources.//
|
|
|
|
|
if(session != null && hasNewSessionData) {
|
|
|
|
|
if(hasNewSessionData && session != null) {
|
|
|
|
|
//Store the session store in the db.//
|
|
|
|
|
session.updateRepository();
|
|
|
|
|
}//if//
|
|
|
|
|
|