FileDocCategorySizeDatePackage
StateMachineAlgorithm.javaAPI DocGlassfish v2 API15964Fri May 04 22:37:06 BST 2007com.sun.enterprise.web.connector.grizzly.algorithms

StateMachineAlgorithm

public 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'
author
Scott Oaks.
author
Jean-Francois Arcand

Fields Summary
Constructors Summary
public StateMachineAlgorithm()

        if (embeddedInGlassFish){
            handler = new NoParsingHandler();
        } else {
            handler = new DummyHandler();
        }      
    
Methods Summary
public com.sun.enterprise.web.connector.grizzly.HandlergetHandler()
Return the Handler used by this algorithm.

        return handler;
    
public java.lang.ClassgetReadTask(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 booleanparse(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.

return
true if we need to call back the SelectorThread This occurs when the stream doesn't contains all the request bytes. false if the stream contains all request bytes.
paran
byteBuffer the bytes read.
return
true if the algorithm determines the end of the stream.

               
        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 voidrecycle()
Recycle this object.

        super.recycle();
        
        socketChannel = null;
        if ( handler != null){
            handler.attachChannel(null);
        }