FileDocCategorySizeDatePackage
DefaultProcessorTask.javaAPI DocGlassfish v2 API65038Mon Jul 09 13:46:46 BST 2007com.sun.enterprise.web.connector.grizzly

DefaultProcessorTask

public class DefaultProcessorTask extends TaskBase implements org.apache.coyote.Processor, org.apache.coyote.ActionHook, ProcessorTask
Process HTTP request. This class is based on org.apache.coyote.http11.Http11Processor
author
Jean-Francois Arcand

Fields Summary
protected org.apache.coyote.Adapter
adapter
Associated adapter.
protected org.apache.coyote.Request
request
Request object.
protected org.apache.coyote.Response
response
Response object.
protected org.apache.coyote.http11.InternalInputBuffer
inputBuffer
Input.
protected org.apache.coyote.http11.InternalOutputBuffer
outputBuffer
Output.
protected boolean
started
State flag.
protected boolean
error
Error flag.
protected boolean
keepAlive
Keep-alive.
protected boolean
connectionHeaderValueSet
Connection: value
protected boolean
http11
HTTP/1.1 flag.
protected boolean
http09
HTTP/0.9 flag.
protected boolean
contentDelimitation
Content delimitator for the request (if false, the connection will be closed at the end of the request).
protected org.apache.tomcat.util.net.SSLSupport
sslSupport
SSL information.
protected Socket
socket
Socket associated with the current connection.
protected String
remoteAddr
Remote Address associated with the current connection.
protected String
remoteHost
Remote Host associated with the current connection.
protected String
localName
Local Host associated with the current connection.
protected int
localPort
Local port to which the socket is connected
protected int
remotePort
Remote port to which the socket is connected
protected String
localAddr
The local Host address.
protected int
uploadTimeout
Maximum timeout on uploads. 5 minutes as in Apache HTTPD server.
protected int
maxPostSize
Max post size.
protected char[]
hostNameC
Host name (used to avoid useless B2C conversion on the host name).
protected TaskContext
taskContext
The taskContext associated with this object. The taskContext contains information about the current connection.
protected TaskEvent
taskEvent
The TaskEvent associated with this task.
protected boolean
hasRequestInfoRegistered
Has the request associated with this ProcessorTask been registered with the RequestGroupInfo
protected int
maxHttpHeaderSize
Default HTTP header buffer size.
protected static int
requestCount
The number of requests ProcessorTask has proceeded.
protected int
requestBufferSize
The input request buffer size.
protected ObjectName
oname
ObjectName under which this ProcessorTask will be JMX-registered if monitoring has been turned on
protected boolean
dropConnection
Allow client of this class to force connection closing.
protected int
keepAliveLeft
The current keep-alive count left before closing the connection.
protected Handler
handler
The handler used by this Task to manipulate the request.
protected String
defaultResponseType
The default response-type
protected String
forcedRequestType
The forced request-type
protected boolean
asyncExecution
Is asynchronous mode enabled?
protected org.apache.coyote.RequestInfo
requestInfo
The code>RequestInfo used to gather stats.
protected AsyncHandler
asyncHandler
When the asynchronous mode is enabled, the execution of this object will be delegated to the AsyncHandler
protected String[]
noCompressionUserAgents
List of user agents to not use gzip with
protected String[]
compressableMimeTypes
List of MIMES which could be gzipped
protected int
compressionLevel
Allowed compression level.
protected int
compressionMinSize
Minimum contentsize to make compression.
protected String[]
restrictedUserAgents
List of restricted user agents.
protected boolean
bufferResponse
Buffer the response until the buffer is full.
protected boolean
disableUploadTimeout
Flag to disable setting a different time-out on uploads.
Constructors Summary
public DefaultProcessorTask()

  
    
    
    // ----------------------------------------------------- Constructor ---- //

     
        this(true);
    
public DefaultProcessorTask(boolean init)

    
        type = PROCESSOR_TASK;
        if (init) {
            initialize();
        }
    
public DefaultProcessorTask(boolean init, boolean bufferResponse)

    
        this.bufferResponse = bufferResponse;

        type = PROCESSOR_TASK;
        if (init) {
            initialize();
        }
    
Methods Summary
public voidaction(org.apache.coyote.ActionCode actionCode, java.lang.Object param)
Send an action to the connector.

