FileDocCategorySizeDatePackage
JkInputStream.javaAPI DocApache Tomcat 6.0.1410838Fri Jul 20 04:20:30 BST 2007org.apache.jk.common

JkInputStream

public class JkInputStream extends Object implements org.apache.coyote.InputBuffer, org.apache.coyote.OutputBuffer
Generic input stream impl on top of ajp

Fields Summary
private static org.apache.juli.logging.Log
log
private org.apache.jk.core.Msg
bodyMsg
private org.apache.jk.core.Msg
outputMsg
private org.apache.jk.core.MsgContext
mc
private org.apache.tomcat.util.buf.MessageBytes
bodyBuff
private org.apache.tomcat.util.buf.MessageBytes
tempMB
private boolean
end_of_stream
private boolean
isEmpty
private boolean
isFirst
private boolean
isReplay
private boolean
isReadRequired
Constructors Summary
public JkInputStream(org.apache.jk.core.MsgContext context, int bsize)


     
        // Make certain HttpMessages is loaded for SecurityManager
        try {
            Class.forName("org.apache.tomcat.util.http.HttpMessages");
        } catch(Exception ex) {
            // ignore
        }
    
        mc = context;
        bodyMsg = new MsgAjp(bsize);
        outputMsg = new MsgAjp(bsize);
    
public JkInputStream(org.apache.jk.core.MsgContext context)

deprecated

        this(context, 8*1024);
    
