Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   *  Licensed to the Apache Software Foundation (ASF) under one or more
   *  contributor license agreements.  See the NOTICE file distributed with
   *  this work for additional information regarding copyright ownership.
   *  The ASF licenses this file to You under the Apache License, Version 2.0
   *  (the "License"); you may not use this file except in compliance with
   *  the License.  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
  *
  *  Unless required by applicable law or agreed to in writing, software
  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
 
 package org.apache.coyote.http11;
 
 import static org.jboss.web.CoyoteMessages.MESSAGES;
 
 
 
Output buffer.

Author(s):
Remy Maucherat
 
 public class InternalAprOutputBuffer 
     implements OutputBuffer {
 
 
     // -------------------------------------------------------------- Constants
 
 
     // ----------------------------------------------------------- Constructors
 

    
Alternate constructor.
 
     public InternalAprOutputBuffer(Response responseint headerBufferSizeAprEndpoint endpoint) {
 
         this. = response;
         this. = endpoint;
          = response.getMimeHeaders();
 
          = new byte[headerBufferSize];
         if (headerBufferSize < (8 * 1024)) {
              = ByteBuffer.allocateDirect(6 * 1500);
         } else {
              = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500);
         }
 
          = new SocketOutputBuffer();
 
          = new OutputFilter[0];
          = new OutputFilter[0];
          = -1;
 
          = false;
          = false;
 
          = new ByteChunk();
          = false;
         
         // Cause loading of HttpMessages
         HttpMessages.getMessage(200);
 
         // Cause loading of constants
         boolean res = ....;
 
     }
 
 
     // ----------------------------------------------------- Instance Variables
 

    
Associated Coyote response.
 
     protected Response response;


    
Headers of the associated request.
    protected MimeHeaders headers;


    
Committed flag.
    protected boolean committed;


    
Finished flag.
    protected boolean finished;


    
Pointer to the current write buffer.
    protected byte[] buf;


    
Position in the buffer.
    protected int pos;


    
Underlying socket.
    protected long socket;


    
Underlying output buffer.
    protected OutputBuffer outputStreamOutputBuffer;


    
Filter library. Note: Filter[0] is always the "chunked" filter.
    protected OutputFilter[] filterLibrary;


    
Active filter (which is actually the top of the pipeline).
    protected OutputFilter[] activeFilters;


    
Index of the last active filter.
    protected int lastActiveFilter;


    
Direct byte buffer used for writing.
    protected ByteBuffer bbuf = null;

    
    
Leftover bytes which could not be written during a non blocking write.
    protected ByteChunk leftover = null;

    
    
Non blocking mode.
    protected boolean nonBlocking = false;
    

    
Apr endpoint.
    protected AprEndpoint endpoint = null;
    
    // ------------------------------------------------------------- Properties


    
Set the underlying socket.
    public void setSocket(long socket) {
        this. = socket;
        Socket.setsbb(this.);
    }


    
Get the underlying socket input stream.
    public long getSocket() {
        return ;
    }


    
Set the non blocking flag.
    public void setNonBlocking(boolean nonBlocking) {
        this. = nonBlocking;
    }


    
Get the non blocking flag value.
    public boolean getNonBlocking() {
        return ;
    }


    
Add an output filter to the filter library.
    public void addFilter(OutputFilter filter) {
        OutputFilter[] newFilterLibrary = 
            new OutputFilter[. + 1];
        for (int i = 0; i < .i++) {
            newFilterLibrary[i] = [i];
        }
        newFilterLibrary[.] = filter;
         = newFilterLibrary;
    }


    
Get filters.
    public OutputFilter[] getFilters() {
        return ;
    }


    
Clear filters.
    public void clearFilters() {
         = new OutputFilter[0];
         = -1;
    }


    
Add an output filter to the filter library.
    public void addActiveFilter(OutputFilter filter) {
        if ( == -1) {
            filter.setBuffer();
        } else {
            for (int i = 0; i <= i++) {
                if ([i] == filter)
                    return;
            }
            filter.setBuffer([]);
        }
        [++] = filter;
        filter.setResponse();
    }
    public void removeActiveFilters() {
        // Recycle filters
        for (int i = 0; i <= i++) {
            [i].recycle();
        }
         = -1;
    }
    // --------------------------------------------------------- Public Methods


    
