Author: costin
Date: Tue Mar 25 08:17:03 2008
New Revision: 640852
URL: http://svn.apache.org/viewvc?rev=640852&view=rev
Log:
A bunch of files to make it easier to load-test, profile, debug coyote.
It can also be used to run simple servers with the maximum speed available - no
tomcat or servlet engine overhead.
To be useful, a couple of extensions to MessageBytes are needed - to make it
easier to
use.
Some of this is from an old experiment, removed than added back.
Added:
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/ClientAbortException.java
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/CoyoteServer.java
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/EchoAdapter.java
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MapperAdapter.java
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MessageReader.java
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MessageWriter.java
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/SimpleFileAdapter.java
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/StaticAdapter.java
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/StaticMain.java
Added:
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/ClientAbortException.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/ClientAbortException.java?rev=640852&view=auto
==============================================================================
---
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/ClientAbortException.java
(added)
+++
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/ClientAbortException.java
Tue Mar 25 08:17:03 2008
@@ -0,0 +1,144 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.adapters;
+
+import java.io.IOException;
+
+/**
+ * Wrap an IOException identifying it as being caused by an abort
+ * of a request by a remote client.
+ *
+ * @author Glenn L. Nielsen
+ * @version $Revision: 304063 $ $Date: 2005-08-18 06:25:18 -0700 (Thu, 18 Aug
2005) $
+ */
+
+public final class ClientAbortException extends IOException {
+
+
+ //------------------------------------------------------------ Constructors
+
+
+ /**
+ * Construct a new ClientAbortException with no other information.
+ */
+ public ClientAbortException() {
+
+ this(null, null);
+
+ }
+
+
+ /**
+ * Construct a new ClientAbortException for the specified message.
+ *
+ * @param message Message describing this exception
+ */
+ public ClientAbortException(String message) {
+
+ this(message, null);
+
+ }
+
+
+ /**
+ * Construct a new ClientAbortException for the specified throwable.
+ *
+ * @param throwable Throwable that caused this exception
+ */
+ public ClientAbortException(Throwable throwable) {
+
+ this(null, throwable);
+
+ }
+
+
+ /**
+ * Construct a new ClientAbortException for the specified message
+ * and throwable.
+ *
+ * @param message Message describing this exception
+ * @param throwable Throwable that caused this exception
+ */
+ public ClientAbortException(String message, Throwable throwable) {
+
+ super();
+ this.message = message;
+ this.throwable = throwable;
+
+ }
+
+
+ //------------------------------------------------------ Instance Variables
+
+
+ /**
+ * The error message passed to our constructor (if any)
+ */
+ protected String message = null;
+
+
+ /**
+ * The underlying exception or error passed to our constructor (if any)
+ */
+ protected Throwable throwable = null;
+
+
+ //---------------------------------------------------------- Public Methods
+
+
+ /**
+ * Returns the message associated with this exception, if any.
+ */
+ public String getMessage() {
+
+ return (message);
+
+ }
+
+
+ /**
+ * Returns the cause that caused this exception, if any.
+ */
+ public Throwable getCause() {
+
+ return (throwable);
+
+ }
+
+
+ /**
+ * Return a formatted string that describes this exception.
+ */
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("ClientAbortException: ");
+ if (message != null) {
+ sb.append(message);
+ if (throwable != null) {
+ sb.append(": ");
+ }
+ }
+ if (throwable != null) {
+ sb.append(throwable.toString());
+ }
+ return (sb.toString());
+
+ }
+
+
+}
Added:
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/CoyoteServer.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/CoyoteServer.java?rev=640852&view=auto
==============================================================================
---
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/CoyoteServer.java
(added)
+++
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/CoyoteServer.java
Tue Mar 25 08:17:03 2008
@@ -0,0 +1,136 @@
+package org.apache.coyote.adapters;
+
+import java.lang.management.ManagementFactory;
+
+import org.apache.coyote.Adapter;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.coyote.http11.Http11NioProtocol;
+import org.apache.juli.JdkLoggerConfig;
+import org.apache.tomcat.util.modeler.Registry;
+
+
+/**
+ * Simple example of embeding coyote servlet.
+ *
+ */
+public class CoyoteServer {
+ int port = 8800;
+ String args[];
+
+ protected ProtocolHandler proto;
+
+ Registry registry;
+
+ protected Adapter adapter;
+ int maxThreads = 20;
+
+ public CoyoteServer() {
+ }
+
+ public CoyoteServer(int i) {
+ port = i;
+ }
+
+ public CoyoteServer(int i, Adapter adapter) {
+ port = i;
+ addAdapter("/", adapter);
+ }
+
+ public void setArgs(String[] args) {
+ this.args = args;
+ }
+
+ /**
+ * Add an adapter. If more than the 'default' adapter is
+ * added, a MapperAdapter will be inserted.
+ *
+ * @param path Use "/" for the default.
+ * @param adapter
+ */
+ public void addAdapter(String path, Adapter added) {
+ if (adapter == null && "/".equals(path)) {
+ adapter = added;
+ } else {
+ if (!(adapter instanceof MapperAdapter)) {
+ Adapter oldDefault = adapter;
+ adapter = new MapperAdapter();
+ ((MapperAdapter) adapter).setDefaultAdapter(oldDefault);
+ }
+ ((MapperAdapter) adapter).getMapper().addWrapper(path, added);
+ }
+ }
+
+ /**
+ */
+ public void run() {
+ init();
+ start();
+ }
+
+ public void init() {
+ new JdkLoggerConfig();
+ initJMX();
+ }
+
+ protected void initAdapters() {
+ // adapter = ...
+ // Adapter secondaryadapter = ...
+ //registry.registerComponent(secondaryadapter, ":name=adapter", null);
+ }
+
+ public void stop() throws Exception {
+ proto.destroy();
+ }
+
+ /**
+ * Simple CLI support - arg is a path:className pair.
+ */
+ public void setAdapter(String arg) {
+ String[] pathClass = arg.split(":", 2);
+ try {
+ Class c = Class.forName(pathClass[1]);
+ Adapter a = (Adapter) c.newInstance();
+ addAdapter(pathClass[0],a);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void setPort() {
+ this.port = port;
+ }
+
+ /**
+ */
+ public static ProtocolHandler getDefaultConnector(int port) {
+ Http11NioProtocol proto = new Http11NioProtocol();
+ proto.setCompression("on");
+ proto.setCompressionMinSize(32);
+ proto.setPort(port);
+ proto.getEndpoint().setDaemon(false);
+ return proto;
+ }
+
+ public void start() {
+ try {
+ proto = getDefaultConnector(port);
+ initAdapters();
+ registry.registerComponent(adapter, ":name=adapter" + (port), null);
+
+ proto.setAdapter(adapter);
+
+ registry.registerComponent(proto, ":name=ep-" + port, null);
+ proto.start();
+ proto.init();
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void initJMX() {
+ ManagementFactory.getPlatformMBeanServer();
+ registry = Registry.getRegistry(null, null);
+
+ }
+
+}
\ No newline at end of file
Added:
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/EchoAdapter.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/EchoAdapter.java?rev=640852&view=auto
==============================================================================
---
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/EchoAdapter.java
(added)
+++
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/EchoAdapter.java
Tue Mar 25 08:17:03 2008
@@ -0,0 +1,42 @@
+package org.apache.coyote.adapters;
+
+import java.util.logging.Logger;
+
+import org.apache.coyote.Adapter;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.http.HttpProcessor;
+import org.apache.tomcat.util.net.SocketStatus;
+
+/**
+ * Response is plain/text, copy of the received request
+ */
+public class EchoAdapter implements Adapter {
+ Logger log = Logger.getLogger("coyote.static");
+
+ String contentType = "text/plain";
+
+
+ public EchoAdapter() {
+ }
+
+ public void service(Request req, final Response res) throws Exception {
+ ByteChunk reqBuf = new ByteChunk(1024);
+ HttpProcessor.serializeRequest(req, reqBuf);
+
+ res.setStatus(200);
+ res.setContentLength(reqBuf.getLength());
+ res.setContentType(contentType);
+
+ res.sendHeaders();
+
+ res.doWrite(reqBuf);
+ }
+
+ public boolean event(Request req, Response res, SocketStatus status)
+ throws Exception {
+ return false;
+ }
+
+}
\ No newline at end of file
Added:
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MapperAdapter.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MapperAdapter.java?rev=640852&view=auto
==============================================================================
---
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MapperAdapter.java
(added)
+++
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MapperAdapter.java
Tue Mar 25 08:17:03 2008
@@ -0,0 +1,214 @@
+package org.apache.coyote.adapters;
+
+import java.io.IOException;
+
+import org.apache.coyote.Adapter;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.mapper.Mapper;
+import org.apache.tomcat.util.http.mapper.MappingData;
+import org.apache.tomcat.util.net.SocketStatus;
+
+/**
+ *
+ */
+public class MapperAdapter implements Adapter {
+
+ private Mapper mapper=new Mapper();
+
+ public MapperAdapter() {
+ mapper = new Mapper();
+ mapper.setDefaultHostName("localhost");
+ mapper.setContext("", new String[] {"index.html"},
+ null);
+ }
+
+ public MapperAdapter(Mapper mapper2) {
+ mapper = mapper2;
+ }
+
+ public static void decodeRequest(Request reqB) throws IOException {
+ MessageBytes decodedURI = reqB.decodedURI();
+ decodedURI.duplicate(reqB.requestURI());
+
+ if (decodedURI.getType() == MessageBytes.T_BYTES) {
+ // %xx decoding of the URL
+ reqB.getURLDecoder().convert(decodedURI, false);
+ // Normalization
+ if (!normalize(decodedURI)) {
+ throw new IOException("Error normalizing");
+ }
+ // Character decoding
+ //convertURI(decodedURI, request);
+ } else {
+ // The URL is chars or String, and has been sent using an in-memory
+ // protocol handler, we have to assume the URL has been properly
+ // decoded already
+ decodedURI.toChars();
+ }
+ }
+
+ /**
+ * Normalize URI.
+ * <p>
+ * This method normalizes "\", "//", "/./" and "/../". This method will
+ * return false when trying to go above the root, or if the URI contains
+ * a null byte.
+ *
+ * @param uriMB URI to be normalized
+ */
+ public static boolean normalize(MessageBytes uriMB) {
+
+ ByteChunk uriBC = uriMB.getByteChunk();
+ byte[] b = uriBC.getBytes();
+ int start = uriBC.getStart();
+ int end = uriBC.getEnd();
+
+ // URL * is acceptable
+ if ((end - start == 1) && b[start] == (byte) '*')
+ return true;
+
+ int pos = 0;
+ int index = 0;
+
+ // Replace '\' with '/'
+ // Check for null byte
+ for (pos = start; pos < end; pos++) {
+ if (b[pos] == (byte) '\\')
+ b[pos] = (byte) '/';
+ if (b[pos] == (byte) 0)
+ return false;
+ }
+
+ // The URL must start with '/'
+ if (b[start] != (byte) '/') {
+ return false;
+ }
+
+ // Replace "//" with "/"
+ for (pos = start; pos < (end - 1); pos++) {
+ if (b[pos] == (byte) '/') {
+ while ((pos + 1 < end) && (b[pos + 1] == (byte) '/')) {
+ copyBytes(b, pos, pos + 1, end - pos - 1);
+ end--;
+ }
+ }
+ }
+
+ // If the URI ends with "/." or "/..", then we append an extra "/"
+ // Note: It is possible to extend the URI by 1 without any side effect
+ // as the next character is a non-significant WS.
+ if (((end - start) >= 2) && (b[end - 1] == (byte) '.')) {
+ if ((b[end - 2] == (byte) '/')
+ || ((b[end - 2] == (byte) '.')
+ && (b[end - 3] == (byte) '/'))) {
+ b[end] = (byte) '/';
+ end++;
+ }
+ }
+
+ uriBC.setEnd(end);
+
+ index = 0;
+
+ // Resolve occurrences of "/./" in the normalized path
+ while (true) {
+ index = uriBC.indexOf("/./", 0, 3, index);
+ if (index < 0)
+ break;
+ copyBytes(b, start + index, start + index + 2,
+ end - start - index - 2);
+ end = end - 2;
+ uriBC.setEnd(end);
+ }
+
+ index = 0;
+
+ // Resolve occurrences of "/../" in the normalized path
+ while (true) {
+ index = uriBC.indexOf("/../", 0, 4, index);
+ if (index < 0)
+ break;
+ // Prevent from going outside our context
+ if (index == 0)
+ return false;
+ int index2 = -1;
+ for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos --) {
+ if (b[pos] == (byte) '/') {
+ index2 = pos;
+ }
+ }
+ copyBytes(b, start + index2, start + index + 3,
+ end - start - index - 3);
+ end = end + index2 - index - 3;
+ uriBC.setEnd(end);
+ index = index2;
+ }
+
+ //uriBC.setBytes(b, start, end);
+ uriBC.setEnd(end);
+ return true;
+
+ }
+
+ /**
+ * Copy an array of bytes to a different position. Used during
+ * normalization.
+ */
+ public static void copyBytes(byte[] b, int dest, int src, int len) {
+ for (int pos = 0; pos < len; pos++) {
+ b[pos + dest] = b[pos + src];
+ }
+ }
+
+
+ public void service(Request req, final Response res)
+ throws Exception {
+ try {
+ // compute decodedURI - not done by connector
+ decodeRequest(req);
+ MappingData mapRes = new MappingData();
+
+ mapper.map(req.requestURI(), mapRes);
+
+ Adapter h=(Adapter)mapRes.wrapper;
+ if (h != null) {
+ h.service( req, res );
+ } else {
+ res.setStatus(404);
+ }
+
+ } catch( Throwable t ) {
+ t.printStackTrace();
+ }
+
+ // Final processing
+ MessageWriter.getWriter(req, res, 0).flush();
+ res.finish();
+
+ req.recycle();
+ res.recycle();
+
+ }
+
+ public Mapper getMapper() {
+ return mapper;
+ }
+
+ public void setDefaultAdapter(Adapter adapter) {
+ mapper.addWrapper("/", adapter);
+ }
+
+ public boolean event(Request req, Response res, boolean error) throws
Exception {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean event(Request req, Response res, SocketStatus status)
+ throws Exception {
+ return false;
+ }
+
+}
\ No newline at end of file
Added:
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MessageReader.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MessageReader.java?rev=640852&view=auto
==============================================================================
---
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MessageReader.java
(added)
+++
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MessageReader.java
Tue Mar 25 08:17:03 2008
@@ -0,0 +1,503 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.adapters;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+
+import org.apache.coyote.Request;
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+
+/**
+ * Refactored from catalina.connector.InputBuffer. Renamed to avoid conflict
+ * with coyote class.
+ *
+ * TODO: move to coyote package.
+ */
+
+/**
+ * The buffer used by Tomcat request. This is a derivative of the Tomcat 3.3
+ * OutputBuffer, adapted to handle input instead of output. This allows
+ * complete recycling of the facade objects (the ServletInputStream and the
+ * BufferedReader).
+ *
+ * @author Remy Maucherat
+ */
+public class MessageReader extends Reader
+ implements ByteChunk.ByteInputChannel, CharChunk.CharInputChannel,
+ CharChunk.CharOutputChannel {
+
+
+ // -------------------------------------------------------------- Constants
+
+
+ public static final String DEFAULT_ENCODING =
+ org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
+ public static final int DEFAULT_BUFFER_SIZE = 8*1024;
+
+ // The buffer can be used for byte[] and char[] reading
+ // ( this is needed to support ServletInputStream and BufferedReader )
+ public final int INITIAL_STATE = 0;
+ public final int CHAR_STATE = 1;
+ public final int BYTE_STATE = 2;
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ /**
+ * The byte buffer.
+ */
+ private ByteChunk bb;
+
+
+ /**
+ * The chunk buffer.
+ */
+ private CharChunk cb;
+
+
+ /**
+ * State of the output buffer.
+ */
+ private int state = 0;
+
+
+ /**
+ * Number of bytes read.
+ */
+ private int bytesRead = 0;
+
+
+ /**
+ * Number of chars read.
+ */
+ private int charsRead = 0;
+
+
+ /**
+ * Flag which indicates if the input buffer is closed.
+ */
+ private boolean closed = false;
+
+
+ /**
+ * Byte chunk used to input bytes.
+ */
+ private ByteChunk inputChunk = new ByteChunk();
+
+
+ /**
+ * Encoding to use.
+ */
+ private String enc;
+
+
+ /**
+ * Encoder is set.
+ */
+ private boolean gotEnc = false;
+
+
+ /**
+ * List of encoders.
+ */
+ protected HashMap encoders = new HashMap();
+
+
+ /**
+ * Current byte to char converter.
+ */
+ protected B2CConverter conv;
+
+
+ /**
+ * Associated Coyote request.
+ */
+ private Request coyoteRequest;
+
+
+ /**
+ * Buffer position.
+ */
+ private int markPos = -1;
+
+
+ /**
+ * Buffer size.
+ */
+ private int size = -1;
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Default constructor. Allocate the buffer with the default buffer size.
+ */
+ public MessageReader() {
+
+ this(DEFAULT_BUFFER_SIZE);
+
+ }
+
+
+ /**
+ * Alternate constructor which allows specifying the initial buffer size.
+ *
+ * @param size Buffer size to use
+ */
+ public MessageReader(int size) {
+
+ this.size = size;
+ bb = new ByteChunk(size);
+ bb.setLimit(size);
+ bb.setByteInputChannel(this);
+ cb = new CharChunk(size);
+ cb.setLimit(size);
+ cb.setOptimizedWrite(false);
+ cb.setCharInputChannel(this);
+ cb.setCharOutputChannel(this);
+
+ }
+
+
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * Associated Coyote request.
+ *
+ * @param coyoteRequest Associated Coyote request
+ */
+ public void setRequest(Request coyoteRequest) {
+ this.coyoteRequest = coyoteRequest;
+ }
+
+
+ /**
+ * Get associated Coyote request.
+ *
+ * @return the associated Coyote request
+ */
+ public Request getRequest() {
+ return this.coyoteRequest;
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Recycle the output buffer.
+ */
+ public void recycle() {
+
+ state = INITIAL_STATE;
+ bytesRead = 0;
+ charsRead = 0;
+
+ // If usage of mark made the buffer too big, reallocate it
+ if (cb.getChars().length > size) {
+ cb = new CharChunk(size);
+ cb.setLimit(size);
+ cb.setCharInputChannel(this);
+ cb.setCharOutputChannel(this);
+ } else {
+ cb.recycle();
+ }
+ markPos = -1;
+ bb.recycle();
+ closed = false;
+
+ if (conv != null) {
+ conv.recycle();
+ }
+
+ gotEnc = false;
+ enc = null;
+
+ }
+
+
+ /**
+ * Close the input buffer.
+ *
+ * @throws IOException An underlying IOException occurred
+ */
+ public void close()
+ throws IOException {
+ closed = true;
+ }
+
+
+ public int available()
+ throws IOException {
+ if (state == BYTE_STATE) {
+ return bb.getLength();
+ } else if (state == CHAR_STATE) {
+ return cb.getLength();
+ } else {
+ return 0;
+ }
+ }
+
+
+ // ------------------------------------------------- Bytes Handling Methods
+
+
+ /**
+ * Reads new bytes in the byte chunk.
+ *
+ * @param cbuf Byte buffer to be written to the response
+ * @param off Offset
+ * @param len Length
+ *
+ * @throws IOException An underlying IOException occurred
+ */
+ public int realReadBytes(byte cbuf[], int off, int len)
+ throws IOException {
+
+ if (closed)
+ return -1;
+ if (coyoteRequest == null)
+ return -1;
+
+ state = BYTE_STATE;
+
+ int result = coyoteRequest.doRead(bb);
+
+ return result;
+
+ }
+
+
+ public int readByte()
+ throws IOException {
+ return bb.substract();
+ }
+
+
+ public int read(byte[] b, int off, int len)
+ throws IOException {
+ return bb.substract(b, off, len);
+ }
+
+
+ // ------------------------------------------------- Chars Handling Methods
+
+
+ /**
+ * Since the converter will use append, it is possible to get chars to
+ * be removed from the buffer for "writing". Since the chars have already
+ * been read before, they are ignored. If a mark was set, then the
+ * mark is lost.
+ */
+ public void realWriteChars(char c[], int off, int len)
+ throws IOException {
+ markPos = -1;
+ }
+
+
+ public void setEncoding(String s) {
+ enc = s;
+ }
+
+
+ public int realReadChars(char cbuf[], int off, int len)
+ throws IOException {
+
+ if (!gotEnc)
+ setConverter();
+
+ if (bb.getLength() <= 0) {
+ int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length);
+ if (nRead < 0) {
+ return -1;
+ }
+ }
+
+ if (markPos == -1) {
+ cb.setOffset(0);
+ cb.setEnd(0);
+ }
+
+ conv.convert(bb, cb);
+ bb.setOffset(bb.getEnd());
+ state = CHAR_STATE;
+
+ return cb.getLength();
+
+ }
+
+
+ public int read()
+ throws IOException {
+ return cb.substract();
+ }
+
+
+ public int read(char[] cbuf)
+ throws IOException {
+ return read(cbuf, 0, cbuf.length);
+ }
+
+
+ public int read(char[] cbuf, int off, int len)
+ throws IOException {
+ return cb.substract(cbuf, off, len);
+ }
+
+
+ public long skip(long n)
+ throws IOException {
+
+ if (n < 0) {
+ throw new IllegalArgumentException();
+ }
+
+ long nRead = 0;
+ while (nRead < n) {
+ if (cb.getLength() >= n) {
+ cb.setOffset(cb.getStart() + (int) n);
+ nRead = n;
+ } else {
+ nRead += cb.getLength();
+ cb.setOffset(cb.getEnd());
+ int toRead = 0;
+ if (cb.getChars().length < (n - nRead)) {
+ toRead = cb.getChars().length;
+ } else {
+ toRead = (int) (n - nRead);
+ }
+ int nb = realReadChars(cb.getChars(), 0, toRead);
+ if (nb < 0)
+ break;
+ }
+ }
+
+ return nRead;
+
+ }
+
+
+ public boolean ready()
+ throws IOException {
+ return (cb.getLength() > 0);
+ }
+
+
+ public boolean markSupported() {
+ return true;
+ }
+
+
+ public void mark(int readAheadLimit)
+ throws IOException {
+ if (cb.getLength() <= 0) {
+ cb.setOffset(0);
+ cb.setEnd(0);
+ } else {
+ if ((cb.getBuffer().length > (2 * size))
+ && (cb.getLength()) < (cb.getStart())) {
+ System.arraycopy(cb.getBuffer(), cb.getStart(),
+ cb.getBuffer(), 0, cb.getLength());
+ cb.setEnd(cb.getLength());
+ cb.setOffset(0);
+ }
+ }
+ int offset = readAheadLimit;
+ if (offset < size) {
+ offset = size;
+ }
+ cb.setLimit(cb.getStart() + offset);
+ markPos = cb.getStart();
+ }
+
+
+ public void reset()
+ throws IOException {
+ if (state == CHAR_STATE) {
+ if (markPos < 0) {
+ cb.recycle();
+ markPos = -1;
+ throw new IOException();
+ } else {
+ cb.setOffset(markPos);
+ }
+ } else {
+ bb.recycle();
+ }
+ }
+
+
+ public void checkConverter()
+ throws IOException {
+
+ if (!gotEnc)
+ setConverter();
+
+ }
+
+
+ protected void setConverter()
+ throws IOException {
+
+ if (coyoteRequest != null)
+ enc = coyoteRequest.getCharacterEncoding();
+
+ gotEnc = true;
+ if (enc == null)
+ enc = DEFAULT_ENCODING;
+ conv = (B2CConverter) encoders.get(enc);
+ if (conv == null) {
+ if (packageDefinitionEnabled && System.getSecurityManager() !=
null) {
+ //SecurityUtil.isPackageProtectionEnabled()){
+ try{
+ conv = (B2CConverter)AccessController.doPrivileged(
+ new PrivilegedExceptionAction(){
+
+ public Object run() throws IOException{
+ return new B2CConverter(enc);
+ }
+
+ }
+ );
+ }catch(PrivilegedActionException ex){
+ Exception e = ex.getException();
+ if (e instanceof IOException)
+ throw (IOException)e;
+ }
+ } else {
+ conv = new B2CConverter(enc);
+ }
+ encoders.put(enc, conv);
+ }
+
+ }
+
+ private static boolean packageDefinitionEnabled =
+ (System.getProperty("package.definition") == null &&
+ System.getProperty("package.access") == null) ? false : true;
+
+}
Added:
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MessageWriter.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MessageWriter.java?rev=640852&view=auto
==============================================================================
---
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MessageWriter.java
(added)
+++
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/MessageWriter.java
Tue Mar 25 08:17:03 2008
@@ -0,0 +1,680 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.adapters;
+
+
+import java.io.IOException;
+import java.io.Writer;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.C2BConverter;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/*
+ * Refactoring: original code in catalina.connector.
+ * - renamed to OutputWriter to avoid confusion with coyote OutputBuffer
+ * -
+ * TODO: move it to coyote, add Response.getWriter
+ *
+ */
+
+/**
+ * The buffer used by Tomcat response. This is a derivative of the Tomcat 3.3
+ * OutputBuffer, with the removal of some of the state handling (which in
+ * Coyote is mostly the Processor's responsability).
+ *
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ */
+public class MessageWriter extends Writer
+ implements ByteChunk.ByteOutputChannel, CharChunk.CharOutputChannel {
+
+ // used in getWriter, until a method is added to res.
+ private static final int WRITER_NOTE = 3;
+
+ // -------------------------------------------------------------- Constants
+
+
+ public static final String DEFAULT_ENCODING =
+ org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
+ public static final int DEFAULT_BUFFER_SIZE = 8*1024;
+
+
+ // The buffer can be used for byte[] and char[] writing
+ // ( this is needed to support ServletOutputStream and for
+ // efficient implementations of templating systems )
+ public final int INITIAL_STATE = 0;
+ public final int CHAR_STATE = 1;
+ public final int BYTE_STATE = 2;
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ /**
+ * The byte buffer.
+ */
+ private ByteChunk bb;
+
+
+ /**
+ * The chunk buffer.
+ */
+ private CharChunk cb;
+
+
+ /**
+ * State of the output buffer.
+ */
+ private int state = 0;
+
+
+ /**
+ * Number of bytes written.
+ */
+ private int bytesWritten = 0;
+
+
+ /**
+ * Number of chars written.
+ */
+ private int charsWritten = 0;
+
+
+ /**
+ * Flag which indicates if the output buffer is closed.
+ */
+ private boolean closed = false;
+
+
+ /**
+ * Do a flush on the next operation.
+ */
+ private boolean doFlush = false;
+
+
+ /**
+ * Byte chunk used to output bytes. This is just used to wrap the byte[]
+ * to match the coyote OutputBuffer interface
+ */
+ private ByteChunk outputChunk = new ByteChunk();
+
+
+ /**
+ * Encoding to use.
+ * TODO: isn't it redundant ? enc, gotEnc, conv plus the enc in the bb
+ */
+ private String enc;
+
+
+ /**
+ * Encoder is set.
+ */
+ private boolean gotEnc = false;
+
+
+ /**
+ * List of encoders. The writer is reused - the encoder mapping
+ * avoids creating expensive objects. In future it'll contain nio.Charsets
+ */
+ protected HashMap encoders = new HashMap();
+
+
+ /**
+ * Current char to byte converter. TODO: replace with Charset
+ */
+ protected C2BConverter conv;
+
+
+ /**
+ * Associated Coyote response.
+ */
+ private Response coyoteResponse;
+
+
+ /**
+ * Suspended flag. All output bytes will be swallowed if this is true.
+ */
+ private boolean suspended = false;
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Default constructor. Allocate the buffer with the default buffer size.
+ */
+ public MessageWriter() {
+
+ this(DEFAULT_BUFFER_SIZE);
+
+ }
+
+
+ /**
+ * Alternate constructor which allows specifying the initial buffer size.
+ *
+ * @param size Buffer size to use
+ */
+ public MessageWriter(int size) {
+
+ bb = new ByteChunk(size);
+ bb.setLimit(size);
+ bb.setByteOutputChannel(this);
+ cb = new CharChunk(size);
+ cb.setCharOutputChannel(this);
+ cb.setLimit(size);
+
+ }
+
+
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * Associated Coyote response.
+ *
+ * @param coyoteResponse Associated Coyote response
+ */
+ public void setResponse(Response coyoteResponse) {
+ this.coyoteResponse = coyoteResponse;
+ }
+
+
+ /**
+ * Get associated Coyote response.
+ *
+ * @return the associated Coyote response
+ */
+ public Response getResponse() {
+ return this.coyoteResponse;
+ }
+
+
+ /**
+ * Is the response output suspended ?
+ *
+ * @return suspended flag value
+ */
+ public boolean isSuspended() {
+ return this.suspended;
+ }
+
+
+ /**
+ * Set the suspended flag.
+ *
+ * @param suspended New suspended flag value
+ */
+ public void setSuspended(boolean suspended) {
+ this.suspended = suspended;
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Recycle the output buffer.
+ */
+ public void recycle() {
+
+ state = INITIAL_STATE;
+ bytesWritten = 0;
+ charsWritten = 0;
+
+ cb.recycle();
+ bb.recycle();
+ closed = false;
+ suspended = false;
+
+ if (conv!= null) {
+ conv.recycle();
+ }
+
+ gotEnc = false;
+ enc = null;
+
+ }
+
+
+ /**
+ * Close the output buffer. This tries to calculate the response size if
+ * the response has not been committed yet.
+ *
+ * @throws IOException An underlying IOException occurred
+ */
+ public void close()
+ throws IOException {
+
+ if (closed)
+ return;
+ if (suspended)
+ return;
+
+ if ((!coyoteResponse.isCommitted())
+ && (coyoteResponse.getContentLengthLong() == -1)) {
+ // Flushing the char buffer
+ if (state == CHAR_STATE) {
+ cb.flushBuffer();
+ state = BYTE_STATE;
+ }
+ // If this didn't cause a commit of the response, the final content
+ // length can be calculated
+ if (!coyoteResponse.isCommitted()) {
+ coyoteResponse.setContentLength(bb.getLength());
+ }
+ }
+
+ doFlush(false);
+ closed = true;
+
+ coyoteResponse.finish();
+
+ }
+
+
+ /**
+ * Flush bytes or chars contained in the buffer.
+ *
+ * @throws IOException An underlying IOException occurred
+ */
+ public void flush()
+ throws IOException {
+ doFlush(true);
+ }
+
+
+ /**
+ * Flush bytes or chars contained in the buffer.
+ *
+ * @throws IOException An underlying IOException occurred
+ */
+ protected void doFlush(boolean realFlush)
+ throws IOException {
+
+ if (suspended)
+ return;
+
+ doFlush = true;
+ if (state == CHAR_STATE) {
+ cb.flushBuffer();
+ bb.flushBuffer();
+ state = BYTE_STATE;
+ } else if (state == BYTE_STATE) {
+ bb.flushBuffer();
+ } else if (state == INITIAL_STATE) {
+ // If the buffers are empty, commit the response header
+ coyoteResponse.sendHeaders();
+ }
+ doFlush = false;
+
+ if (realFlush) {
+ coyoteResponse.action(ActionCode.ACTION_CLIENT_FLUSH,
+ coyoteResponse);
+ // If some exception occurred earlier, or if some IOE occurred
+ // here, notify the servlet with an IOE
+ if (coyoteResponse.isExceptionPresent()) {
+ throw new ClientAbortException
+ (coyoteResponse.getErrorException());
+ }
+ }
+
+ }
+
+
+ // ------------------------------------------------- Bytes Handling Methods
+
+
+ /**
+ * Sends the buffer data to the client output, checking the
+ * state of Response and calling the right interceptors.
+ *
+ * @param buf Byte buffer to be written to the response
+ * @param off Offset
+ * @param cnt Length
+ *
+ * @throws IOException An underlying IOException occurred
+ */
+ public void realWriteBytes(byte buf[], int off, int cnt)
+ throws IOException {
+
+ if (closed)
+ return;
+ if (coyoteResponse == null)
+ return;
+
+ // If we really have something to write
+ if (cnt > 0) {
+ // real write to the adapter
+ outputChunk.setBytes(buf, off, cnt);
+ try {
+ coyoteResponse.doWrite(outputChunk);
+ } catch (IOException e) {
+ // An IOException on a write is almost always due to
+ // the remote client aborting the request. Wrap this
+ // so that it can be handled better by the error dispatcher.
+ throw new ClientAbortException(e);
+ }
+ }
+
+ }
+
+
+ public void write(byte b[], int off, int len) throws IOException {
+
+ if (suspended)
+ return;
+
+ if (state == CHAR_STATE)
+ cb.flushBuffer();
+ state = BYTE_STATE;
+ writeBytes(b, off, len);
+
+ }
+
+
+ private void writeBytes(byte b[], int off, int len)
+ throws IOException {
+
+ if (closed)
+ return;
+
+ bb.append(b, off, len);
+ bytesWritten += len;
+
+ // if called from within flush(), then immediately flush
+ // remaining bytes
+ if (doFlush) {
+ bb.flushBuffer();
+ }
+
+ }
+
+
+ public void writeByte(int b)
+ throws IOException {
+
+ if (suspended)
+ return;
+
+ if (state == CHAR_STATE)
+ cb.flushBuffer();
+ state = BYTE_STATE;
+
+ bb.append( (byte)b );
+ bytesWritten++;
+
+ }
+
+
+ // ------------------------------------------------- Chars Handling Methods
+
+
+ public void write(int c)
+ throws IOException {
+
+ if (suspended)
+ return;
+
+ state = CHAR_STATE;
+
+ cb.append((char) c);
+ charsWritten++;
+
+ }
+
+
+ public void write(char c[])
+ throws IOException {
+
+ if (suspended)
+ return;
+
+ write(c, 0, c.length);
+
+ }
+
+
+ public void write(char c[], int off, int len)
+ throws IOException {
+
+ if (suspended)
+ return;
+
+ state = CHAR_STATE;
+
+ cb.append(c, off, len);
+ charsWritten += len;
+
+ }
+
+
+ public void write(StringBuffer sb)
+ throws IOException {
+
+ if (suspended)
+ return;
+
+ state = CHAR_STATE;
+
+ int len = sb.length();
+ charsWritten += len;
+ cb.append(sb);
+
+ }
+
+
+ /**
+ * Append a string to the buffer
+ */
+ public void write(String s, int off, int len)
+ throws IOException {
+
+ if (suspended)
+ return;
+
+ state=CHAR_STATE;
+
+ charsWritten += len;
+ if (s==null)
+ s="null";
+ cb.append( s, off, len );
+
+ }
+
+
+ public void write(String s)
+ throws IOException {
+
+ if (suspended)
+ return;
+
+ state = CHAR_STATE;
+ if (s==null)
+ s="null";
+ write(s, 0, s.length());
+
+ }
+
+
+ public void flushChars()
+ throws IOException {
+
+ cb.flushBuffer();
+ state = BYTE_STATE;
+
+ }
+
+
+ public boolean flushCharsNeeded() {
+ return state == CHAR_STATE;
+ }
+
+
+ public void setEncoding(String s) {
+ enc = s;
+ }
+
+
+ public void realWriteChars(char c[], int off, int len)
+ throws IOException {
+
+ if (!gotEnc)
+ setConverter();
+
+ conv.convert(c, off, len);
+ conv.flushBuffer(); // ???
+
+ }
+
+
+ public void checkConverter()
+ throws IOException {
+
+ if (!gotEnc)
+ setConverter();
+
+ }
+
+
+ protected void setConverter()
+ throws IOException {
+
+ if (coyoteResponse != null)
+ enc = coyoteResponse.getCharacterEncoding();
+
+ gotEnc = true;
+ if (enc == null)
+ enc = DEFAULT_ENCODING;
+ conv = (C2BConverter) encoders.get(enc);
+ if (conv == null) {
+
+ if (System.getSecurityManager() != null){
+ try{
+ conv = (C2BConverter)AccessController.doPrivileged(
+ new PrivilegedExceptionAction(){
+
+ public Object run() throws IOException{
+ return new C2BConverter(bb, enc);
+ }
+
+ }
+ );
+ }catch(PrivilegedActionException ex){
+ Exception e = ex.getException();
+ if (e instanceof IOException)
+ throw (IOException)e;
+ }
+ } else {
+ conv = new C2BConverter(bb, enc);
+ }
+
+ encoders.put(enc, conv);
+
+ }
+ }
+
+
+ // -------------------- BufferedOutputStream compatibility
+
+
+ /**
+ * Real write - this buffer will be sent to the client
+ */
+ public void flushBytes()
+ throws IOException {
+
+ bb.flushBuffer();
+
+ }
+
+
+ public int getBytesWritten() {
+ return bytesWritten;
+ }
+
+
+ public int getCharsWritten() {
+ return charsWritten;
+ }
+
+
+ public int getContentWritten() {
+ return bytesWritten + charsWritten;
+ }
+
+
+ /**
+ * True if this buffer hasn't been used ( since recycle() ) -
+ * i.e. no chars or bytes have been added to the buffer.
+ */
+ public boolean isNew() {
+ return (bytesWritten == 0) && (charsWritten == 0);
+ }
+
+
+ public void setBufferSize(int size) {
+ if (size > bb.getLimit()) {// ??????
+ bb.setLimit(size);
+ }
+ }
+
+
+ public void reset() {
+
+ //count=0;
+ bb.recycle();
+ bytesWritten = 0;
+ cb.recycle();
+ charsWritten = 0;
+ gotEnc = false;
+ enc = null;
+ state = INITIAL_STATE;
+ }
+
+
+ public int getBufferSize() {
+ return bb.getLimit();
+ }
+
+
+ public static MessageWriter getWriter(Request req, Response res, int size)
+ {
+ MessageWriter
out=(MessageWriter)req.getNote(MessageWriter.WRITER_NOTE);
+ if( out == null ) {
+ if( size<=0 ) {
+ out=new MessageWriter();
+ } else {
+ out=new MessageWriter(size);
+ }
+ out.setResponse(res);
+ req.setNote(MessageWriter.WRITER_NOTE, out );
+ }
+ return out;
+ }
+
+
+}
Added:
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/SimpleFileAdapter.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/SimpleFileAdapter.java?rev=640852&view=auto
==============================================================================
---
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/SimpleFileAdapter.java
(added)
+++
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/SimpleFileAdapter.java
Tue Mar 25 08:17:03 2008
@@ -0,0 +1,138 @@
+package org.apache.coyote.adapters;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+import org.apache.coyote.Adapter;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.C2BConverter;
+import org.apache.tomcat.util.net.SocketStatus;
+
+/**
+ * Serve a static file. This is the traditional method, a separate adapter
could
+ * use Sendfile.
+ *
+ * No fancy things. Not sure if it should have dir support even.
+ */
+public class SimpleFileAdapter implements Adapter {
+ Logger log = Logger.getLogger("coyote.file");
+
+ private String baseDir = "html/";
+
+ private File baseDirF;
+
+ public SimpleFileAdapter() {
+ init();
+ }
+
+ public void setBaseDir(String s) {
+ baseDir = s;
+ }
+
+ public void init() {
+ baseDirF = new File(baseDir);
+ try {
+ baseDir = baseDirF.getCanonicalPath();
+ } catch (IOException e) {
+ }
+ }
+
+ public void service(Request req, final Response res) throws Exception {
+
+ String uri = req.requestURI().toString();
+ if (uri.indexOf("..") >= 0) {
+ // not supported, too dangerous
+ // what else to escape ?
+ log.info("Invalid .. in " + uri);
+ res.setStatus(404);
+ return;
+ }
+
+ // local file
+ File f = new File(baseDirF, uri);
+
+ // extra check
+ if (!f.getCanonicalPath().startsWith(baseDir)) {
+ log.info("File outside basedir " + baseDir + " " + f);
+ res.setStatus(404);
+ return;
+ }
+
+ if (f.isDirectory()) {
+ // check for index.html, redirect if exists
+ // list dir if not
+
+ f = new File(f, "index.html");
+ }
+
+ if (!f.exists()) {
+ log.info("File not found " + f);
+ res.setStatus(404);
+ return;
+ }
+
+ res.setStatus(200);
+
+ // TODO: read from a resources in classpath !
+ // TODO: refactor to allow sendfile
+ // TODO: read mime types
+
+ int dot=uri.lastIndexOf(".");
+ if( dot > 0 ) {
+ String ext=uri.substring(dot+1);
+ String ct=getContentType(ext);
+ if( ct!=null) {
+ res.setContentType(ct);
+ }
+ }
+
+ res.setContentLength(f.length());
+
+ res.sendHeaders();
+
+ // not used - writes directly to response
+ // MessageWriter out = MessageWriter.getWriter(req, res, 0);
+
+ FileInputStream fis = new FileInputStream(f);
+ byte b[] = new byte[4096];
+ ByteChunk mb = new ByteChunk();
+ int rd = 0;
+ while ((rd = fis.read(b)) > 0) {
+ mb.setBytes(b, 0, rd);
+ res.doWrite(mb);
+ }
+
+ }
+
+ static Properties contentTypes=new Properties();
+ static {
+ initContentTypes();
+ }
+ static void initContentTypes() {
+ contentTypes.put("xhtml", "text/html");
+ contentTypes.put("html", "text/html");
+ contentTypes.put("txt", "text/plain");
+ contentTypes.put("css", "text/css");
+ contentTypes.put("xul", "application/vnd.mozilla.xul+xml");
+ }
+
+ public String getContentType( String ext ) {
+ return contentTypes.getProperty( ext, "text/plain" );
+ }
+
+ public boolean event(Request req, Response res, boolean error) throws
Exception {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean event(Request req, Response res, SocketStatus status)
+ throws Exception {
+ return false;
+ }
+
+}
\ No newline at end of file
Added:
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/StaticAdapter.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/StaticAdapter.java?rev=640852&view=auto
==============================================================================
---
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/StaticAdapter.java
(added)
+++
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/StaticAdapter.java
Tue Mar 25 08:17:03 2008
@@ -0,0 +1,85 @@
+package org.apache.coyote.adapters;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.net.SocketStatus;
+
+/**
+ * Serve a static file. This is the traditional method, a separate adapter
could
+ * use Sendfile.
+ *
+ * No fancy things. Not sure if it should have dir support even.
+ */
+public class StaticAdapter implements Adapter {
+ Logger log = Logger.getLogger("coyote.static");
+ ByteChunk mb = new ByteChunk();
+ int len = 4096;
+ byte[] data;
+
+ boolean chunked = false;
+
+ String contentType = "text/plain";
+
+
+ public StaticAdapter() {
+ init();
+ }
+
+ public StaticAdapter chunked() {
+ chunked = true;
+ return this;
+ }
+
+ public void setFile(String path) {
+ try {
+ FileInputStream fis = new FileInputStream(path);
+ mb.recycle();
+ mb.allocate(4096, -1);
+
+ byte b[] = new byte[4096];
+ int rd = 0;
+ while ((rd = fis.read(b)) > 0) {
+ mb.append(b, 0, rd);
+ }
+ len = mb.getLength();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void init() {
+ data = new byte[len];
+ for (int i = 0; i < len; i++) {
+ data[i] = 'A';
+ }
+ mb.setBytes(data, 0, len);
+ }
+
+ public void service(Request req, final Response res) throws Exception {
+
+ res.setStatus(200);
+ if (!chunked) {
+ res.setContentLength(len);
+ }
+ res.setContentType(contentType);
+ res.sendHeaders();
+ if (chunked) {
+ res.doWrite(mb);
+ res.action(ActionCode.ACTION_CLIENT_FLUSH, res);
+ }
+ res.doWrite(mb);
+ }
+
+ public boolean event(Request req, Response res, SocketStatus status)
+ throws Exception {
+ return false;
+ }
+
+}
\ No newline at end of file
Added:
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/StaticMain.java
URL:
http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/StaticMain.java?rev=640852&view=auto
==============================================================================
---
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/StaticMain.java
(added)
+++
tomcat/sandbox/tomcat-lite/coyote-extensions/org/apache/coyote/adapters/StaticMain.java
Tue Mar 25 08:17:03 2008
@@ -0,0 +1,31 @@
+package org.apache.coyote.adapters;
+
+import org.apache.tomcat.util.IntrospectionUtils;
+
+
+
+/**
+ * Serve a static resource, all in RAM. This should be the fastest way to
+ * send data over HTTP with tomcat - no overhead except the coyote layer.
+ *
+ * Used to benchmark and for files/resources that are extremely popular.
+ */
+public class StaticMain extends CoyoteServer {
+
+ public StaticMain() {
+ }
+
+ protected void initAdapters() {
+ adapter = new StaticAdapter();
+ }
+
+ // ------------------- Main ---------------------
+ public static void main( String args[]) throws Exception {
+ StaticMain sa=new StaticMain();
+ IntrospectionUtils.processArgs(sa, args);
+ sa.setArgs(args);
+ sa.run();
+ }
+
+
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]