param
actionCode Type of the action
param
param Action parameter


        if (actionCode == ActionCode.ACTION_COMMIT) {
            // Commit current response

            if (response.isCommitted())
                return;
                        
            // Validate and write response headers
            prepareResponse();
            try {
                outputBuffer.commit();
            } catch (IOException ex) {
                SelectorThread.logger().log(Level.FINEST,
                        "processorTask.nonBlockingError", ex);               
                // Set error flag
                error = true;
            }

        } else if (actionCode == ActionCode.ACTION_ACK) {

            // Acknowlege request

            // Send a 100 status back if it makes sense (response not committed
            // yet, and client specified an expectation for 100-continue)

            if ((response.isCommitted()) || (!http11))
                return;

            MessageBytes expectMB = request.getMimeHeaders().getValue("expect");
            if ((expectMB != null)
                && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) {
                try {
                    outputBuffer.sendAck();
                } catch (IOException e) {
                    // Set error flag
                    error = true;
                }
            }

        } else if (actionCode == ActionCode.ACTION_CLOSE) {
            // Close

            // End the processing of the current request, and stop any further
            // transactions with the client

            try {
                outputBuffer.endRequest();
            } catch (IOException e) {
                SelectorThread.logger().log(Level.FINEST,
                        "processorTask.nonBlockingError", e);
                // Set error flag
                error = true;
            }

            if (key != null) {
                try {
                    ((SocketChannelOutputBuffer) outputBuffer).flushBuffer();
                } catch (IOException ioe) {
                    if(SelectorThread.logger().isLoggable(Level.FINEST))
                    SelectorThread.logger().log(Level.FINEST, "ACTION_POST_REQUEST", ioe);
                    error = true;
                }
            }
        } else if (actionCode == ActionCode.ACTION_RESET) {

            // Reset response

            // Note: This must be called before the response is committed

            outputBuffer.reset();

        } else if (actionCode == ActionCode.ACTION_CUSTOM) {

            // Do nothing

        } else if (actionCode == ActionCode.ACTION_START) {

            started = true;

        } else if (actionCode == ActionCode.ACTION_STOP) {

            started = false;

        } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) {

            try {
                if (sslSupport != null) {
                    Object sslO = sslSupport.getCipherSuite();
                    if (sslO != null)
                        request.setAttribute
                            (SSLSupport.CIPHER_SUITE_KEY, sslO);
                    sslO = sslSupport.getPeerCertificateChain(false);
                    if (sslO != null)
                        request.setAttribute
                            (SSLSupport.CERTIFICATE_KEY, sslO);
                    sslO = sslSupport.getKeySize();
                    if (sslO != null)
                        request.setAttribute
                            (SSLSupport.KEY_SIZE_KEY, sslO);
                    sslO = sslSupport.getSessionId();
                    if (sslO != null)
                        request.setAttribute
                            (SSLSupport.SESSION_ID_KEY, sslO);
                }
            } catch (Exception e) {
                SelectorThread.logger().log(Level.WARNING,
                        "processorTask.errorSSL" ,e);
            }

        } else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) {

            if ((remoteAddr == null) && (socket != null)) {
                InetAddress inetAddr = socket.getInetAddress();
                if (inetAddr != null) {
                    remoteAddr = inetAddr.getHostAddress();
                }   
            }
            request.remoteAddr().setString(remoteAddr);

        } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE) {
            
            if ((localName == null) && (socket != null)) {
                InetAddress inetAddr = socket.getLocalAddress();
                if (inetAddr != null) {
                    localName = inetAddr.getHostName();
                }
            }
            request.localName().setString(localName);

        } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) {
            
            if ((remoteHost == null) && (socket != null)) {
                InetAddress inetAddr = socket.getInetAddress();
                if (inetAddr != null) {
                    remoteHost = inetAddr.getHostName();
                }
                
                if(remoteHost == null) {
                    if(remoteAddr != null) {
                        remoteHost = remoteAddr;
                    } else { // all we can do is punt
                        request.remoteHost().recycle();
                    }
                }
            }
            request.remoteHost().setString(remoteHost);
            
        } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) {
                       
            if (localAddr == null)
               localAddr = socket.getLocalAddress().getHostAddress();

            request.localAddr().setString(localAddr);
            
        } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) {
            
            if ((remotePort == -1 ) && (socket !=null)) {
                remotePort = socket.getPort(); 
            }    
            request.setRemotePort(remotePort);

        } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) {
            
            if ((localPort == -1 ) && (socket !=null)) {
                localPort = socket.getLocalPort(); 
            }            
            request.setLocalPort(localPort);
       
        } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) {
            if( sslSupport != null) {
                /*
                 * Consume and buffer the request body, so that it does not
                 * interfere with the client's handshake messages
                 */
                InputFilter[] inputFilters = inputBuffer.getFilters();
                ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER])
                    .setLimit(maxPostSize);
                inputBuffer.addActiveFilter
                    (inputFilters[Constants.BUFFERED_FILTER]);
                try {
                    Object sslO = sslSupport.getPeerCertificateChain(true);
                    if( sslO != null) {
                        request.setAttribute
                            (SSLSupport.CERTIFICATE_KEY, sslO);
                    }
                } catch (Exception e) {
                    SelectorThread.logger().log(Level.WARNING,
                            "processorTask.exceptionSSLcert",e);
                }
            }
        } else if ( actionCode == ActionCode.ACTION_POST_REQUEST ) { 
            if (response.getStatus() == 200 && compressionLevel == 0){
                try{
                    handler.handle(request,Handler.RESPONSE_PROCEEDED);
                } catch(IOException ex){
                    SelectorThread.logger().log(Level.FINEST,
                            "Handler exception",ex);
                }
            }      
        } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH ) { 
            if (key != null) {
                SocketChannelOutputBuffer channelOutputBuffer = 
                        ((SocketChannelOutputBuffer)outputBuffer);
                try{
                    channelOutputBuffer.flush();
                } catch (IOException ex){
                    if (SelectorThread.logger().isLoggable(Level.FINEST)){
                        SelectorThread.logger().log(Level.FINEST,
                                "ACTION_CLIENT_FLUSH",ex); 
                    }
                    error = true;
                }
            } 
        }
    
public voidaddCompressableMimeType(java.lang.String mimeType)
Add a mime-type which will be compressable The mime-type String will be exactly matched in the response mime-type header .

param
userAgent user-agent string

    	addStringArray(compressableMimeTypes, mimeType);
    
protected voidaddFilter(java.lang.String className)
Add input or output filter.

param
className class name of the filter

        try {
            Class clazz = Class.forName(className);
            Object obj = clazz.newInstance();
            if (obj instanceof InputFilter) {
                inputBuffer.addFilter((InputFilter) obj);
            } else if (obj instanceof OutputFilter) {
                outputBuffer.addFilter((OutputFilter) obj);
            } else {
                SelectorThread.logger().log(Level.WARNING,
                        "processorTask.unknownFilter" ,className);
            }
        } catch (Exception e) {
            SelectorThread.logger().log(Level.SEVERE,"processorTask.errorFilter", 
                        new Object[]{className, e});
        }
    
protected booleanaddInputFilter(org.apache.coyote.http11.InputFilter[] inputFilters, java.lang.String encodingName)
Add an input filter to the current request.