Flush the response.

Throws:
java.io.IOException an undelying I/O error occured
    public void flush()
        throws IOException {
        if (!) {
            // Send the connector a request for commit. The connector should
            // then validate the headers, send them (using sendHeader) and 
            // set the filters accordingly.
            .action(.null);
        }
        // Flush the current buffer
        flushBuffer();
    }


    
Recycle the output buffer. This should be called when closing the connection.
    public void recycle() {
        // Recycle Request object
        .recycle();
         = 0;
         = 0;
         = -1;
         = false;
         = false;
    }


    
End processing of current HTTP request. Note: All bytes of the current request should have been already consumed. This method only resets all the pointers so that we are ready to parse the next HTTP request.
    public void nextRequest() {
        // Recycle Request object
        .recycle();
        // Recycle filters
        for (int i = 0; i <= i++) {
            [i].recycle();
        }
        // Reset pointers
        .recycle();
         = 0;
         = -1;
         = false;
         = false;
         = false;
    }


    
End request.

Throws:
java.io.IOException an undelying I/O error occured
    public void endRequest()
        throws IOException {
        if (!) {
            // Send the connector a request for commit. The connector should
            // then validate the headers, send them (using sendHeader) and 
            // set the filters accordingly.
            .action(.null);
        }
        if ()
            return;
        if ( != -1)
            [].end();
        flushBuffer();
         = true;
    }
    // ------------------------------------------------ HTTP/1.1 Output Methods


    
Send an acknoledgement.
    public void sendAck()
        throws IOException {
        if (!) {
            if (Socket.send(., 0, ..) < 0)
                throw new IOException(.failedWrite());
        }
    }


    
Send the response status line.
    public void sendStatus() {
        // Write protocol name
        write(.);
        [++] = .;
        // Write status code
        int status = .getStatus();
        switch (status) {
        case 200:
            write(.);
            break;
        case 400:
            write(.);
            break;
        case 404:
            write(.);
            break;
        default:
            write(status);
        }
        [++] = .;
        // Write message
        String message = null;
            message = .getMessage();
        }
        if (message == null) {
            write(HttpMessages.getMessage(status));
        } else {
            write(message.replace('\n'' ').replace('\r'' '));
        }
        // End the response status line
        [++] = .;
        [++] = .;
    }


    
Send a header.

Parameters:
name Header name
value Header value
    public void sendHeader(MessageBytes nameMessageBytes value) {
        if (name.getLength() > 0 && !value.isNull()) {
            write(name);
            [++] = .;
            [++] = .;
            write(value);
            [++] = .;
            [++] = .;
        }
    }


    
Send a header.

Parameters:
name Header name
value Header value
    public void sendHeader(ByteChunk nameByteChunk value) {
        write(name);
        [++] = .;
        [++] = .;
        write(value);
        [++] = .;
        [++] = .;
    }


    
Send a header.

Parameters:
name Header name
value Header value
    public void sendHeader(String nameString value) {
        write(name);
        [++] = .;
        [++] = .;
        write(value);
        [++] = .;
        [++] = .;
    }


    
End the header block.
    public void endHeaders() {
        [++] = .;
        [++] = .;
    }
    // --------------------------------------------------- OutputBuffer Methods


    
Write the contents of a byte chunk.

