StateMachineAlgorithmpublic final class StateMachineAlgorithm extends StreamAlgorithmBase Predict if the NIO channel has been fully read or not. This lagorithm will
first search for the content-length header, and use that value to determine if
the bytes has been fully read or not. If the content-length isn't included,
it will search for the end of the HTTP stream, which is a '\r\n' |
Constructors Summary |
---|
public StateMachineAlgorithm()
if (embeddedInGlassFish){
handler = new NoParsingHandler();
} else {
handler = new DummyHandler();
}
|
Methods Summary |
---|
public com.sun.enterprise.web.connector.grizzly.Handler | getHandler()Return the Handler used by this algorithm.
return handler;
| public java.lang.Class | getReadTask(com.sun.enterprise.web.connector.grizzly.SelectorThread selectorThread)Return the full name of the class responsible for handling OP_READ.
return com.sun.enterprise.web.connector.grizzly.XAReadTask.class;
| public boolean | parse(java.nio.ByteBuffer byteBuffer)Parse the ByteBuffer and try to determine if the bytes
stream has been fully read from the SocketChannel .
Drain the SocketChannel and determine if the request bytes
has been fully read. For POST method, parse the bytes and seek for the
content-type header to determine the length of the request bytes.
boolean isFound = false;
curLimit = byteBuffer.limit();
curPosition = byteBuffer.position();
// Rule a - if we know the content length, verify all bytes are read
if ( contentLength != -1 ){
isFound = ((contentLength + headerLength) <= byteBuffer.position());
if (isFound)
byteBuffer.flip();
return isFound;
}
// Rule b - If nothing, return to the Selector.
if (byteBuffer.position() == 0)
return false;
if (SelectorThread.logger().isLoggable(Level.FINEST))
SelectorThread.logger().log(Level.FINEST,dump(byteBuffer));
byteBuffer.flip();
try {
byte c;
byte prev_c = ' ";
try{
if ( state != 0 ){
byteBuffer.position(lastStatePosition);
}
} catch (RuntimeException ex){
// If for any reason we aren't able to recover, use the bytes as
// it is (so DoS are avoided).
state = 0;
lastStatePosition = -1;
}
// Rule c - try to determine the content-length
while(byteBuffer.hasRemaining()) {
c = byteBuffer.get();
// State Machine
// 0: no special characters have been read, but at beginning
// of line
// 1: not at beginning of line; parse until the next line
// 2: read initial G
// 3: read initial GE
// 4: read initial GET -- now we know we have a GET request;
// we can parse until we see \r\n\r\n
// we stay state 4-7 until we're done
// 8: read initial P
// 9: read initial PO
// 10: read initial POS
// 11: read initial POST -- now we can look for content-length
// we can parse until we see content-lenth
// we stay in state 12-27 until we've got length
// 28: read all of post; parse until \r\n\r\n (see state 4)
// ************************************************************
// XXX This algorithm needs to use
// InternalInputBuffer.parseRequestLine instead
// ************************************************************
switch(state) {
case 0: // looking for g or p
if (c == 0x47 || c == 0x67)
state = 2;
else if (c == 0x50 || c == 0x70)
state = 8;
else if (c != 0x0d && c != 0x0a)
state = 1;
break;
case 1: // looking for next line
if (c == 0x0a || c == 0x0d)
state = 0;
break;
case 2: // looking for e
if (c == 0x45 || c == 0x65)
state = 3;
else state = 1;
break;
case 3: // looking for t
if (c == 0x54 || c == 0x74)
state = 4;
else state = 1;
break;
case 4: // \r
if ( c == 0x0a ){
state = 5;
}
break;
case 5: // \n or \r
if ( c == 0x0d || c == 0x0a){
headerLength = byteBuffer.position();
isFound = true;
return isFound;
}
else state = 4;
break;
case 8: // looking for o
if (c == 0x4F || c == 0x6F)
state = 9;
else state = 1;
break;
case 9: // looking for s
if (c == 0x73 || c == 0x53)
state = 10;
else state = 1;
break;
case 10: // looking for t
if (c == 0x74 || c == 0x54)
state = 11;
else state = 1;
break;
case 11: // looking for new line
if (c == 0x0a || c == 0x0d)
state = 12;
else state = 11;
break;
case 12: // looking for c
if (c == 0x43 || c == 0x63)
state = 13;
else if (prev_c == 0x0a
&& byteBuffer.position() == curPosition) {
headerLength = byteBuffer.position();
// Content-length not specified.
isFound = true;
return isFound;
} else state = 12;
break;
case 13: // looking for o
if (c == 0x4F || c == 0x6F)
state = 14;
else state = 11;
break;
case 14: // looking for n
if (c == 0x4E || c == 0x6E)
state = 15;
else state = 11;
break;
case 15: // looking for t
if (c == 0x54 || c == 0x74)
state = 16;
else state = 11;
break;
case 16: // looking for e
if (c == 0x45 || c == 0x65)
state = 17;
else state = 11;
break;
case 17: // looking for n
if (c == 0x4E || c == 0x6E)
state = 18;
else state = 11;
break;
case 18: // looking for t
if (c == 0x54 || c == 0x74)
state = 19;
else state = 11;
break;
case 19: // -
if (c == 0x2D || c == 0x2D)
state = 20;
else state = 11;
break;
case 20: // l
if (c == 0x4C || c == 0x6C)
state = 21;
else state = 11;
break;
case 21: // e
if (c == 0x45 || c == 0x65)
state = 22;
else state = 11;
break;
case 22: // n
if (c == 0x4E || c == 0x6E)
state = 23;
else state = 11;
break;
case 23: // g
if (c == 0x47 || c == 0x67)
state = 24;
else state = 11;
break;
case 24: // t
if (c == 0x54 || c == 0x74)
state = 25;
else state = 11;
break;
case 25: // h
if (c == 0x48 || c == 0x68)
state = 26;
else state = 11;
break;
case 26: // :
if (c == 0x3a)
state = 27;
else state = 11;
break;
case 27: // read length until \r
while (c < 0x30 || c > 0x39) {
// Read past the whitespace between the :
// and the length
c = byteBuffer.get();
}
StringBuilder sb = new StringBuilder();
while (c >= 0x30 && c <= 0x39) {
sb.append((char) c);
c = byteBuffer.get();
}
contentLength = Integer.parseInt(sb.toString());
// XXX: We've already read the character past the length.
// Can it ever not be 0x0d? Would that be an error
// otherwise?
if (c == 0x0d)
state = 29;
else state = 28;
break;
case 28: // looking for \r
if (c == 0x0d)
state = 29;
break;
case 29: // looking for \n
if (c == 0x0a)
state = 30;
else state = 28;
break;
case 30: // looking for \r
if (c == 0x0d)
state = 31;
else state = 28;
break;
case 31: // looking for \n
if (c == 0x0a){
headerLength = byteBuffer.position();
// wait until we have fully read the request body.
isFound = ((contentLength + headerLength)
<= byteBuffer.limit());
return isFound;
}
else state = 28;
break;
default:
throw new IllegalArgumentException("Unexpected state");
}
prev_c = c;
}
// NEITHER A GET OR A POST
if ( state == 0 ) {
isFound = true;
}
return isFound;
} catch (BufferUnderflowException bue) {
SelectorThread.logger().log(Level.SEVERE,"readTask.bufferunderflow", bue);
return false;
} finally {
if ( headerLength == -1 && (state > 0)){
// This means we weren't able to able to find the content-length
// or the end of the stream.
lastStatePosition = byteBuffer.limit();
}
byteBuffer.limit(curLimit);
byteBuffer.position(curPosition);
if (isFound){
byteBuffer.flip();
}
}
| public void | recycle()Recycle this object.
super.recycle();
socketChannel = null;
if ( handler != null){
handler.attachChannel(null);
}
|
|