return
false if the encoding was not found (which would mean it is unsupported)

        if (encodingName.equals("identity")) {
            // Skip
        } else if (encodingName.equals("chunked")) {
            inputBuffer.addActiveFilter
                (inputFilters[Constants.CHUNKED_FILTER]);
            contentDelimitation = true;
        } else {
            for (int i = 2; i < inputFilters.length; i++) {
                if (inputFilters[i].getEncodingName()
                    .toString().equals(encodingName)) {
                    inputBuffer.addActiveFilter(inputFilters[i]);
                    return true;
                }
            }
            return false;
        }
        return true;
    
public voidaddNoCompressionUserAgent(java.lang.String userAgent)
Add user-agent for which gzip compression didn't works The user agent String given will be exactly matched to the user-agent header submitted by the client.

param
userAgent user-agent string

    	addStringArray(noCompressionUserAgents, userAgent);
    
public voidaddRestrictedUserAgent(java.lang.String userAgent)
Add restricted user-agent (which will downgrade the connector to HTTP/1.0 mode). The user agent String given will be exactly matched to the user-agent header submitted by the client.

param
userAgent user-agent string

    	addStringArray(restrictedUserAgents, userAgent);
    
private voidaddStringArray(java.lang.String[] sArray, java.lang.String value)
General use method

param
sArray the StringArray
param
value string

        if (sArray == null)
            sArray = new String[0];
        String[] results = new String[sArray.length + 1];
        for (int i = 0; i < sArray.length; i++)
            results[i] = sArray[i];
        results[sArray.length] = value;
        sArray = results;
    
protected voidconfigPreProcess()
Prepare this object before parsing the request.

        if (isMonitoringEnabled()){
            adapter.
                fireAdapterEvent(Adapter.CONNECTION_PROCESSING_STARTED,
                    request.getRequestProcessor());
        }
                    
        if( selectorThread.getDomain() != null 
                && isMonitoringEnabled() 
                && !hasRequestInfoRegistered ) {
            registerMonitoring();
        } else if (!isMonitoringEnabled() && hasRequestInfoRegistered) {
            unregisterMonitoring();
        } 
        
        if (isMonitoringEnabled()) {
            requestInfo = request.getRequestProcessor();
            requestInfo.setWorkerThreadID(Thread.currentThread().getId());
        }
        
        // Set the remote address
        remoteAddr = null;
        remoteHost = null;
        localName = null;
        localAddr = null;
        remotePort = -1;
        localPort = -1;
        connectionHeaderValueSet = false;
        
        // Error flag
        error = false;
        keepAlive = true;

        if (request.getServerPort() == 0) {
            request.setServerPort(selectorThread.getPort());
        }        
    
protected booleandoProcess()
Process an HTTP request using a non blocking socket

        return doProcess(taskContext.getInputStream(),
                         taskContext.getOutputStream());
    
protected booleandoProcess(java.io.InputStream input, java.io.OutputStream output)
Process an HTTP request using a non blocking socket

param
input the InputStream to read bytes
param
output the OutputStream to write bytes

        
        boolean exitWhile = parseRequest(input,output,false);
        if ( exitWhile ) return exitWhile;
        invokeAdapter();
        postResponse();  
        return error;
    
public voiddoTask()
Execute the HTTP request by parsing the header/body, and then by delegating the process to the Catalina container.

        try {
            process(taskContext.getInputStream(),
                    taskContext.getOutputStream());
        } catch(Throwable ex){
            SelectorThread.logger().log(Level.FINE,
                    "processorTask.errorProcessingRequest", ex);
        } finally {
            terminateProcess();        
        }
    
protected intfindBytes(org.apache.tomcat.util.buf.ByteChunk bc, byte[] b)
Specialized utility method: find a sequence of lower case bytes inside a ByteChunk.


        byte first = b[0];
        byte[] buff = bc.getBuffer();
        int start = bc.getStart();
        int end = bc.getEnd();

        // Look for first char 
        int srcEnd = b.length;

        for (int i = start; i <= (end - srcEnd); i++) {
            if (Ascii.toLower(buff[i]) != first) continue;
            // found first char, now look for a match
            int myPos = i+1;
            for (int srcPos = 1; srcPos < srcEnd; ) {
                    if (Ascii.toLower(buff[myPos++]) != b[srcPos++])
                break;
                    if (srcPos == srcEnd) return i - start; // found it
            }
        }
        return -1;

    
public java.lang.String[]findCompressableMimeTypes()
Return the list of restricted user agents.

        return (compressableMimeTypes);
    
public java.lang.String[]findNoCompressionUserAgents()
Return the list of no compression user agents.

        return (noCompressionUserAgents);
    
public java.lang.String[]findRestrictedUserAgents()
Return the list of restricted user agents.

        return (restrictedUserAgents);
    
public org.apache.coyote.AdaptergetAdapter()
Get the associated adapter.

return
the associated adapter

        return adapter;
    
public AsyncHandlergetAsyncHandler()
Return the AsyncHandler used when asynchronous execution is enabled.

        return asyncHandler;
    
public intgetBufferSize()
Return the request input buffer size

        return requestBufferSize;
    
public java.lang.StringgetCompression()
Return compression level.

        switch (compressionLevel) {
        case 0:
            return "off";
        case 1:
            return "on";
        case 2:
            return "force";
        }
        return "off";
    
public intgetCompressionMinSize()

        return compressionMinSize;
    
public java.lang.StringgetDefaultResponseType()
Return the default response type used

         return defaultResponseType;
    
public booleangetDisableUploadTimeout()
Get the flag that controls upload time-outs.

        return disableUploadTimeout;
    
public booleangetDropConnection()
Is the keep-alive mechanism enabled or disabled.

        return dropConnection;
    
public java.lang.StringgetForcedRequestType()
Return the default request type used

        return forcedRequestType;
    
public HandlergetHandler()
Return the Handler used by this instance.

        return handler;
    