Parameters:
chunk byte chunk
Returns:
number of bytes written
Throws:
java.io.IOException an undelying I/O error occured
    public int doWrite(ByteChunk chunkResponse res
        throws IOException {
        if (!) {
            // Send the connector a request for commit. The connector should
            // then validate the headers, send them (using sendHeaders) and 
            // set the filters accordingly.
            .action(.null);
        }
        // If non blocking (event) and there are leftover bytes, 
        // and lastWrite was 0 -> error
        if (.getLength() > 0 && !(..get() == .)) {
            throw new IOException(.invalidBacklog());
        }
        if ( == -1)
            return .doWrite(chunkres);
        else
            return [].doWrite(chunkres);
    }
    // ------------------------------------------------------ Protected Methods


    
Commit the response.

Throws:
java.io.IOException an undelying I/O error occured
    protected void commit()
        throws IOException {
        // The response is now committed
         = true;
        .setCommitted(true);
        if ( > 0) {
            // Sending the response header buffer
            .clear();
            .put(, 0, );
        }
    }


    
This method will write the contents of the specyfied message bytes buffer to the output stream, without filtering. This method is meant to be used to write the response header.

Parameters:
mb data to be written
    protected void write(MessageBytes mb) {
        if (mb.getType() == .) {
            ByteChunk bc = mb.getByteChunk();
            write(bc);
        } else if (mb.getType() == .) {
            CharChunk cc = mb.getCharChunk();
            write(cc);
        } else {
            write(mb.toString());
        }
    }


    
This method will write the contents of the specyfied message bytes buffer to the output stream, without filtering. This method is meant to be used to write the response header.

Parameters:
bc data to be written
    protected void write(ByteChunk bc) {
        // Writing the byte chunk to the output buffer
        int length = bc.getLength();
        System.arraycopy(bc.getBytes(), bc.getStart(), length);
         =  + length;
    }


    
This method will write the contents of the specyfied char buffer to the output stream, without filtering. This method is meant to be used to write the response header.

Parameters:
cc data to be written
    protected void write(CharChunk cc) {
        int start = cc.getStart();
        int end = cc.getEnd();
        char[] cbuf = cc.getBuffer();
        for (int i = starti < endi++) {
            char c = cbuf[i];
            // Note:  This is clearly incorrect for many strings,
            // but is the only consistent approach within the current
            // servlet framework.  It must suffice until servlet output
            // streams properly encode their output.
            if (((c <= 31) && (c != 9)) || c == 127 || c > 255) {
                c = ' ';
            }
            [++] = (bytec;
        }
    }


    
This method will write the contents of the specyfied byte buffer to the output stream, without filtering. This method is meant to be used to write the response header.

Parameters:
b data to be written
    public void write(byte[] b) {
        // Writing the byte chunk to the output buffer
        System.arraycopy(b, 0, b.length);
         =  + b.length;
    }


    
This method will write the contents of the specyfied String to the output stream, without filtering. This method is meant to be used to write the response header.

Parameters:
s data to be written
    protected void write(String s) {
        if (s == null)
            return;
        // From the Tomcat 3.3 HTTP/1.0 connector
        int len = s.length();
        for (int i = 0; i < leni++) {
            char c = s.charAt (i);
            // Note:  This is clearly incorrect for many strings,
            // but is the only consistent approach within the current
            // servlet framework.  It must suffice until servlet output
            // streams properly encode their output.
            if (((c <= 31) && (c != 9)) || c == 127 || c > 255) {
                c = ' ';
            }
            [++] = (bytec;
        }
    }


    
This method will print the specified integer to the output stream, without filtering. This method is meant to be used to write the response header.

Parameters:
i data to be written
    protected void write(int i) {
        write(String.valueOf(i));
    }

    
    
Flush leftover bytes.

Returns:
true if all leftover bytes have been flushed
    public boolean flushLeftover()
        throws IOException {
        int len = .getLength();
        int start = .getStart();
        byte[] b = .getBuffer();
        
        while (len > 0) {
            int thisTime = len;
            if (.position() == .capacity()) {
                int pos = 0;
                int end = .position();
                int res = 0;
                while (pos < end) {
                    res = Socket.sendibb(posend - pos);
                    if (res > 0) {
                        pos += res;
                    } else {
                        break;
                    }
                }
                if (res < 0) {
                    throw new IOException(.failedWrite());
                }
                .setLastWrite(res);
                if (pos < end) {
                    // Could not write all leftover data: put back to write poller
                    .setOffset(start);
                    .position(pos);
                    return false;
                } else {
                    .clear();
                }
            }
            if (thisTime > .capacity() - .position()) {
                thisTime = .capacity() - .position();
            }
            .put(bstartthisTime);
            len = len - thisTime;
            start = start + thisTime;
        }
        
        int pos = 0;
        int end = .position();
        if (pos < end) {
            int res = 0;
            while (pos < end) {
                res = Socket.sendibb(posend - pos);
                if (res > 0) {
                    pos += res;
                } else {
                    break;
                }
            }
            if (res < 0) {
                throw new IOException(.failedWrite());
            }
            .setLastWrite(res);
        }
        if (pos < end) {
            .allocate(end - pos, -1);
            .position(pos);
            .limit(end);
            .get(.getBuffer(), 0, end - pos);
            .setEnd(end - pos);
            .clear();
            return false;
        }
        .clear();
        .recycle();
        return true;
    }
    

    
Callback to write data from the buffer.
    protected void flushBuffer()
        throws IOException {
        int res = 0;
        
        // If there are still leftover bytes here, this means the user did a direct flush:
        // - If the call is asynchronous, throw an exception
        // - If the call is synchronous, make regular blocking writes to flush the data
        if (.getLength() > 0) {
            if (..get() == .) {
                Socket.timeoutSet(.getSoTimeout() * 1000);
                // Send leftover bytes
                res = Socket.send(.getBuffer(), .getOffset(), .getEnd());
                .recycle();
                // Send current buffer
                if (res > 0 && .position() > 0) {
                    res = Socket.sendbb(, 0, .position());
                }
                .clear();
                Socket.timeoutSet(, 0);
            } else {
                throw new IOException(.invalidBacklog());
            }
        }
        
        if (.position() > 0) {
            if () {
                // Perform non blocking writes until all data is written, or the result
                // of the write is 0
                int pos = 0;
                int end = .position();
                while (pos < end) {
                    res = Socket.sendibb(posend - pos);
                    if (res > 0) {
                        pos += res;
                    } else {
                        break;
                    }
                }
                if (pos < end) {
                    if (.getFlushLeftovers() && (..get() == .)) {
                        // Switch to blocking mode and write the data
                        Socket.timeoutSet(.getSoTimeout() * 1000);
                        res = Socket.sendbb(, 0, end);
                        Socket.timeoutSet(, 0);
                    } else {
                        // Put any leftover bytes in the leftover byte chunk
                        .allocate(end - pos, -1);
                        .position(pos);
                        .limit(end);
                        .get(.getBuffer(), 0, end - pos);
                        .setEnd(end - pos);
                        // Call for a write event because it is possible that no further write
                        // operations are made
                        if (!.getFlushLeftovers()) {
                            .action(.null);
                        }
                    }
                }
            } else {
                res = Socket.sendbb(, 0, .position());
            }
            .setLastWrite(res);
            .clear();
            if (res < 0) {
                throw new IOException(.failedWrite());
            }
        }
        
    }
    // ----------------------------------- OutputStreamOutputBuffer Inner Class


    
This class is an output buffer which will write data to an output stream.
    protected class SocketOutputBuffer 
        implements OutputBuffer {


        
Write chunk.
        public int doWrite(ByteChunk chunkResponse res
            throws IOException {
            // If non blocking (event) and there are leftover bytes, 
            // put all remaining bytes in the leftover buffer (they are
            // part of the same write operation)
            if (.getLength() > 0) {
                .append(chunk);
                return chunk.getLength();
            }
            
            int len = chunk.getLength();
            int start = chunk.getStart();
            byte[] b = chunk.getBuffer();
            while (len > 0) {
                int thisTime = len;
                if (.position() == .capacity()) {
                    flushBuffer();
                    if (.getLength() > 0) {
                        // If non blocking (event) and there are leftover bytes, 
                        // put all remaining bytes in the leftover buffer (they are
                        // part of the same write operation)
                        int oldStart = chunk.getOffset();
                        chunk.setOffset(start);
                        .append(chunk);
                        chunk.setOffset(oldStart);
                        // After that, all content has been "written"
                        return chunk.getLength();
                    }
                }
                if (thisTime > .capacity() - .position()) {
                    thisTime = .capacity() - .position();
                }
                .put(bstartthisTime);
                len = len - thisTime;
                start = start + thisTime;
            }
            return chunk.getLength();
        }
    }
New to GrepCode? Check out our FAQ X