Added: tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/coyote/http11/InternalAprInputBuffer.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/coyote/http11/InternalAprInputBuffer.java?rev=640860&view=auto ============================================================================== --- tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/coyote/http11/InternalAprInputBuffer.java (added) +++ tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/coyote/http11/InternalAprInputBuffer.java Tue Mar 25 08:26:26 2008 @@ -0,0 +1,807 @@ +/* + * 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.io.EOFException; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; + +import org.apache.tomcat.jni.Socket; +import org.apache.tomcat.jni.Status; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.res.StringManager; + +import org.apache.coyote.InputBuffer; +import org.apache.coyote.Request; + +/** + * Implementation of InputBuffer which provides HTTP request header parsing as + * well as transfer decoding. + * + * @author <a href="mailto:[EMAIL PROTECTED]">Remy Maucherat</a> + */ +public class InternalAprInputBuffer implements InputBuffer { + + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------------- Constructors + + + /** + * Alternate constructor. + */ + public InternalAprInputBuffer(Request request, int headerBufferSize) { + + this.request = request; + headers = request.getMimeHeaders(); + + buf = new byte[headerBufferSize]; + if (headerBufferSize < (8 * 1024)) { + bbuf = ByteBuffer.allocateDirect(6 * 1500); + } else { + bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500); + } + + inputStreamInputBuffer = new SocketInputBuffer(); + + filterLibrary = new InputFilter[0]; + activeFilters = new InputFilter[0]; + lastActiveFilter = -1; + + parsingHeader = true; + swallowInput = true; + + } + + + // -------------------------------------------------------------- Variables + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated Coyote request. + */ + protected Request request; + + + /** + * Headers of the associated request. + */ + protected MimeHeaders headers; + + + /** + * State. + */ + protected boolean parsingHeader; + + + /** + * Swallow input ? (in the case of an expectation) + */ + protected boolean swallowInput; + + + /** + * Pointer to the current read buffer. + */ + protected byte[] buf; + + + /** + * Last valid byte. + */ + protected int lastValid; + + + /** + * Position in the buffer. + */ + protected int pos; + + + /** + * Pos of the end of the header in the buffer, which is also the + * start of the body. + */ + protected int end; + + + /** + * Direct byte buffer used to perform actual reading. + */ + protected ByteBuffer bbuf; + + + /** + * Underlying socket. + */ + protected long socket; + + + /** + * Underlying input buffer. + */ + protected InputBuffer inputStreamInputBuffer; + + + /** + * Filter library. + * Note: Filter[0] is always the "chunked" filter. + */ + protected InputFilter[] filterLibrary; + + + /** + * Active filters (in order). + */ + protected InputFilter[] activeFilters; + + + /** + * Index of the last active filter. + */ + protected int lastActiveFilter; + + + // ------------------------------------------------------------- Properties + + + /** + * Set the underlying socket. + */ + public void setSocket(long socket) { + this.socket = socket; + Socket.setrbb(this.socket, bbuf); + } + + + /** + * Get the underlying socket input stream. + */ + public long getSocket() { + return socket; + } + + + /** + * Add an input filter to the filter library. + */ + public void addFilter(InputFilter filter) { + + InputFilter[] newFilterLibrary = + new InputFilter[filterLibrary.length + 1]; + for (int i = 0; i < filterLibrary.length; i++) { + newFilterLibrary[i] = filterLibrary[i]; + } + newFilterLibrary[filterLibrary.length] = filter; + filterLibrary = newFilterLibrary; + + activeFilters = new InputFilter[filterLibrary.length]; + + } + + + /** + * Get filters. + */ + public InputFilter[] getFilters() { + + return filterLibrary; + + } + + + /** + * Clear filters. + */ + public void clearFilters() { + + filterLibrary = new InputFilter[0]; + lastActiveFilter = -1; + + } + + + /** + * Add an input filter to the filter library. + */ + public void addActiveFilter(InputFilter filter) { + + if (lastActiveFilter == -1) { + filter.setBuffer(inputStreamInputBuffer); + } else { + for (int i = 0; i <= lastActiveFilter; i++) { + if (activeFilters[i] == filter) + return; + } + filter.setBuffer(activeFilters[lastActiveFilter]); + } + + activeFilters[++lastActiveFilter] = filter; + + filter.setRequest(request); + + } + + + /** + * Set the swallow input flag. + */ + public void setSwallowInput(boolean swallowInput) { + this.swallowInput = swallowInput; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Recycle the input buffer. This should be called when closing the + * connection. + */ + public void recycle() { + + // Recycle Request object + request.recycle(); + + socket = 0; + lastValid = 0; + pos = 0; + lastActiveFilter = -1; + parsingHeader = true; + swallowInput = true; + + } + + + /** + * 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 + request.recycle(); + + // Copy leftover bytes to the beginning of the buffer + if (lastValid - pos > 0) { + int npos = 0; + int opos = pos; + while (lastValid - opos > opos - npos) { + System.arraycopy(buf, opos, buf, npos, opos - npos); + npos += pos; + opos += pos; + } + System.arraycopy(buf, opos, buf, npos, lastValid - opos); + } + + // Recycle filters + for (int i = 0; i <= lastActiveFilter; i++) { + activeFilters[i].recycle(); + } + + // Reset pointers + lastValid = lastValid - pos; + pos = 0; + lastActiveFilter = -1; + parsingHeader = true; + swallowInput = true; + + } + + + /** + * End request (consumes leftover bytes). + * + * @throws IOException an undelying I/O error occured + */ + public void endRequest() + throws IOException { + + if (swallowInput && (lastActiveFilter != -1)) { + int extraBytes = (int) activeFilters[lastActiveFilter].end(); + pos = pos - extraBytes; + } + + } + + + /** + * Read the request line. This function is meant to be used during the + * HTTP request header parsing. Do NOT attempt to read the request body + * using it. + * + * @throws IOException If an exception occurs during the underlying socket + * read operations, or if the given buffer is not big enough to accomodate + * the whole line. + * @return true if data is properly fed; false if no data is available + * immediately and thread should be freed + */ + public boolean parseRequestLine(boolean useAvailableData) + throws IOException { + + int start = 0; + + // + // Skipping blank lines + // + + byte chr = 0; + do { + + // Read new bytes if needed + if (pos >= lastValid) { + if (useAvailableData) { + return false; + } + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + chr = buf[pos++]; + + } while ((chr == Constants.CR) || (chr == Constants.LF)); + + pos--; + + // Mark the current buffer position + start = pos; + + if (pos >= lastValid) { + if (useAvailableData) { + return false; + } + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + // + // Reading the method name + // Method name is always US-ASCII + // + + boolean space = false; + + while (!space) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.SP) { + space = true; + request.method().setBytes(buf, start, pos - start); + } + + pos++; + + } + + // Mark the current buffer position + start = pos; + int end = 0; + int questionPos = -1; + + // + // Reading the URI + // + + space = false; + boolean eol = false; + + while (!space) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.SP) { + space = true; + end = pos; + } else if ((buf[pos] == Constants.CR) + || (buf[pos] == Constants.LF)) { + // HTTP/0.9 style request + eol = true; + space = true; + end = pos; + } else if ((buf[pos] == Constants.QUESTION) + && (questionPos == -1)) { + questionPos = pos; + } + + pos++; + + } + + request.unparsedURI().setBytes(buf, start, end - start); + if (questionPos >= 0) { + request.queryString().setBytes(buf, questionPos + 1, + end - questionPos - 1); + request.requestURI().setBytes(buf, start, questionPos - start); + } else { + request.requestURI().setBytes(buf, start, end - start); + } + + // Mark the current buffer position + start = pos; + end = 0; + + // + // Reading the protocol + // Protocol is always US-ASCII + // + + while (!eol) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.CR) { + end = pos; + } else if (buf[pos] == Constants.LF) { + if (end == 0) + end = pos; + eol = true; + } + + pos++; + + } + + if ((end - start) > 0) { + request.protocol().setBytes(buf, start, end - start); + } else { + request.protocol().setString(""); + } + + return true; + + } + + + /** + * Parse the HTTP headers. + */ + public void parseHeaders() + throws IOException { + + while (parseHeader()) { + } + + parsingHeader = false; + end = pos; + } + + + /** + * Parse an HTTP header. + * + * @return false after reading a blank line (which indicates that the + * HTTP header parsing is done + */ + public boolean parseHeader() + throws IOException { + + // + // Check for blank line + // + + byte chr = 0; + while (true) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + chr = buf[pos]; + + if ((chr == Constants.CR) || (chr == Constants.LF)) { + if (chr == Constants.LF) { + pos++; + return false; + } + } else { + break; + } + + pos++; + + } + + // Mark the current buffer position + int start = pos; + + // + // Reading the header name + // Header name is always US-ASCII + // + + boolean colon = false; + MessageBytes headerValue = null; + + while (!colon) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.COLON) { + colon = true; + headerValue = headers.addValue(buf, start, pos - start); + } + chr = buf[pos]; + if ((chr >= Constants.A) && (chr <= Constants.Z)) { + buf[pos] = (byte) (chr - Constants.LC_OFFSET); + } + + pos++; + + } + + // Mark the current buffer position + start = pos; + int realPos = pos; + + // + // Reading the header value (which can be spanned over multiple lines) + // + + boolean eol = false; + boolean validLine = true; + + while (validLine) { + + boolean space = true; + + // Skipping spaces + while (space) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) { + pos++; + } else { + space = false; + } + + } + + int lastSignificantChar = realPos; + + // Reading bytes until the end of the line + while (!eol) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.CR) { + } else if (buf[pos] == Constants.LF) { + eol = true; + } else if (buf[pos] == Constants.SP) { + buf[realPos] = buf[pos]; + realPos++; + } else { + buf[realPos] = buf[pos]; + realPos++; + lastSignificantChar = realPos; + } + + pos++; + + } + + realPos = lastSignificantChar; + + // Checking the first character of the new line. If the character + // is a LWS, then it's a multiline header + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + chr = buf[pos]; + if ((chr != Constants.SP) && (chr != Constants.HT)) { + validLine = false; + } else { + eol = false; + // Copying one extra space in the buffer (since there must + // be at least one space inserted between the lines) + buf[realPos] = chr; + realPos++; + } + + } + + // Set the header value + headerValue.setBytes(buf, start, realPos - start); + + return true; + + } + + + /** + * Available bytes (note that due to encoding, this may not correspond ) + */ + public int available() { + int result = (lastValid - pos); + if ((result == 0) && (lastActiveFilter >= 0)) { + for (int i = 0; (result == 0) && (i <= lastActiveFilter); i++) { + result = activeFilters[i].available(); + } + } + return result; + } + + + // ---------------------------------------------------- InputBuffer Methods + + + /** + * Read some bytes. + */ + public int doRead(ByteChunk chunk, Request req) + throws IOException { + + if (lastActiveFilter == -1) + return inputStreamInputBuffer.doRead(chunk, req); + else + return activeFilters[lastActiveFilter].doRead(chunk,req); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Fill the internal buffer using data from the undelying input stream. + * + * @return false if at end of stream + */ + protected boolean fill() + throws IOException { + + int nRead = 0; + + if (parsingHeader) { + + if (lastValid == buf.length) { + throw new IOException + (sm.getString("iib.requestheadertoolarge.error")); + } + + bbuf.clear(); + nRead = Socket.recvbb(socket, 0, buf.length - lastValid); + if (nRead > 0) { + bbuf.limit(nRead); + bbuf.get(buf, pos, nRead); + lastValid = pos + nRead; + } else { + if ((-nRead) == Status.EAGAIN) { + return false; + } else { + throw new IOException(sm.getString("iib.failedread")); + } + } + + } else { + + if (buf.length - end < 4500) { + // In this case, the request header was really large, so we allocate a + // brand new one; the old one will get GCed when subsequent requests + // clear all references + buf = new byte[buf.length]; + end = 0; + } + pos = end; + lastValid = pos; + bbuf.clear(); + nRead = Socket.recvbb(socket, 0, buf.length - lastValid); + if (nRead > 0) { + bbuf.limit(nRead); + bbuf.get(buf, pos, nRead); + lastValid = pos + nRead; + } else { + if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) { + throw new SocketTimeoutException(sm.getString("iib.failedread")); + } else { + throw new IOException(sm.getString("iib.failedread")); + } + } + + } + + return (nRead > 0); + + } + + + // ------------------------------------- InputStreamInputBuffer Inner Class + + + /** + * This class is an input buffer which will read its data from an input + * stream. + */ + protected class SocketInputBuffer + implements InputBuffer { + + + /** + * Read bytes into the specified chunk. + */ + public int doRead(ByteChunk chunk, Request req ) + throws IOException { + + if (pos >= lastValid) { + if (!fill()) + return -1; + } + + int length = lastValid - pos; + chunk.setBytes(buf, pos, length); + pos = lastValid; + + return (length); + + } + + + } + + +}
Added: tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/coyote/http11/InternalAprOutputBuffer.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/coyote/http11/InternalAprOutputBuffer.java?rev=640860&view=auto ============================================================================== --- tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/coyote/http11/InternalAprOutputBuffer.java (added) +++ tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/coyote/http11/InternalAprOutputBuffer.java Tue Mar 25 08:26:26 2008 @@ -0,0 +1,739 @@ +/* + * 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.nio.ByteBuffer; + +import org.apache.tomcat.jni.Socket; +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; + +/** + * Output buffer. + * + * @author <a href="mailto:[EMAIL PROTECTED]">Remy Maucherat</a> + */ +public class InternalAprOutputBuffer + implements OutputBuffer { + + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor. + */ + public InternalAprOutputBuffer(Response response) { + this(response, Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE); + } + + + /** + * Alternate constructor. + */ + public InternalAprOutputBuffer(Response response, int headerBufferSize) { + + this.response = response; + headers = response.getMimeHeaders(); + + buf = new byte[headerBufferSize]; + if (headerBufferSize < (8 * 1024)) { + bbuf = ByteBuffer.allocateDirect(6 * 1500); + } else { + bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500); + } + + outputStreamOutputBuffer = new SocketOutputBuffer(); + + filterLibrary = new OutputFilter[0]; + activeFilters = new OutputFilter[0]; + lastActiveFilter = -1; + + committed = false; + finished = false; + + // Cause loading of HttpMessages + HttpMessages.getMessage(200); + + } + + + // -------------------------------------------------------------- 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; + + + /** + * 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; + + + // ------------------------------------------------------------- Properties + + + /** + * Set the underlying socket. + */ + public void setSocket(long socket) { + this.socket = socket; + Socket.setsbb(this.socket, bbuf); + } + + + /** + * Get the underlying socket input stream. + */ + public long getSocket() { + return socket; + } + + + /** + * Set the socket buffer size. + */ + public void setSocketBuffer(int socketBufferSize) { + // FIXME: Remove + } + + + /** + * 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 + + + /** + * 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); + + } + + // Flush the current buffer + flushBuffer(); + + } + + + /** + * 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 Request object + response.recycle(); + bbuf.clear(); + + socket = 0; + 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(); + + flushBuffer(); + + finished = true; + + } + + + // ------------------------------------------------ HTTP/1.1 Output Methods + + + /** + * Send an acknoledgement. + */ + public void sendAck() + throws IOException { + + if (!committed) { + if (Socket.send(socket, Constants.ACK_BYTES, 0, Constants.ACK_BYTES.length) < 0) + throw new IOException(sm.getString("iib.failedwrite")); + } + + } + + + /** + * 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 = response.getMessage(); + if (message == null) { + write(HttpMessages.getMessage(status)); + } else { + write(message); + } + + // 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 + + + /** + * Commit the response. + * + * @throws IOException an undelying I/O error occured + */ + protected void commit() + throws IOException { + + // The response is now committed + committed = true; + response.setCommitted(true); + + if (pos > 0) { + // Sending the response header buffer + bbuf.put(buf, 0, pos); + } + + } + + + /** + * 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() + throws IOException { + if (bbuf.position() > 0) { + if (Socket.sendbb(socket, 0, bbuf.position()) < 0) { + throw new IOException(); + } + bbuf.clear(); + } + } + + + // ----------------------------------- 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 chunk, Response res) + throws IOException { + + int len = chunk.getLength(); + int start = chunk.getStart(); + byte[] b = chunk.getBuffer(); + while (len > 0) { + int thisTime = len; + if (bbuf.position() == bbuf.capacity()) { + flushBuffer(); + } + if (thisTime > bbuf.capacity() - bbuf.position()) { + thisTime = bbuf.capacity() - bbuf.position(); + } + bbuf.put(b, start, thisTime); + len = len - thisTime; + start = start + thisTime; + } + return chunk.getLength(); + + } + + + } + + +} Added: tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/Apr.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/Apr.java?rev=640860&view=auto ============================================================================== --- tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/Apr.java (added) +++ tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/Apr.java Tue Mar 25 08:26:26 2008 @@ -0,0 +1,41 @@ +/* + * 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.tomcat; + +import java.io.InputStream; +import java.util.Properties; + +public class Apr { + private static String aprInfo = null; + + static { + + try { + InputStream is = Apr.class.getResourceAsStream + ("/org/apache/tomcat/apr.properties"); + Properties props = new Properties(); + props.load(is); + is.close(); + aprInfo = props.getProperty("tcn.info"); + } + catch (Throwable t) { + ; // Nothing + } + } +} Added: tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/apr.properties URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/apr.properties?rev=640860&view=auto ============================================================================== --- tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/apr.properties (added) +++ tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/apr.properties Tue Mar 25 08:26:26 2008 @@ -0,0 +1,16 @@ +# 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. + +tcn.info=Tomcat Native/@VERSION@ Added: tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/Address.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/Address.java?rev=640860&view=auto ============================================================================== --- tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/Address.java (added) +++ tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/Address.java Tue Mar 25 08:26:26 2008 @@ -0,0 +1,114 @@ +/* + * 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.tomcat.jni; + +/** Address + * + * @author Mladen Turk + * @version $Revision: 467222 $, $Date: 2006-10-23 20:17:11 -0700 (Mon, 23 Oct 2006) $ + */ + +public class Address { + + static public String APR_ANYADDR = "0.0.0.0"; + /** + * Fill the Sockaddr class from apr_sockaddr_t + * @param info Sockaddr class to fill + * @param sa Structure pointer + */ + public static native boolean fill(Sockaddr info, long sa); + + /** + * Create the Sockaddr object from apr_sockaddr_t + * @param sa Structure pointer + */ + public static native Sockaddr getInfo(long sa); + + /** + * Create apr_sockaddr_t from hostname, address family, and port. + * @param hostname The hostname or numeric address string to resolve/parse, or + * NULL to build an address that corresponds to 0.0.0.0 or :: + * @param family The address family to use, or APR_UNSPEC if the system should + * decide. + * @param port The port number. + * @param flags Special processing flags: + * <PRE> + * APR_IPV4_ADDR_OK first query for IPv4 addresses; only look + * for IPv6 addresses if the first query failed; + * only valid if family is APR_UNSPEC and hostname + * isn't NULL; mutually exclusive with + * APR_IPV6_ADDR_OK + * APR_IPV6_ADDR_OK first query for IPv6 addresses; only look + * for IPv4 addresses if the first query failed; + * only valid if family is APR_UNSPEC and hostname + * isn't NULL and APR_HAVE_IPV6; mutually exclusive + * with APR_IPV4_ADDR_OK + * </PRE> + * @param p The pool for the apr_sockaddr_t and associated storage. + * @return The new apr_sockaddr_t. + */ + public static native long info(String hostname, int family, + int port, int flags, long p) + throws Exception; + /** + * Look up the host name from an apr_sockaddr_t. + * @param sa The apr_sockaddr_t. + * @param flags Special processing flags. + * @return The hostname. + */ + public static native String getnameinfo(long sa, int flags); + + /** + * Return the IP address (in numeric address string format) in + * an APR socket address. APR will allocate storage for the IP address + * string from the pool of the apr_sockaddr_t. + * @param sa The socket address to reference. + * @return The IP address. + */ + public static native String getip(long sa); + + /** + * Given an apr_sockaddr_t and a service name, set the port for the service + * @param sockaddr The apr_sockaddr_t that will have its port set + * @param servname The name of the service you wish to use + * @return APR status code. + */ + public static native int getservbyname(long sockaddr, String servname); + + /** + * Return an apr_sockaddr_t from an apr_socket_t + * @param which Which interface do we want the apr_sockaddr_t for? + * @param sock The socket to use + * @return The returned apr_sockaddr_t. + */ + public static native long get(int which, long sock) + throws Exception; + + /** + * See if the IP addresses in two APR socket addresses are + * equivalent. Appropriate logic is present for comparing + * IPv4-mapped IPv6 addresses with IPv4 addresses. + * + * @param a One of the APR socket addresses. + * @param b The other APR socket address. + * The return value will be True if the addresses + * are equivalent. + */ + public static native boolean equal(long a, long b); + +} Added: tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/BIOCallback.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/BIOCallback.java?rev=640860&view=auto ============================================================================== --- tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/BIOCallback.java (added) +++ tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/BIOCallback.java Tue Mar 25 08:26:26 2008 @@ -0,0 +1,56 @@ +/* + * 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.tomcat.jni; + +/** Open SSL BIO Callback Interface + * + * @author Mladen Turk + * @version $Revision: 467222 $, $Date: 2006-10-23 20:17:11 -0700 (Mon, 23 Oct 2006) $ + */ + +public interface BIOCallback { + + /** + * Write data + * @param buf containg the bytes to write. + * @return Number of characters written. + */ + public int write(byte [] buf); + + /** + * Read data + * @param buf buffer to store the read bytes. + * @return number of bytes read. + */ + public int read(byte [] buf); + + /** + * Puts string + * @param data String to write + * @return Number of characters written + */ + public int puts(String data); + + /** + * Read string up to the len or CLRLF + * @param len Maximum number of characters to read + * @return String with up to len bytes readed + */ + public String gets(int len); + +} Added: tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/Directory.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/Directory.java?rev=640860&view=auto ============================================================================== --- tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/Directory.java (added) +++ tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/Directory.java Tue Mar 25 08:26:26 2008 @@ -0,0 +1,97 @@ +/* + * 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.tomcat.jni; + +/** Directory + * + * @author Mladen Turk + * @version $Revision: 467222 $, $Date: 2006-10-23 20:17:11 -0700 (Mon, 23 Oct 2006) $ + */ + +public class Directory { + + /** + * Create a new directory on the file system. + * @param path the path for the directory to be created. (use / on all systems) + * @param perm Permissions for the new direcoty. + * @param pool the pool to use. + */ + public static native int make(String path, int perm, long pool); + + /** Creates a new directory on the file system, but behaves like + * 'mkdir -p'. Creates intermediate directories as required. No error + * will be reported if PATH already exists. + * @param path the path for the directory to be created. (use / on all systems) + * @param perm Permissions for the new direcoty. + * @param pool the pool to use. + */ + public static native int makeRecursive(String path, int perm, long pool); + + /** + * Remove directory from the file system. + * @param path the path for the directory to be removed. (use / on all systems) + * @param pool the pool to use. + */ + public static native int remove(String path, long pool); + + /** + * Find an existing directory suitable as a temporary storage location. + * @param pool The pool to use for any necessary allocations. + * @return The temp directory. + * + * This function uses an algorithm to search for a directory that an + * an application can use for temporary storage. Once such a + * directory is found, that location is cached by the library. Thus, + * callers only pay the cost of this algorithm once if that one time + * is successful. + * + */ + public static native String tempGet(long pool); + + /** + * Open the specified directory. + * @param dirname The full path to the directory (use / on all systems) + * @param pool The pool to use. + * @return The opened directory descriptor. + */ + public static native long open(String dirname, long pool) + throws Error; + + /** + * close the specified directory. + * @param thedir the directory descriptor to close. + */ + public static native int close(long thedir); + + /** + * Rewind the directory to the first entry. + * @param thedir the directory descriptor to rewind. + */ + public static native int rewind(long thedir); + + + /** + * Read the next entry from the specified directory. + * @param finfo the file info structure and filled in by apr_dir_read + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values + * @param thedir the directory descriptor returned from apr_dir_open + * No ordering is guaranteed for the entries read. + */ + public static native int read(FileInfo finfo, int wanted, long thedir); + +} Added: tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/Error.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/Error.java?rev=640860&view=auto ============================================================================== --- tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/Error.java (added) +++ tomcat/sandbox/tomcat-lite/coyote-apr/org/apache/tomcat/jni/Error.java Tue Mar 25 08:26:26 2008 @@ -0,0 +1,96 @@ +/* + * 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.tomcat.jni; + +/** Error + * + * @author Mladen Turk + * @version $Revision: 467222 $, $Date: 2006-10-23 20:17:11 -0700 (Mon, 23 Oct 2006) $ + */ + +public class Error extends Exception { + + /** + * APR error type. + */ + private int error; + + /** + * A description of the problem. + */ + private String description; + + /** + * Construct an APRException. + * + * @param error one of the value in Error + * @param description error message + */ + private Error(int error, String description) + { + super(description); + this.error = error; + this.description = description; + } + + /** + * Get the APR error code of the exception. + * + * @return error of the Exception + */ + public int getError() + { + return error; + } + + /** + * Get the APR description of the exception. + * + * @return description of the Exception + */ + public String getDescription() + { + return description; + } + + /** + * Get the last platform error. + * @return apr_status_t the last platform error, folded into apr_status_t, on most platforms + * This retrieves errno, or calls a GetLastError() style function, and + * folds it with APR_FROM_OS_ERROR. Some platforms (such as OS2) have no + * such mechanism, so this call may be unsupported. Do NOT use this + * call for socket errors from socket, send, recv etc! + */ + public static native int osError(); + + /** + * Get the last platform socket error. + * @return the last socket error, folded into apr_status_t, on all platforms + * This retrieves errno or calls a GetLastSocketError() style function, + * and folds it with APR_FROM_OS_ERROR. + */ + public static native int netosError(); + + /** + * Return a human readable string describing the specified error. + * @param statcode The error code the get a string for. + * @return The error string. + */ + public static native String strerror(int statcode); + +} --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]