public intgetMaxHttpHeaderSize()

        return maxHttpHeaderSize;
    
public intgetMaxPostSize()
Return the maximum size of a POST which will be buffered in SSL mode.

        return maxPostSize;
    
public org.apache.coyote.RequestgetRequest()
Return the internal Request object.

        return request;
    
public java.lang.StringgetRequestURI()
Get the request URI associated with this processor.

        return request.requestURI().toString();
    
public org.apache.tomcat.util.net.SSLSupportgetSSLSupport()
Return the SSLSupport object used by this instance.

        return sslSupport;
    
public java.net.SocketgetSocket()
Return the current Socket used by this instance

return
socket the current Socket used by this instance

        return socket;
    
public intgetTimeout()
Get the upload timeout.

        return uploadTimeout;
    
public longgetWorkerThreadID()
Return the current WorkerThread ID associated with this instance.

        return request.getRequestProcessor().getWorkerThreadID();
    
private booleaninStringArray(java.lang.String[] sArray, java.lang.String value)
General use method

param
sArray the StringArray
param
value string

        for (int i = 0; i < sArray.length; i++) {
            if (sArray[i].equals(value)) {
                return true;
            }
        }
        return false;
    
public voidinitialize()
Initialize the stream and the buffer used to parse the request.

        started = true;   
        request = new Request();

        response = new Response();
        response.setHook(this);
        
        inputBuffer = new InternalInputBuffer(request,requestBufferSize); 
        outputBuffer = new SocketChannelOutputBuffer(response,
                                                     maxHttpHeaderSize,
                                                     bufferResponse);
        request.setInputBuffer(inputBuffer);
       
        response.setOutputBuffer(outputBuffer);
        request.setResponse(response);

        initializeFilters();

    
protected voidinitializeFilters()
Initialize standard input and output filters.


        // Create and add the identity filters.
        inputBuffer.addFilter(new IdentityInputFilter());
        outputBuffer.addFilter(new IdentityOutputFilter());

        // Create and add the chunked filters.
        inputBuffer.addFilter(new ChunkedInputFilter());
        outputBuffer.addFilter(new ChunkedOutputFilter());

        // Create and add the void filters.
        inputBuffer.addFilter(new VoidInputFilter());
        outputBuffer.addFilter(new VoidOutputFilter());

        // Create and add buffered input filter
        inputBuffer.addFilter(new BufferedInputFilter());

        // Create and add the chunked filters.
        //inputBuffer.addFilter(new GzipInputFilter());
        outputBuffer.addFilter(new GzipOutputFilter());

    
public voidinvokeAdapter()
Invoke the Adapter, which usualy invoke the Servlet Container.

        // Process the request in the adapter
        if (!error) {
            try {
                adapter.service(request, response);
                // Handle when the response was committed before a serious
                // error occurred.  Throwing a ServletException should both
                // set the status to 500 and set the errorException.
                // If we fail here, then the response is likely already 
                // committed, so we can't try and set headers.
                if(keepAlive && !error) { // Avoid checking twice.
                    error = response.getErrorException() != null ||
                            statusDropsConnection(response.getStatus());
                }
            } catch (InterruptedIOException e) {
                error = true;
            } catch (Throwable t) {
                SelectorThread.logger().log(Level.SEVERE,
                        "processorTask.serviceError", t);
                // 500 - Internal Server Error
                response.setStatus(500);
                error = true;
            }
        }
    
public booleanisAsyncExecutionEnabled()
Is asynchronous execution enabled?

        return asyncExecution;
    
private booleanisCompressable()
Check for compression

        // Compression only since HTTP 1.1
        if (! http11)
            return false;

        // Check if browser support gzip encoding
        MessageBytes acceptEncodingMB = 
            request.getMimeHeaders().getValue("accept-encoding");
            
        if ((acceptEncodingMB == null) 
            || (acceptEncodingMB.indexOf("gzip") == -1))
            return false;

        // Check if content is not allready gzipped
        MessageBytes contentEncodingMB =
            response.getMimeHeaders().getValue("Content-Encoding");

        if ((contentEncodingMB != null) 
            && (contentEncodingMB.indexOf("gzip") != -1))
            return false;

        // If force mode, allways compress (test purposes only)
        if (compressionLevel == 2)
           return true;

        // Check for incompatible Browser
        if (noCompressionUserAgents != null) {
            MessageBytes userAgentValueMB =  
                request.getMimeHeaders().getValue("user-agent");
            String userAgentValue = userAgentValueMB.toString();

        	if (inStringArray(noCompressionUserAgents, userAgentValue))
        		return false;
        }

        // Check if suffisant len to trig the compression        
        int contentLength = response.getContentLength();
        if ((contentLength == -1) 
            || (contentLength > compressionMinSize)) {
            // Check for compatible MIME-TYPE
            if (compressableMimeTypes != null)
                return (inStringArray(compressableMimeTypes, 
                        response.getContentType()));
        }

	return false;
    
public booleanisError()

        return error;
    
public booleanisKeepAlive()

        return keepAlive;
    
