Author: fhanik Date: Fri Oct 9 16:24:43 2009 New Revision: 823608 URL: http://svn.apache.org/viewvc?rev=823608&view=rev Log: Abstract out code for output buffer, much easier to read
Added: tomcat/trunk/java/org/apache/coyote/http11/AbstractOutputBuffer.java (with props) Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java tomcat/trunk/java/org/apache/coyote/http11/InternalNioOutputBuffer.java tomcat/trunk/java/org/apache/coyote/http11/InternalOutputBuffer.java Added: tomcat/trunk/java/org/apache/coyote/http11/AbstractOutputBuffer.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/AbstractOutputBuffer.java?rev=823608&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http11/AbstractOutputBuffer.java (added) +++ tomcat/trunk/java/org/apache/coyote/http11/AbstractOutputBuffer.java Fri Oct 9 16:24:43 2009 @@ -0,0 +1,566 @@ +/* + * 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 java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.OutputBuffer; +import org.apache.coyote.Response; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.HttpMessages; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.res.StringManager; + +public abstract class AbstractOutputBuffer implements OutputBuffer{ + + // ----------------------------------------------------- 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; + + + /** + * The buffer used for header composition. + */ + protected byte[] buf; + + + /** + * Position in the buffer. + */ + protected int pos; + + + + /** + * 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; + + /** + * Underlying output buffer. + */ + protected OutputBuffer outputStreamOutputBuffer; + + // -------------------------------------------------------------- Variables + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + // ------------------------------------------------------------- Properties + + + + + + /** + * Add an output filter to the filter library. + */ + public void addFilter(OutputFilter filter) { + + OutputFilter[] newFilterLibrary = + new OutputFilter[filterLibrary.length + 1]; + for (int i = 0; i < filterLibrary.length; i++) { + newFilterLibrary[i] = filterLibrary[i]; + } + newFilterLibrary[filterLibrary.length] = filter; + filterLibrary = newFilterLibrary; + + activeFilters = new OutputFilter[filterLibrary.length]; + + } + + + /** + * Get filters. + */ + public OutputFilter[] getFilters() { + + return filterLibrary; + + } + + + /** + * Clear filters. + */ + public void clearFilters() { + + filterLibrary = new OutputFilter[0]; + lastActiveFilter = -1; + + } + + + /** + * Add an output filter to the filter library. + */ + public void addActiveFilter(OutputFilter filter) { + + if (lastActiveFilter == -1) { + filter.setBuffer(outputStreamOutputBuffer); + } else { + for (int i = 0; i <= lastActiveFilter; i++) { + if (activeFilters[i] == filter) + return; + } + filter.setBuffer(activeFilters[lastActiveFilter]); + } + + activeFilters[++lastActiveFilter] = filter; + + filter.setResponse(response); + + } + + + + + // --------------------------------------------------- OutputBuffer Methods + + + /** + * Write the contents of a byte chunk. + * + * @param chunk byte chunk + * @return number of bytes written + * @throws IOException an undelying I/O error occured + */ + public int doWrite(ByteChunk chunk, Response res) + throws IOException { + + if (!committed) { + + // Send the connector a request for commit. The connector should + // then validate the headers, send them (using sendHeaders) and + // set the filters accordingly. + response.action(ActionCode.ACTION_COMMIT, null); + + } + + if (lastActiveFilter == -1) + return outputStreamOutputBuffer.doWrite(chunk, res); + else + return activeFilters[lastActiveFilter].doWrite(chunk, res); + + } + + // --------------------------------------------------------- Public Methods + + + /** + * Flush the response. + * + * @throws IOException an undelying I/O error occured + */ + public void flush() + throws IOException { + + if (!committed) { + + // Send the connector a request for commit. The connector should + // then validate the headers, send them (using sendHeader) and + // set the filters accordingly. + response.action(ActionCode.ACTION_COMMIT, null); + + } + } + + /** + * Reset current response. + * + * @throws IllegalStateException if the response has already been committed + */ + public void reset() { + + if (committed) + throw new IllegalStateException(/*FIXME:Put an error message*/); + + // Recycle Request object + response.recycle(); + + } + + /** + * Recycle the output buffer. This should be called when closing the + * connection. + */ + public void recycle() { + // Recycle filters + for (int i = 0; i <= lastActiveFilter; i++) { + activeFilters[i].recycle(); + } + // Recycle Request object + response.recycle(); + pos = 0; + lastActiveFilter = -1; + committed = false; + finished = 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 + response.recycle(); + // Recycle filters + for (int i = 0; i <= lastActiveFilter; i++) { + activeFilters[i].recycle(); + } + + // Reset pointers + pos = 0; + lastActiveFilter = -1; + committed = false; + finished = false; + + } + + /** + * End request. + * + * @throws IOException an undelying I/O error occured + */ + public void endRequest() + throws IOException { + + if (!committed) { + + // Send the connector a request for commit. The connector should + // then validate the headers, send them (using sendHeader) and + // set the filters accordingly. + response.action(ActionCode.ACTION_COMMIT, null); + + } + + if (finished) + return; + + if (lastActiveFilter != -1) + activeFilters[lastActiveFilter].end(); + finished = true; + + } + + public abstract void sendAck() throws IOException; + + protected abstract void commit() throws IOException; + + + /** + * Send the response status line. + */ + public void sendStatus() { + + // Write protocol name + write(Constants.HTTP_11_BYTES); + buf[pos++] = Constants.SP; + + // Write status code + int status = response.getStatus(); + switch (status) { + case 200: + write(Constants._200_BYTES); + break; + case 400: + write(Constants._400_BYTES); + break; + case 404: + write(Constants._404_BYTES); + break; + default: + write(status); + } + + buf[pos++] = Constants.SP; + + // Write message + String message = null; + if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER) { + message = response.getMessage(); + } + if (message == null) { + write(HttpMessages.getMessage(status)); + } else { + write(message.replace('\n', ' ').replace('\r', ' ')); + } + + // End the response status line + if (org.apache.coyote.Constants.IS_SECURITY_ENABLED){ + AccessController.doPrivileged( + new PrivilegedAction<Void>(){ + public Void run(){ + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + return null; + } + } + ); + } else { + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + } + + } + + + + /** + * Send a header. + * + * @param name Header name + * @param value Header value + */ + public void sendHeader(MessageBytes name, MessageBytes value) { + + write(name); + buf[pos++] = Constants.COLON; + buf[pos++] = Constants.SP; + write(value); + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * Send a header. + * + * @param name Header name + * @param value Header value + */ + public void sendHeader(ByteChunk name, ByteChunk value) { + + write(name); + buf[pos++] = Constants.COLON; + buf[pos++] = Constants.SP; + write(value); + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * Send a header. + * + * @param name Header name + * @param value Header value + */ + public void sendHeader(String name, String value) { + + write(name); + buf[pos++] = Constants.COLON; + buf[pos++] = Constants.SP; + write(value); + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * End the header block. + */ + public void endHeaders() { + + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * 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. + * + * @param mb data to be written + */ + protected void write(MessageBytes mb) { + + if (mb.getType() == MessageBytes.T_BYTES) { + ByteChunk bc = mb.getByteChunk(); + write(bc); + } else if (mb.getType() == MessageBytes.T_CHARS) { + 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. + * + * @param 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(), buf, pos, length); + pos = pos + 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. + * + * @param 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 = start; i < end; i++) { + 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 = ' '; + } else if (c == 127) { + c = ' '; + } + buf[pos++] = (byte) c; + } + + } + + + /** + * 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. + * + * @param b data to be written + */ + public void write(byte[] b) { + + // Writing the byte chunk to the output buffer + System.arraycopy(b, 0, buf, pos, b.length); + pos = pos + 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. + * + * @param 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 < len; i++) { + 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 = ' '; + } else if (c == 127) { + c = ' '; + } + buf[pos++] = (byte) c; + } + + } + + + /** + * 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. + * + * @param i data to be written + */ + protected void write(int i) { + + write(String.valueOf(i)); + + } + + + +} Propchange: tomcat/trunk/java/org/apache/coyote/http11/AbstractOutputBuffer.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java?rev=823608&r1=823607&r2=823608&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java (original) +++ tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java Fri Oct 9 16:24:43 2009 @@ -66,18 +66,6 @@ /** - * Logger. - */ - protected static org.apache.juli.logging.Log log - = org.apache.juli.logging.LogFactory.getLog(Http11NioProcessor.class); - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - /** * SSL information. */ protected SSLSupport sslSupport; Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java?rev=823608&r1=823607&r2=823608&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java (original) +++ tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java Fri Oct 9 16:24:43 2009 @@ -56,14 +56,7 @@ */ public class Http11Processor extends AbstractHttp11Processor implements ActionHook { - - /** - * Logger. - */ - protected static org.apache.juli.logging.Log log - = org.apache.juli.logging.LogFactory.getLog(Http11Processor.class); - - // ------------------------------------------------------------ Constructor + // ------------------------------------------------------------ Constructor public Http11Processor(int headerBufferSize, JIoEndpoint endpoint) { Modified: tomcat/trunk/java/org/apache/coyote/http11/InternalNioOutputBuffer.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/InternalNioOutputBuffer.java?rev=823608&r1=823607&r2=823608&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http11/InternalNioOutputBuffer.java (original) +++ tomcat/trunk/java/org/apache/coyote/http11/InternalNioOutputBuffer.java Fri Oct 9 16:24:43 2009 @@ -22,19 +22,14 @@ import java.nio.channels.SelectionKey; import java.nio.channels.Selector; -import org.apache.coyote.ActionCode; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Response; +import org.apache.tomcat.util.MutableInteger; import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.http.HttpMessages; -import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.net.NioChannel; import org.apache.tomcat.util.net.NioEndpoint; import org.apache.tomcat.util.net.NioSelectorPool; -import org.apache.tomcat.util.res.StringManager; -import org.apache.tomcat.util.MutableInteger; /** * Output buffer. @@ -42,8 +37,7 @@ * @author <a href="mailto:r...@apache.org">Remy Maucherat</a> * @author Filip Hanik */ -public class InternalNioOutputBuffer - implements OutputBuffer { +public class InternalNioOutputBuffer extends AbstractOutputBuffer { // -------------------------------------------------------------- Constants @@ -93,54 +87,6 @@ } - // -------------------------------------------------------------- Variables - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------- 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; - /** * Number of bytes last written */ @@ -158,29 +104,6 @@ - /** - * 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; // ------------------------------------------------------------- Properties @@ -207,67 +130,6 @@ return pool; } - /** - * Add an output filter to the filter library. - */ - public void addFilter(OutputFilter filter) { - - OutputFilter[] newFilterLibrary = - new OutputFilter[filterLibrary.length + 1]; - for (int i = 0; i < filterLibrary.length; i++) { - newFilterLibrary[i] = filterLibrary[i]; - } - newFilterLibrary[filterLibrary.length] = filter; - filterLibrary = newFilterLibrary; - - activeFilters = new OutputFilter[filterLibrary.length]; - - } - - - /** - * Get filters. - */ - public OutputFilter[] getFilters() { - - return filterLibrary; - - } - - - /** - * Clear filters. - */ - public void clearFilters() { - - filterLibrary = new OutputFilter[0]; - lastActiveFilter = -1; - - } - - - /** - * Add an output filter to the filter library. - */ - public void addActiveFilter(OutputFilter filter) { - - if (lastActiveFilter == -1) { - filter.setBuffer(outputStreamOutputBuffer); - } else { - for (int i = 0; i <= lastActiveFilter; i++) { - if (activeFilters[i] == filter) - return; - } - filter.setBuffer(activeFilters[lastActiveFilter]); - } - - activeFilters[++lastActiveFilter] = filter; - - filter.setResponse(response); - - } - - // --------------------------------------------------------- Public Methods @@ -275,19 +137,12 @@ * Flush the response. * * @throws IOException an undelying I/O error occured + * */ - public void flush() - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeader) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } + @Override + public void flush() throws IOException { + super.flush(); // Flush the current buffer flushBuffer(); @@ -295,66 +150,15 @@ /** - * Reset current response. - * - * @throws IllegalStateException if the response has already been committed - */ - public void reset() { - - if (committed) - throw new IllegalStateException(/*FIXME:Put an error message*/); - - // Recycle Request object - response.recycle(); - } - - - /** * Recycle the output buffer. This should be called when closing the * connection. */ + @Override public void recycle() { - // Recycle filters - for (int i = 0; i <= lastActiveFilter; i++) { - activeFilters[i].recycle(); - } - - // Recycle Request object - response.recycle(); + super.recycle(); socket.getBufHandler().getWriteBuffer().clear(); - socket = null; - pos = 0; - lastActiveFilter = -1; - committed = false; - finished = false; lastWrite.set(1); - - } - - - /** - * 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 - response.recycle(); - - // Recycle filters - for (int i = 0; i <= lastActiveFilter; i++) { - activeFilters[i].recycle(); - } - - // Reset pointers - pos = 0; - lastActiveFilter = -1; - committed = false; - finished = false; - } @@ -363,28 +167,10 @@ * * @throws IOException an undelying I/O error occured */ - public void endRequest() - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeader) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - if (finished) - return; - - if (lastActiveFilter != -1) - activeFilters[lastActiveFilter].end(); - + @Override + public void endRequest() throws IOException { + super.endRequest(); flushBuffer(); - - finished = true; - } public boolean isWritable() { @@ -396,8 +182,7 @@ /** * Send an acknoledgement. */ - public void sendAck() - throws IOException { + public void sendAck() throws IOException { if (!committed) { //Socket.send(socket, Constants.ACK_BYTES, 0, Constants.ACK_BYTES.length) < 0 @@ -443,145 +228,6 @@ } - /** - * Send the response status line. - */ - public void sendStatus() { - - // Write protocol name - write(Constants.HTTP_11_BYTES); - buf[pos++] = Constants.SP; - - // Write status code - int status = response.getStatus(); - switch (status) { - case 200: - write(Constants._200_BYTES); - break; - case 400: - write(Constants._400_BYTES); - break; - case 404: - write(Constants._404_BYTES); - break; - default: - write(status); - } - - buf[pos++] = Constants.SP; - - // Write message - String message = null; - if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER) { - message = response.getMessage(); - } - if (message == null) { - write(HttpMessages.getMessage(status)); - } else { - write(message.replace('\n', ' ').replace('\r', ' ')); - } - - // End the response status line - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(MessageBytes name, MessageBytes value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(ByteChunk name, ByteChunk value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(String name, String value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * End the header block. - */ - public void endHeaders() { - - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - // --------------------------------------------------- OutputBuffer Methods - - - /** - * Write the contents of a byte chunk. - * - * @param chunk byte chunk - * @return number of bytes written - * @throws IOException an undelying I/O error occured - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeaders) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - if (lastActiveFilter == -1) - return outputStreamOutputBuffer.doWrite(chunk, res); - else - return activeFilters[lastActiveFilter].doWrite(chunk, res); - - } - // ------------------------------------------------------ Protected Methods @@ -628,135 +274,6 @@ /** - * 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. - * - * @param mb data to be written - */ - protected void write(MessageBytes mb) { - - if (mb.getType() == MessageBytes.T_BYTES) { - ByteChunk bc = mb.getByteChunk(); - write(bc); - } else if (mb.getType() == MessageBytes.T_CHARS) { - 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. - * - * @param 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(), buf, pos, length); - pos = pos + 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. - * - * @param 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 = start; i < end; i++) { - 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 = ' '; - } else if (c == 127) { - c = ' '; - } - buf[pos++] = (byte) c; - } - - } - - - /** - * 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. - * - * @param b data to be written - */ - public void write(byte[] b) { - - // Writing the byte chunk to the output buffer - System.arraycopy(b, 0, buf, pos, b.length); - pos = pos + 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. - * - * @param 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 < len; i++) { - 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 = ' '; - } else if (c == 127) { - c = ' '; - } - buf[pos++] = (byte) c; - } - - } - - - /** - * 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. - * - * @param i data to be written - */ - protected void write(int i) { - - write(String.valueOf(i)); - - } - - - /** * Callback to write data from the buffer. */ protected void flushBuffer() Modified: tomcat/trunk/java/org/apache/coyote/http11/InternalOutputBuffer.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/InternalOutputBuffer.java?rev=823608&r1=823607&r2=823608&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http11/InternalOutputBuffer.java (original) +++ tomcat/trunk/java/org/apache/coyote/http11/InternalOutputBuffer.java Fri Oct 9 16:24:43 2009 @@ -19,27 +19,18 @@ import java.io.IOException; import java.io.OutputStream; -import java.security.AccessController; -import java.security.PrivilegedAction; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.HttpMessages; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.res.StringManager; - -import org.apache.coyote.ActionCode; import org.apache.coyote.OutputBuffer; import org.apache.coyote.Response; +import org.apache.tomcat.util.buf.ByteChunk; /** * Output buffer. * * @author <a href="mailto:r...@apache.org">Remy Maucherat</a> */ -public class InternalOutputBuffer - implements OutputBuffer, ByteChunk.ByteOutputChannel { +public class InternalOutputBuffer extends AbstractOutputBuffer + implements ByteChunk.ByteOutputChannel { // -------------------------------------------------------------- Constants @@ -80,56 +71,6 @@ } - - // -------------------------------------------------------------- Variables - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------- 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; - - - /** - * The buffer used for header composition. - */ - protected byte[] buf; - - - /** - * Position in the buffer. - */ - protected int pos; - - /** * Underlying output stream. */ @@ -137,31 +78,6 @@ /** - * 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; - - - /** * Socket buffer. */ protected ByteChunk socketBuffer; @@ -170,12 +86,8 @@ /** * Socket buffer (extra buffering to reduce number of packets sent). */ - protected boolean useSocketBuffer = false; - - - // ------------------------------------------------------------- Properties - - + protected boolean useSocketBuffer = false; + /** * Set the underlying socket output stream. */ @@ -211,68 +123,9 @@ } } + - /** - * Add an output filter to the filter library. - */ - public void addFilter(OutputFilter filter) { - - OutputFilter[] newFilterLibrary = - new OutputFilter[filterLibrary.length + 1]; - for (int i = 0; i < filterLibrary.length; i++) { - newFilterLibrary[i] = filterLibrary[i]; - } - newFilterLibrary[filterLibrary.length] = filter; - filterLibrary = newFilterLibrary; - - activeFilters = new OutputFilter[filterLibrary.length]; - - } - - - /** - * Get filters. - */ - public OutputFilter[] getFilters() { - - return filterLibrary; - - } - - - /** - * Clear filters. - */ - public void clearFilters() { - - filterLibrary = new OutputFilter[0]; - lastActiveFilter = -1; - - } - - - /** - * Add an output filter to the filter library. - */ - public void addActiveFilter(OutputFilter filter) { - - if (lastActiveFilter == -1) { - filter.setBuffer(outputStreamOutputBuffer); - } else { - for (int i = 0; i <= lastActiveFilter; i++) { - if (activeFilters[i] == filter) - return; - } - filter.setBuffer(activeFilters[lastActiveFilter]); - } - - activeFilters[++lastActiveFilter] = filter; - - filter.setResponse(response); - - } - // --------------------------------------------------------- Public Methods @@ -280,20 +133,13 @@ /** * Flush the response. * - * @throws IOException an undelying I/O error occured + * @throws IOException an underlying I/O error occurred */ public void flush() throws IOException { - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeader) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - + super.flush(); + // Flush the current buffer if (useSocketBuffer) { socketBuffer.flushBuffer(); @@ -302,20 +148,7 @@ } - /** - * Reset current response. - * - * @throws IllegalStateException if the response has already been committed - */ - public void reset() { - - if (committed) - throw new IllegalStateException(/*FIXME:Put an error message*/); - - // Recycle Request object - response.recycle(); - - } + /** @@ -323,17 +156,9 @@ * connection. */ public void recycle() { - - // Recycle Request object - response.recycle(); + super.recycle(); socketBuffer.recycle(); - outputStream = null; - pos = 0; - lastActiveFilter = -1; - committed = false; - finished = false; - } @@ -344,54 +169,22 @@ * to parse the next HTTP request. */ public void nextRequest() { - - // Recycle Request object - response.recycle(); + super.nextRequest(); socketBuffer.recycle(); - - // Recycle filters - for (int i = 0; i <= lastActiveFilter; i++) { - activeFilters[i].recycle(); - } - - // Reset pointers - pos = 0; - lastActiveFilter = -1; - committed = false; - finished = false; - } /** * End request. * - * @throws IOException an undelying I/O error occured + * @throws IOException an underlying I/O error occurred */ public void endRequest() throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeader) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - if (finished) - return; - - if (lastActiveFilter != -1) - activeFilters[lastActiveFilter].end(); - + super.endRequest(); if (useSocketBuffer) { socketBuffer.flushBuffer(); } - - finished = true; - } @@ -410,156 +203,6 @@ } - /** - * Send the response status line. - */ - public void sendStatus() { - - // Write protocol name - write(Constants.HTTP_11_BYTES); - buf[pos++] = Constants.SP; - - // Write status code - int status = response.getStatus(); - switch (status) { - case 200: - write(Constants._200_BYTES); - break; - case 400: - write(Constants._400_BYTES); - break; - case 404: - write(Constants._404_BYTES); - break; - default: - write(status); - } - - buf[pos++] = Constants.SP; - - // Write message - String message = null; - if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER) { - message = response.getMessage(); - } - if (message == null) { - write(HttpMessages.getMessage(status)); - } else { - write(message.replace('\n', ' ').replace('\r', ' ')); - } - - // End the response status line - if (org.apache.coyote.Constants.IS_SECURITY_ENABLED){ - AccessController.doPrivileged( - new PrivilegedAction<Void>(){ - public Void run(){ - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - return null; - } - } - ); - } else { - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - } - - } - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(MessageBytes name, MessageBytes value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(ByteChunk name, ByteChunk value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(String name, String value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * End the header block. - */ - public void endHeaders() { - - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - // --------------------------------------------------- OutputBuffer Methods - - - /** - * Write the contents of a byte chunk. - * - * @param chunk byte chunk - * @return number of bytes written - * @throws IOException an undelying I/O error occured - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeaders) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - if (lastActiveFilter == -1) - return outputStreamOutputBuffer.doWrite(chunk, res); - else - return activeFilters[lastActiveFilter].doWrite(chunk, res); - - } - // ------------------------------------------------------ Protected Methods @@ -588,134 +231,7 @@ } - /** - * 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. - * - * @param mb data to be written - */ - protected void write(MessageBytes mb) { - - if (mb.getType() == MessageBytes.T_BYTES) { - ByteChunk bc = mb.getByteChunk(); - write(bc); - } else if (mb.getType() == MessageBytes.T_CHARS) { - 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. - * - * @param 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(), buf, pos, length); - pos = pos + 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. - * - * @param 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 = start; i < end; i++) { - 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 = ' '; - } else if (c == 127) { - c = ' '; - } - buf[pos++] = (byte) c; - } - - } - - - /** - * 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. - * - * @param b data to be written - */ - public void write(byte[] b) { - - // Writing the byte chunk to the output buffer - System.arraycopy(b, 0, buf, pos, b.length); - pos = pos + 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. - * - * @param 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 < len; i++) { - 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 = ' '; - } else if (c == 127) { - c = ' '; - } - buf[pos++] = (byte) c; - } - - } - - - /** - * 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. - * - * @param i data to be written - */ - protected void write(int i) { - - write(String.valueOf(i)); - - } - + /** * Callback to write data from the buffer. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org