Methods Summary
public voidappendHead(org.apache.coyote.Response res)

        if( log.isDebugEnabled() )
            log.debug("COMMIT sending headers " + res + " " + res.getMimeHeaders() );
        
        C2BConverter c2b=mc.getConverter();
        
        outputMsg.reset();
        outputMsg.appendByte(AjpConstants.JK_AJP13_SEND_HEADERS);
        outputMsg.appendInt( res.getStatus() );
        
        String message=res.getMessage();
        if( message==null ){
            message= HttpMessages.getMessage(res.getStatus());
        } else {
            message = message.replace('\n", ' ").replace('\r", ' ");
        }
        tempMB.setString( message );
        c2b.convert( tempMB );
        outputMsg.appendBytes(tempMB);

        // XXX add headers
        
        MimeHeaders headers=res.getMimeHeaders();
        String contentType = res.getContentType();
        if( contentType != null ) {
            headers.setValue("Content-Type").setString(contentType);
        }
        String contentLanguage = res.getContentLanguage();
        if( contentLanguage != null ) {
            headers.setValue("Content-Language").setString(contentLanguage);
        }
        long contentLength = res.getContentLengthLong();
        if( contentLength >= 0 ) {
            headers.setValue("Content-Length").setLong(contentLength);
        }
        int numHeaders = headers.size();
        outputMsg.appendInt(numHeaders);
        for( int i=0; i<numHeaders; i++ ) {
            MessageBytes hN=headers.getName(i);
            // no header to sc conversion - there's little benefit
            // on this direction
            c2b.convert ( hN );
            outputMsg.appendBytes( hN );
                        
            MessageBytes hV=headers.getValue(i);
            c2b.convert( hV );
            outputMsg.appendBytes( hV );
        }
        mc.getSource().send( outputMsg, mc );
    
public intdoRead(org.apache.tomcat.util.buf.ByteChunk responseChunk, org.apache.coyote.Request req)


        if( log.isDebugEnabled())
            log.debug( "doRead "  + end_of_stream+
                       " " + responseChunk.getOffset()+ " " + responseChunk.getLength());
        if( end_of_stream ) {
            return -1;
        }

        if( isFirst && isReadRequired ) {
            // Handle special first-body-chunk, but only if httpd expects it.
            if( !receive() ) {
                return 0;
            }
        } else if(isEmpty) {
            if ( !refillReadBuffer() ){
                return -1;
            }
        }
        ByteChunk bc = bodyBuff.getByteChunk();
        responseChunk.setBytes( bc.getBuffer(), bc.getStart(), bc.getLength() );
        isEmpty = true;
        return responseChunk.getLength();
    
public intdoWrite(org.apache.tomcat.util.buf.ByteChunk chunk, org.apache.coyote.Response res)

        if (!res.isCommitted()) {
            // Send the connector a request for commit. The connector should
            // then validate the headers, send them (using sendHeader) and 
            // set the filters accordingly.
            res.sendHeaders();
        }

        int len=chunk.getLength();
        byte buf[]=outputMsg.getBuffer();
        // 4 - hardcoded, byte[] marshalling overhead 
        int chunkSize=buf.length - outputMsg.getHeaderLength() - 4;
        int off=0;
        while( len > 0 ) {
            int thisTime=len;
            if( thisTime > chunkSize ) {
                thisTime=chunkSize;
            }
            len-=thisTime;
            
            outputMsg.reset();
            outputMsg.appendByte( AjpConstants.JK_AJP13_SEND_BODY_CHUNK);
            if( log.isTraceEnabled() ) 
                log.trace("doWrite " + off + " " + thisTime + " " + len );
            outputMsg.appendBytes( chunk.getBytes(), chunk.getOffset() + off, thisTime );
            off+=thisTime;
            mc.getSource().send( outputMsg, mc );
        }
        return 0;
    
public voidendMessage()

        outputMsg.reset();
        outputMsg.appendByte(AjpConstants.JK_AJP13_END_RESPONSE);
        outputMsg.appendByte(1);
        mc.getSource().send(outputMsg, mc);
        mc.getSource().flush(outputMsg, mc);
    
public booleanisReadRequired()
Return the flag saying that the server is sending a body

        return isReadRequired;
    
public booleanreceive()
Receive a chunk of data. Called to implement the 'special' packet in ajp13 and to receive the data after we send a GET_BODY packet

        isFirst = false;
        bodyMsg.reset();
        int err = mc.getSource().receive(bodyMsg, mc);
        if( log.isDebugEnabled() )
            log.info( "Receiving: getting request body chunk " + err + " " + bodyMsg.getLen() );
        
        if(err < 0) {
            throw new IOException();
        }

        // No data received.
        if( bodyMsg.getLen() == 0 ) { // just the header
            // Don't mark 'end of stream' for the first chunk.
            // end_of_stream = true;
            return false;
        }
        int blen = bodyMsg.peekInt();

        if( blen == 0 ) {
            return false;
        }

        if( log.isTraceEnabled() ) {
            bodyMsg.dump("Body buffer");
        }
        
        bodyMsg.getBytes(bodyBuff);
        if( log.isTraceEnabled() )
            log.trace( "Data:\n" + bodyBuff);
        isEmpty = false;
        return true;
    
public voidrecycle()
Must be called before or after each request

        if(isReadRequired && isFirst) {
            // The Servlet never read the request body, so we need to junk it
            try {
              receive();
            } catch(IOException iex) {
              log.debug("Error consuming request body",iex);
            }
        }

        end_of_stream = false;
        isEmpty = true;
        isFirst = true;
        isReplay = false;
        isReadRequired = false;
        bodyBuff.recycle();
        tempMB.recycle();
    
private booleanrefillReadBuffer()
Get more request body data from the web server and store it in the internal buffer.

return
true if there is more data, false if not.

        // If the server returns an empty packet, assume that that end of
        // the stream has been reached (yuck -- fix protocol??).
        if(isReplay) {
            end_of_stream = true; // we've read everything there is
        }
        if (end_of_stream) {
            if( log.isDebugEnabled() ) 
                log.debug("refillReadBuffer: end of stream " );
            return false;
        }

        // Why not use outBuf??
        bodyMsg.reset();
        bodyMsg.appendByte(AjpConstants.JK_AJP13_GET_BODY_CHUNK);
        bodyMsg.appendInt(AjpConstants.MAX_READ_SIZE);
        
        if( log.isDebugEnabled() )
            log.debug("refillReadBuffer " + Thread.currentThread());

        mc.getSource().send(bodyMsg, mc);
        mc.getSource().flush(bodyMsg, mc); // Server needs to get it

        // In JNI mode, response will be in bodyMsg. In TCP mode, response need to be
        // read

        boolean moreData=receive();
        if( !moreData ) {
            end_of_stream=true;
        }
        return moreData;
    
public voidsetIsReadRequired(boolean irr)
Set the flag saying that the server is sending a body

        isReadRequired = irr;
    
public voidsetReplay(org.apache.tomcat.util.buf.ByteChunk replay)
Set the replay buffer for Form auth

        isFirst = false;
        isEmpty = false;
        isReplay = true;
        bodyBuff.setBytes(replay.getBytes(), replay.getStart(), replay.getLength());