public voidparseHost(org.apache.tomcat.util.buf.MessageBytes valueMB)
Parse host.


        if (valueMB == null || valueMB.isNull()) {
            // HTTP/1.0
            // Default is what the socket tells us. Overriden if a host is 
            // found/parsed
            request.setServerPort(socket.getLocalPort());
            InetAddress localAddress = socket.getLocalAddress();
            // Setting the socket-related fields. The adapter doesn't know 
            // about socket.
            request.setLocalHost(localAddress.getHostName());
            request.serverName().setString(localAddress.getHostName());
            return;
        }

        ByteChunk valueBC = valueMB.getByteChunk();
        byte[] valueB = valueBC.getBytes();
        int valueL = valueBC.getLength();
        int valueS = valueBC.getStart();
        int colonPos = -1;
        if (hostNameC.length < valueL) {
            hostNameC = new char[valueL];
        }

        boolean ipv6 = (valueB[valueS] == '[");
        boolean bracketClosed = false;
        for (int i = 0; i < valueL; i++) {
            char b = (char) valueB[i + valueS];
            hostNameC[i] = b;
            if (b == ']") {
                bracketClosed = true;
            } else if (b == ':") {
                if (!ipv6 || bracketClosed) {
                    colonPos = i;
                    break;
                }
            }
        }

        if (colonPos < 0) {
            if (sslSupport == null) {
                // 80 - Default HTTTP port
                request.setServerPort(80);
            } else {
                // 443 - Default HTTPS port
                request.setServerPort(443);
            }
            request.serverName().setChars(hostNameC, 0, valueL);
        } else {

            request.serverName().setChars(hostNameC, 0, colonPos);

            int port = 0;
            int mult = 1;
            for (int i = valueL - 1; i > colonPos; i--) {
                int charValue = HexUtils.DEC[(int) valueB[i + valueS]];
                if (charValue == -1) {
                    // Invalid character
                    error = true;
                    // 400 - Bad request
                    response.setStatus(400);
                    break;
                }
                port = port + (charValue * mult);
                mult = 10 * mult;
            }
            request.setServerPort(port);

        }

    
public voidparseRequest()
Parse the request line and the http header.

        parseRequest(taskContext.getInputStream(),
                     taskContext.getOutputStream(), true);
    
public booleanparseRequest(java.io.InputStream input, java.io.OutputStream output, boolean keptAlive)
Parse the request line and the http header.

param
input the InputStream to read bytes
param
output the OutputStream to write bytes

        
        // Parsing the request header
        try { 
            if (isMonitoringEnabled()){
                adapter.fireAdapterEvent(Adapter.REQUEST_PROCESSING_STARTED, 
                        request.getRequestProcessor());
            }

            inputBuffer.parseRequestLine();
            if (isMonitoringEnabled()) {
                request.getRequestProcessor().setRequestCompletionTime(0);
            }

            request.setStartTime(System.currentTimeMillis());
            if ( handler != null && 
                    handler.handle(request,Handler.REQUEST_LINE_PARSED)
                        == Handler.BREAK){
                return true;
            }

            if (!disableUploadTimeout && getSelectionKey() != null) {
                ((ByteBufferInputStream)input).setReadTimeout(uploadTimeout);
            }
            
            keptAlive = true;
            inputBuffer.parseHeaders();
        
            if ( selectorThread.isEnableNioLogging() ){                               
                SelectorThread.logger().log(Level.INFO, 
                        "SocketChannel request line" + key.channel() + " is: " 
                        + request);
                
                SelectorThread.logger().log(Level.INFO, "SocketChannel headers" 
                        + key.channel() + " are: "
                        + request.getMimeHeaders());
            }                       
        } catch (IOException e) {
            SelectorThread.logger().log(Level.FINEST,
                    "processorTask.nonBlockingError", e);
            error = true;
            keepAlive = false;
            return true;
        } catch (Throwable t) {
            SelectorThread.logger().log(Level.SEVERE,
                    "processorTask.nonBlockingError", t);
            // 400 - Bad Request
            response.setStatus(400);
            error = true;
        }

        // Setting up filters, and parse some request headers
        try {
            prepareRequest();
        } catch (Throwable t) {
            SelectorThread.logger().log(Level.FINE,
                    "processorTask.createRequestError", t);
            // 400 - Internal Server Error
            response.setStatus(400);
            error = true;
        }
        return false;
    
public voidpostProcess()
Post process the http request, after the response has been commited.

        postProcess(taskContext.getInputStream(),
                    taskContext.getOutputStream());
    
public voidpostProcess(java.io.InputStream input, java.io.OutputStream output)
Post process the http request, after the response has been commited.

        if (!recycle){
            started = false;
            inputBuffer = null;
            outputBuffer = null;
            response = null;
            if (isMonitoringEnabled()) {
                request.getRequestProcessor().setWorkerThreadID(0);
                adapter.fireAdapterEvent(Adapter.CONNECTION_PROCESSING_COMPLETED, 
                        request.getRequestProcessor());              
            }
            request = null;
        } else {
            inputBuffer.recycle();
            outputBuffer.recycle();
        }

        // Recycle ssl info
        sslSupport = null;

        if (error){
            keepAlive = false;
            connectionHeaderValueSet = false;
        }
    
public voidpostResponse()
Prepare and post the response.

param
input the InputStream to read bytes
param
output the OutputStream to write bytes

        
        try {
            adapter.afterService(request,response);
        } catch (Exception ex) {
            error = true;
            SelectorThread.logger().log(Level.FINEST,
                    "processorTask.errorFinishingRequest", ex);            
        }
        
        // Finish the handling of the request
        try {
             inputBuffer.endRequest();
        } catch (IOException e) {
            error = true;
        } catch (Throwable t) {
            SelectorThread.logger().log(Level.SEVERE,
                    "processorTask.errorFinishingRequest", t);
            // 500 - Internal Server Error
            response.setStatus(500);
            error = true;
        }
        try {
            outputBuffer.endRequest();
        } catch (IOException e) {
            error = true;
        } catch (Throwable t) {
            SelectorThread.logger().log(Level.SEVERE,
                    "processorTask.errorFinishingResponse", t);
            error = true;
        }

        // If there was an error, make sure the request is counted as
        // and error, and update the statistics counter
        if (error) {
            response.setStatus(500);
        }

        if (isMonitoringEnabled()) {
            request.updateCounters();
            adapter.fireAdapterEvent(Adapter.REQUEST_PROCESSING_COMPLETED, 
                    request.getRequestProcessor());              
        }

        // Next request
        inputBuffer.nextRequest();
        outputBuffer.nextRequest();
    
public voidpreProcess()
Pre process the request by decoding the request line and the header.

        preProcess(taskContext.getInputStream(),
                   taskContext.getOutputStream());
    
public voidpreProcess(java.io.InputStream input, java.io.OutputStream output)
Pre process the request by decoding the request line and the header.

param
input the InputStream to read bytes
param
output the OutputStream to write bytes

        
        // Make sure this object has been initialized.
        if ( !started ){
            initialize();
        }
        // Setting up the I/O
        inputBuffer.setInputStream(input);
        if ( key != null ) {
            SocketChannelOutputBuffer channelOutputBuffer = 
                    ((SocketChannelOutputBuffer)outputBuffer);
            channelOutputBuffer.setChannel((SocketChannel)key.channel());
        } 
        configPreProcess();
    
protected voidprepareRequest()
After reading the request headers, we have to setup the request filters.


        http11 = true;
        http09 = false;
        contentDelimitation = false;
        if (sslSupport != null) {
            request.scheme().setString("https");
        }
        MessageBytes protocolMB = request.protocol();
        if (protocolMB.equals(Constants.HTTP_11)) {
            http11 = true;
            protocolMB.setString(Constants.HTTP_11);
        } else if (protocolMB.equals(Constants.HTTP_10)) {
            http11 = false;
            keepAlive = false;
            protocolMB.setString(Constants.HTTP_10);
        } else if (protocolMB.equals("")) {
            // HTTP/0.9
            http09 = true;
            http11 = false;
            keepAlive = false;
        } else {
            // Unsupported protocol
            http11 = false;
            error = true;
            // Send 505; Unsupported HTTP version
            response.setStatus(505);
        }
        
        MessageBytes methodMB = request.method();
        if (methodMB.equals(Constants.GET)) {
            methodMB.setString(Constants.GET);
        } else if (methodMB.equals(Constants.POST)) {
            methodMB.setString(Constants.POST);
        }

        MimeHeaders headers = request.getMimeHeaders();

        // Check connection header
        MessageBytes connectionValueMB = headers.getValue("connection");
        if (connectionValueMB != null) {
            ByteChunk connectionValueBC = connectionValueMB.getByteChunk();
            if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) {
                keepAlive = false;
                connectionHeaderValueSet = false;
            } else if (findBytes(connectionValueBC, 
                                 Constants.KEEPALIVE_BYTES) != -1) {
                keepAlive = true;
                connectionHeaderValueSet = true;
            }
        }

        // Check user-agent header
        if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) {
            MessageBytes userAgentValueMB =  
                request.getMimeHeaders().getValue("user-agent");
            // Check in the restricted list, and adjust the http11 
            // and keepAlive flags accordingly
            String userAgentValue = userAgentValueMB.toString();
            for (int i = 0; i < restrictedUserAgents.length; i++) {
                if (restrictedUserAgents[i].equals(userAgentValue)) {
                    http11 = false;
                    keepAlive = false;
                }
            }
        }

        // Check for a full URI (including protocol://host:port/)
        ByteChunk uriBC = request.requestURI().getByteChunk();
        if (uriBC.startsWithIgnoreCase("http", 0)) {

            int pos = uriBC.indexOf("://", 0, 3, 4);
            int uriBCStart = uriBC.getStart();
            int slashPos = -1;
            if (pos != -1) {
                byte[] uriB = uriBC.getBytes();
                slashPos = uriBC.indexOf('/", pos + 3);
                if (slashPos == -1) {
                    slashPos = uriBC.getLength();
                    // Set URI as "/"
                    request.requestURI().setBytes
                        (uriB, uriBCStart + pos + 1, 1);
                } else {
                    request.requestURI().setBytes
                        (uriB, uriBCStart + slashPos, 
                         uriBC.getLength() - slashPos);
                }
                MessageBytes hostMB = headers.setValue("host");
                hostMB.setBytes(uriB, uriBCStart + pos + 3, 
                                slashPos - pos - 3);
            }

        }

        // Input filter setup
        InputFilter[] inputFilters = inputBuffer.getFilters();

        // Parse content-length header
        long contentLength = request.getContentLengthLong();
        if (contentLength >= 0) {
            
            inputBuffer.addActiveFilter
                (inputFilters[Constants.IDENTITY_FILTER]);
            contentDelimitation = true;
        }

        // Parse transfer-encoding header
        MessageBytes transferEncodingValueMB = null;
        if (http11)
            transferEncodingValueMB = headers.getValue("transfer-encoding");
        if (transferEncodingValueMB != null) {
            String transferEncodingValue = transferEncodingValueMB.toString();
            // Parse the comma separated list. "identity" codings are ignored
            int startPos = 0;
            int commaPos = transferEncodingValue.indexOf(',");
            String encodingName = null;
            while (commaPos != -1) {
                encodingName = transferEncodingValue.substring
                    (startPos, commaPos).toLowerCase().trim();
                if (!addInputFilter(inputFilters, encodingName)) {
                    // Unsupported transfer encoding
                    error = true;
                    // 501 - Unimplemented
                    response.setStatus(501);
                }
                startPos = commaPos + 1;
                commaPos = transferEncodingValue.indexOf(',", startPos);
            }
            encodingName = transferEncodingValue.substring(startPos)
                .toLowerCase().trim();
            if (!addInputFilter(inputFilters, encodingName)) {
                // Unsupported transfer encoding
                error = true;
                // 501 - Unimplemented
                response.setStatus(501);
            }
        }

        MessageBytes valueMB = headers.getValue("host");

        // Check host header
        if (http11 && (valueMB == null)) {
            error = true;
            // 400 - Bad request
            response.setStatus(400);
        }

        parseHost(valueMB);

        if (!contentDelimitation) {
            // If there's no content length 
            // (broken HTTP/1.0 or HTTP/1.1), assume
            // the client is not broken and didn't send a body
            inputBuffer.addActiveFilter
                (inputFilters[Constants.VOID_FILTER]);
            contentDelimitation = true;
        }
    
protected voidprepareResponse()
When committing the response, we have to validate the set of headers, as well as setup the response filters.


        boolean entityBody = true;
        contentDelimitation = false;

        OutputFilter[] outputFilters = outputBuffer.getFilters();

        if (http09 == true) {
            // HTTP/0.9
            outputBuffer.addActiveFilter
                (outputFilters[Constants.IDENTITY_FILTER]);
            return;
        }

        int statusCode = response.getStatus();
        if ((statusCode == 204) || (statusCode == 205) 
            || (statusCode == 304)) {
            // No entity body
            outputBuffer.addActiveFilter
                (outputFilters[Constants.VOID_FILTER]);
            entityBody = false;
            contentDelimitation = true;
        }

        // Check for compression
        boolean useCompression = false;
        if (entityBody && (compressionLevel > 0)) {
            useCompression = isCompressable();
            
            // Change content-length to -1 to force chunking
            if (useCompression) {
                response.setContentLength(-1);
            }
        }
        
        MessageBytes methodMB = request.method();
        if (methodMB.equals("HEAD")) {
            // No entity body
            outputBuffer.addActiveFilter
                (outputFilters[Constants.VOID_FILTER]);
            contentDelimitation = true;
        }

        MimeHeaders headers = response.getMimeHeaders();
        if (!entityBody) {
            response.setContentLength(-1);
        } else {
            String contentType = response.getContentType();
            if (contentType != null) {
                headers.setValue("Content-Type").setString(contentType);
            } else {
                headers.setValue("Content-Type").setString(defaultResponseType);                
            }
        
            String contentLanguage = response.getContentLanguage();
            if (contentLanguage != null) {
                headers.setValue("Content-Language")
                    .setString(contentLanguage);
            }
        }

        int contentLength = response.getContentLength();
        if (contentLength != -1) {
            headers.setValue("Content-Length").setInt(contentLength);
            outputBuffer.addActiveFilter
                (outputFilters[Constants.IDENTITY_FILTER]);
            contentDelimitation = true;
        } else {
            if (entityBody && http11 && keepAlive) {
                outputBuffer.addActiveFilter
                    (outputFilters[Constants.CHUNKED_FILTER]);
                contentDelimitation = true;
                response.addHeader("Transfer-Encoding", "chunked");
            } else {
                outputBuffer.addActiveFilter
                    (outputFilters[Constants.IDENTITY_FILTER]);
            }
        }

        if (useCompression) {
            outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]);
            // FIXME: Make content-encoding generation dynamic
            response.setHeader("Content-Encoding", "gzip");
            // Make Proxies happy via Vary (from mod_deflate)
            response.setHeader("Vary", "Accept-Encoding");
        }
        
        // Add date header
        if (! response.containsHeader("Date")){
            String date = FastHttpDateFormat.getCurrentDate();
            response.addHeader("Date", date);
        }
         
        // Add transfer encoding header
        // FIXME

        if ((entityBody) && (!contentDelimitation)) {
            // Mark as close the connection after the request, and add the 
            // connection: close header
            keepAlive = false;
        }

        // If we know that the request is bad this early, add the
        // Connection: close header.
        keepAlive = keepAlive && !statusDropsConnection(statusCode)
            && !dropConnection;
        if (!keepAlive ) {
            headers.setValue("Connection").setString("close");
            connectionHeaderValueSet = false;
        } else if (!http11 && !error) {
            headers.setValue("Connection").setString("Keep-Alive");
        }

        // Build the response header
        outputBuffer.sendStatus();

        int size = headers.size();
        for (int i = 0; i < size; i++) {
            outputBuffer.sendHeader(headers.getName(i), headers.getValue(i));
        }
        outputBuffer.endHeaders();

    
public booleanprocess(java.io.InputStream input, java.io.OutputStream output)
Process pipelined HTTP requests using the specified input and output streams.

param
input stream from which the HTTP requests will be read
param
output stream which will be used to output the HTTP responses
return
true if the connection needs to be keep-alived.
throws
Exception error during an I/O operation

                
        preProcess(input,output);    
        doProcess(input,output);
        postProcess(input,output);
        return keepAlive;
    
public voidrecycle()
Recyle this object.

        if ( taskEvent != null ){
            taskEvent.setStatus(TaskEvent.START);
        }
        
        if ( listeners!= null && listeners.size() > 0)
            clearTaskListeners();
        
        socket = null;
        dropConnection = false;
        key = null;
    
private voidregisterMonitoring()
Register a new RequestProcessor instance.


        if ( selectorThread.getManagement() == null ) return;
        
        RequestInfo requestInfo = request.getRequestProcessor();
        // Add RequestInfo to RequestGroupInfo
        requestInfo.setGlobalProcessor(getRequestGroupInfo());
      
        try {
            oname = new ObjectName(selectorThread.getDomain()
                                   +  ":type=RequestProcessor,worker=http"
                                   + selectorThread.getPort()
                                   + ",name=HttpRequest" 
                                   + requestCount++ );
            selectorThread.getManagement().
                    registerComponent(requestInfo, oname,null);
        } catch( Exception ex ) {
            SelectorThread.logger().log(Level.WARNING,
                       "processorTask.errorRegisteringRequest",
                       ex);
        }

        hasRequestInfoRegistered = true;
    
public voidsetAdapter(org.apache.coyote.Adapter adapter)
Set the associated adapter.

param
adapter the new adapter

        this.adapter = adapter;
    
public voidsetAsyncHandler(AsyncHandler asyncHandler)
Set the AsyncHandler used when asynchronous execution is enabled.

        this.asyncHandler = asyncHandler;     
    
public voidsetBufferSize(int requestBufferSize)
Set the request input buffer size

        this.requestBufferSize = requestBufferSize;
    
public voidsetCompressableMimeType(java.lang.String[] compressableMimeTypes)
Set compressable mime-type list (this method is best when used with a large number of connectors, where it would be better to have all of them referenced a single array).

        this.compressableMimeTypes = compressableMimeTypes;
    
public voidsetCompression(java.lang.String compression)
Set compression level.

        if (compression.equals("on")) {
            this.compressionLevel = 1;
        } else if (compression.equals("force")) {
            this.compressionLevel = 2;
        } else if (compression.equals("off")) {
            this.compressionLevel = 0;
        } else {
            try {
                // Try to parse compression as an int, which would give the
                // minimum compression size
                compressionMinSize = Integer.parseInt(compression);
                this.compressionLevel = 1;
            } catch (Exception e) {
                this.compressionLevel = 0;
            }
        }
    
public voidsetCompressionMinSize(int compressionMinSize)

        this.compressionMinSize = compressionMinSize;
    
public voidsetConnectionHeaderValueSet(boolean connectionHeaderValueSet)

        this.connectionHeaderValueSet = connectionHeaderValueSet;
    
public voidsetDefaultResponseType(java.lang.String defaultResponseType)
Set the default response type used. Specified as a semi-colon delimited string consisting of content-type, encoding, language, charset

         this.defaultResponseType = defaultResponseType;
    
public voidsetDisableUploadTimeout(boolean isDisabled)
Set the flag to control upload time-outs.

        disableUploadTimeout = isDisabled;
    
public voidsetDropConnection(boolean dropConnection)
Enable or disable the keep-alive mechanism. Setting this value to false will automatically add the following header to the response ' Connection: close '

        this.dropConnection = dropConnection;
    
public voidsetEnableAsyncExecution(boolean asyncExecution)
Enable/disable asynchronous execution of this object.

        this.asyncExecution = asyncExecution;
    
public voidsetError(boolean error)

        this.error = error;
    
public voidsetForcedRequestType(java.lang.String forcedRequestType)
Sets the forced request type, which is forced onto requests that do not already specify any MIME type.

        this.forcedRequestType = forcedRequestType;
    
public voidsetHandler(Handler handler)
Set the Handler used by this class.

        this.handler = handler;
    
public voidsetMaxHttpHeaderSize(int maxHttpHeaderSize)

        this.maxHttpHeaderSize = maxHttpHeaderSize;
    
public voidsetMaxPostSize(int mps)
Set the maximum size of a POST which will be buffered in SSL mode.

        maxPostSize = mps;
    
public voidsetNoCompressionUserAgents(java.lang.String[] noCompressionUserAgents)
Set no compression user agent list (this method is best when used with a large number of connectors, where it would be better to have all of them referenced a single array).

        this.noCompressionUserAgents = noCompressionUserAgents;
    
public voidsetRestrictedUserAgents(java.lang.String[] restrictedUserAgents)
Set restricted user agent list (this method is best when used with a large number of connectors, where it would be better to have all of them referenced a single array).

        this.restrictedUserAgents = restrictedUserAgents;
    
public voidsetSSLSupport(org.apache.tomcat.util.net.SSLSupport sslSupport)
Set the SSLSupport object used by this instance.

        this.sslSupport = sslSupport;
    
public voidsetSocket(java.net.Socket socket)
Set the socket associated with this HTTP connection.

        this.socket = socket;
    
public voidsetTimeout(int uploadTimeout)
Set the upload timeout.

        this.uploadTimeout = uploadTimeout ;
    
protected booleanstatusDropsConnection(int status)
Determine if we must drop the connection because of the HTTP status code. Use the same list of codes as Apache/httpd.

        return status == 400 /* SC_BAD_REQUEST */ ||
               status == 408 /* SC_REQUEST_TIMEOUT */ ||
               status == 411 /* SC_LENGTH_REQUIRED */ ||
               status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ ||
               status == 414 /* SC_REQUEST_URI_TOO_LARGE */ ||
               status == 500 /* SC_INTERNAL_SERVER_ERROR */ ||
               status == 503 /* SC_SERVICE_UNAVAILABLE */ ||
               status == 501 /* SC_NOT_IMPLEMENTED */;
    
public voidtaskEvent(TaskEvent event)

        if ( event.getStatus() == TaskEvent.START) {
            taskContext = (TaskContext)event.attachement();
            if (taskEvent == null) {
                taskEvent = new TaskEvent<TaskContext>();
            }
            
            taskEvent.attach(taskContext);

            if ( !asyncExecution ) {
                execute();
            } else {
                asyncHandler.handle(this);
            }
        }
    
public voidterminateProcess()
Notify the TaskListener that the request has been fully processed.

        if ( error ) {
            taskEvent.setStatus(TaskEvent.ERROR);
        } else {
            taskEvent.setStatus(TaskEvent.COMPLETED);
        }
        fireTaskEvent(taskEvent); 
    
private voidunregisterMonitoring()
Unregisters the MBean corresponding to this ProcessorTask.


        if ( selectorThread.getManagement() == null ) return;
        
        RequestInfo requestInfo = request.getRequestProcessor();
        /*
         * Remove 'requestInfo' from 'requestGroupInfo'.
         * This will also update 'requestGroupInfo' with the current stats
         * of 'requestInfo', which is why we need to reset 'requestInfo' so
         * its current stats will not be considered when it is added back to
         * 'requestGroupInfo' next time registerMonitoring() is called.
         */
        requestInfo.setGlobalProcessor(null);
        requestInfo.reset();

        if (oname != null) {
            try {
                selectorThread.getManagement().unregisterComponent(oname);
            } catch (Exception ex) {
                SelectorThread.logger().log(Level.WARNING,
                           "processorTask.errorUnregisteringRequest",
                           ex);
            }
        }

        hasRequestInfoRegistered = false;