From: costin Date: Thu, 25 Jun 2009 15:00:52 +0000 (+0000) Subject: - added new methods stups from servlet, so it compiles X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=d056d986a6c985ca118a1f38a862f6ea7ae09cf5;p=tomcat7.0 - added new methods stups from servlet, so it compiles - removed all deps on coyote, it can now run with the new async connector from sandbox ( still need to update ). Coyote is still the default - various cleanups in the simple/example integration support - still passes all watchdog servlet and all but 7 jsp tests - more separation between the servlets/filters and the engine - and few tweaks to allow file servlet to be used in other containers. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@788376 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/tomcat-lite/java/org/apache/tomcat/addons/Filesystem.java b/modules/tomcat-lite/java/org/apache/tomcat/addons/Filesystem.java new file mode 100644 index 000000000..963d06b0b --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/addons/Filesystem.java @@ -0,0 +1,26 @@ +/* + */ +package org.apache.tomcat.addons; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Abstract the filesystem - lighter than the JNDI used in catalina. + * + * This can be used to port the File/Dav servlets to environments that + * don't have a file system access, or in servlet engines with class-based + * sandboxing. + */ +public class Filesystem { + + public OutputStream getOutputStream(String name) throws IOException { + return null; + } + + public InputStream getInputStream(String name) throws IOException { + return new FileInputStream(name); + } +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/integration/ObjectManager.java b/modules/tomcat-lite/java/org/apache/tomcat/integration/ObjectManager.java index 88d4c6aac..e1d8cc233 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/integration/ObjectManager.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/integration/ObjectManager.java @@ -36,7 +36,7 @@ public class ObjectManager { * The framework may inject properties - if it supports that. */ public void bind(String name, Object o) { - for (ObjectManagerSpi p : providers) { + for (ObjectManager p : children) { p.bind(name, o); } } @@ -45,7 +45,7 @@ public class ObjectManager { * When an object is no longer in use. */ public void unbind(String name) { - for (ObjectManagerSpi p : providers) { + for (ObjectManager p : children) { p.unbind(name); } } @@ -54,7 +54,7 @@ public class ObjectManager { * Create or get a new object with the given name. */ public Object get(String key) { - for (ObjectManagerSpi p : providers) { + for (ObjectManager p : children) { Object o = p.get(key); if (o != null) { return o; @@ -74,6 +74,10 @@ public class ObjectManager { * ObjectManager delegates to providers. You can have multiple * providers - for example JMX, DI and OSGI at the same time. */ - protected List providers = - new ArrayList(); + protected List children = + new ArrayList(); + + public void register(ObjectManager om) { + om.children.add(this); + } } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/integration/ObjectManagerSpi.java b/modules/tomcat-lite/java/org/apache/tomcat/integration/ObjectManagerSpi.java deleted file mode 100644 index 3619087e5..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/integration/ObjectManagerSpi.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - */ -package org.apache.tomcat.integration; - -/** - * Base class for framework-integration plugins. - */ -public abstract class ObjectManagerSpi { - public abstract void bind(String name, Object o); - - public abstract void unbind(String name); - - public abstract Object get(String key); - - public void register(ObjectManager om) { - om.providers.add(this); - } -} \ No newline at end of file diff --git a/modules/tomcat-lite/java/org/apache/tomcat/integration/jmx/JmxObjectManagerSpi.java b/modules/tomcat-lite/java/org/apache/tomcat/integration/jmx/JmxObjectManagerSpi.java index 96b134773..0a1b1bab9 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/integration/jmx/JmxObjectManagerSpi.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/integration/jmx/JmxObjectManagerSpi.java @@ -4,7 +4,7 @@ package org.apache.tomcat.integration.jmx; import java.util.logging.Logger; -import org.apache.tomcat.integration.ObjectManagerSpi; +import org.apache.tomcat.integration.ObjectManager; import org.apache.tomcat.util.modeler.Registry; /** @@ -12,7 +12,7 @@ import org.apache.tomcat.util.modeler.Registry; * * All objects of interest are registered automatically. */ -public class JmxObjectManagerSpi extends ObjectManagerSpi { +public class JmxObjectManagerSpi extends ObjectManager { Registry registry; Logger log = Logger.getLogger("JmxObjectManager"); diff --git a/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/LocalFilesystem.java b/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/LocalFilesystem.java new file mode 100644 index 000000000..782d5c2ab --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/LocalFilesystem.java @@ -0,0 +1,16 @@ +/* + */ +package org.apache.tomcat.integration.simple; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.tomcat.addons.Filesystem; + +public class LocalFilesystem extends Filesystem { + + public OutputStream getOutputStream(String name) throws IOException { + return new FileOutputStream(name); + } +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/Main.java b/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/Main.java new file mode 100644 index 000000000..7871cbbb7 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/Main.java @@ -0,0 +1,50 @@ +/* + */ +package org.apache.tomcat.integration.simple; + +import org.apache.tomcat.integration.ObjectManager; + +/** + * Replacement for tomcat-lite specific Main, using the simple + * injection. SimpleObjectManager also has support for simple + * command line processing - CLI is treated the same with + * properties from the config file. + * + * @author Costin Manolache + */ +public class Main { + + public static void main(String args[]) + throws Exception { + SimpleObjectManager om = new SimpleObjectManager(); + + // Will process CLI. + // 'config' will load a config file. + om.bind("Main.args", args); + + Runnable main = (Runnable) om.get("Main"); + if (main == null) { + // TODO: look for a pre-defined name in local dir, resource, + // manifest + System.err.println("Using default tomcat-lite configuration"); + + if (args.length == 0) { + System.err.println("Example command line:"); + System.err.println("-context /:webapps/ROOT -Connector.port 9999"); + } + + String cfgFile = "org/apache/tomcat/lite/config.properties"; + om.loadResource(cfgFile); + main = (Runnable) om.get("Main"); + } + + // add JMX support + ObjectManager jmx = (ObjectManager) om.get("JMX"); + if (jmx != null) { + jmx.register(om); + } + + main.run(); + + } +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/ServletHelper.java b/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/ServletHelper.java new file mode 100644 index 000000000..bf5bf15e2 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/ServletHelper.java @@ -0,0 +1,60 @@ +/* + */ +package org.apache.tomcat.integration.simple; + +import java.util.Enumeration; + +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +import org.apache.tomcat.integration.ObjectManager; + +public class ServletHelper { + + public static ObjectManager getObjectManager(ServletContext ctx) { + // May be provided by container or a listener + ObjectManager om = (ObjectManager) ctx.getAttribute(ObjectManager.ATTRIBUTE); + if (om == null) { + // Default + SimpleObjectManager som = new SimpleObjectManager(); + om = som; + + // All context init params are set + Enumeration namesE = ctx.getInitParameterNames(); + while (namesE.hasMoreElements()) { + String n = (String) namesE.nextElement(); + String v = ctx.getInitParameter(n); + som.getProperties().put(n, v); + } + + ctx.setAttribute(ObjectManager.ATTRIBUTE, om); + // load context settings + } + return om; + } + + public static void initServlet(Servlet s) { + ServletConfig sc = s.getServletConfig(); + String name = sc.getServletName(); + String ctx = sc.getServletContext().getContextPath(); + + // Servlets are named:... + + ObjectManager om = getObjectManager(sc.getServletContext()); + + String dn = ctx + ":" + name; + + // If SimpleObjectManager ( or maybe other supporting dynamic config ): + if (om instanceof SimpleObjectManager) { + SimpleObjectManager som = (SimpleObjectManager) om; + + + } + + + om.bind(dn, s); + + } + +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/SimpleObjectManager.java b/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/SimpleObjectManager.java index 5b3398359..20854a550 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/SimpleObjectManager.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/integration/simple/SimpleObjectManager.java @@ -2,6 +2,7 @@ */ package org.apache.tomcat.integration.simple; +import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; @@ -11,8 +12,8 @@ import java.util.Properties; import java.util.logging.Logger; import org.apache.tomcat.integration.ObjectManager; -import org.apache.tomcat.integration.ObjectManagerSpi; import org.apache.tomcat.util.IntrospectionUtils; +import org.apache.tools.ant.taskdefs.LoadResource; /** * This is a very small 'dependency injection'/registry poor-man substitute, @@ -39,36 +40,30 @@ import org.apache.tomcat.util.IntrospectionUtils; * * @author Costin Manolache */ -public class SimpleObjectManager extends ObjectManagerSpi { - +public class SimpleObjectManager extends ObjectManager { static Logger log = Logger.getLogger(SimpleObjectManager.class.getName()); - /** - * Saved CLI arguments. Will be added to the properties. - */ - public static String[] args; - protected Properties props = new Properties(); protected Map objects = new HashMap(); ObjectManager om; public SimpleObjectManager() { + // Register PropertiesSpi } - public SimpleObjectManager(ObjectManager om) { - register(om); + public SimpleObjectManager(String[] args) { + this(); + bind("Main.args", args); } - + + public void loadResource(String res) { + InputStream in = this.getClass().getClassLoader() + .getResourceAsStream(res); + load(in); + } + public void register(ObjectManager om) { this.om = om; - if (args != null) { - try { - processArgs(args, props); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } super.register(om); } @@ -84,12 +79,6 @@ public class SimpleObjectManager extends ObjectManagerSpi { } } - public void loadResource(String res) { - InputStream in = this.getClass().getClassLoader() - .getResourceAsStream(res); - load(in); - } - public Properties getProperties() { return props; } @@ -100,8 +89,16 @@ public class SimpleObjectManager extends ObjectManagerSpi { @Override public void bind(String name, Object o) { - log.info("Bound: " + name + " " + o); + //log.info("Bound: " + name + " " + o); + if ("Main.args".equals(name)) { + try { + processArgs((String[]) o, props); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + // TODO: can I make 'inject' public - Guice seems to // support this. inject(name, o); @@ -170,7 +167,7 @@ public class SimpleObjectManager extends ObjectManagerSpi { * @return everything after the first non arg not starting with '-' * @throws IOException */ - public static String[] processArgs(String[] args, Properties props) + public String[] processArgs(String[] args, Properties props) throws IOException { for (int i = 0; i < args.length; i++) { @@ -200,15 +197,15 @@ public class SimpleObjectManager extends ObjectManagerSpi { } if ("config".equals(arg)) { - props.load(new FileInputStream(value)); + if (new File(value).exists()) { + load(new FileInputStream(value)); + } else { + loadResource(value); + } } else { props.put(name, value); } } return new String[] {}; - } - - public static void setArgs(String[] argv) { - SimpleObjectManager.args = argv; - } + } } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/BodyReader.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/BodyReader.java new file mode 100644 index 000000000..e8f8a6be5 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/BodyReader.java @@ -0,0 +1,509 @@ +/* + * 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.lite; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.util.HashMap; + +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. + * + */ + +/** + * 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 BodyReader 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. More data may be added to it while reading. + */ + private ByteChunk bb; + + + /** + * The chunk buffer, will be filled in from the bb. + */ + 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; + + /** + * Encoding to use. + */ + private String enc; + + + /** + * Encoder is set. + */ + private boolean gotEnc = false; + + + /** + * Cached encoders. + */ + protected HashMap encoders = + new HashMap(); + + + /** + * Current byte to char converter. + */ + protected B2CConverter conv; + + + /** + * Associated Coyote request. + */ + private ServletRequestImpl coyoteRequest; + Connector connector; + + /** + * Buffer position. + */ + private int markPos = -1; + + + /** + * Buffer size. + */ + private int size = -1; + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor. Allocate the buffer with the default buffer size. + */ + public BodyReader() { + this(DEFAULT_BUFFER_SIZE); + } + + + /** + * Alternate constructor which allows specifying the initial buffer size. + * + * @param size Buffer size to use + */ + public BodyReader(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 setConnector(Connector c, ServletRequestImpl coyoteRequest) { + this.connector = c; + this.coyoteRequest = 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 = connector.doRead(coyoteRequest, 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; + } + + /** + * Called when a read(char[]) operation is lacking data. It will read + * bytes. + */ + 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, -1); + 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(); + } + } + + + 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) { + conv = new B2CConverter(enc); + encoders.put(enc, conv); + } + } + + public class MRInputStream extends InputStream { + public long skip(long n) + throws IOException { + return BodyReader.this.skip(n); + } + + public void mark(int readAheadLimit) + { + try { + BodyReader.this.mark(readAheadLimit); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + public void reset() + throws IOException { + BodyReader.this.reset(); + } + + + + public int read() + throws IOException { + return BodyReader.this.readByte(); + } + + public int available() throws IOException { + return BodyReader.this.available(); + } + + public int read(final byte[] b) throws IOException { + return BodyReader.this.read(b, 0, b.length); + } + + + public int read(final byte[] b, final int off, final int len) + throws IOException { + + return BodyReader.this.read(b, off, len); + } + + + /** + * Close the stream + * Since we re-cycle, we can't allow the call to super.close() + * which would permantely disable us. + */ + public void close() throws IOException { + BodyReader.this.close(); + } + } + + MRInputStream is = new MRInputStream(); + + public InputStream asInputStream() { + return is; + } +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/BodyWriter.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/BodyWriter.java new file mode 100644 index 000000000..cad571d7c --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/BodyWriter.java @@ -0,0 +1,656 @@ +/* + */ +package org.apache.tomcat.lite; + +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.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.C2BConverter; +import org.apache.tomcat.util.buf.CharChunk; + +/** + * Implement buffering and character translation acording to the + * servlet spec. + * + * This class handles both chars and bytes. + * + * It is tightly integrated with servlet response, sending headers + * and updating the commit state. + * + * TODO: add 'extension' interface that allows direct access to + * the async connector non-copy non-blocking queue. Same for the + * OutputStream. Maybe switch the buffer to the brigade. + * + * @author Costin Manolache + */ +public class BodyWriter extends Writer { + + // used in getWriter, until a method is added to res. + protected static final int WRITER_NOTE = 3; + + + private ByteChunk.ByteOutputChannel byteFlusher = + new ByteChunk.ByteOutputChannel() { + + @Override + public void realWriteBytes(byte[] cbuf, int off, int len) + throws IOException { + BodyWriter.this.realWriteBytes(cbuf, off, len); + } + }; + + private CharChunk.CharOutputChannel charFlusher = + new CharChunk.CharOutputChannel() { + @Override + public void realWriteChars(char[] cbuf, int off, int len) + throws IOException { + BodyWriter.this.realWriteChars(cbuf, off, len); + } + }; + + + 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 CHAR_STATE = 1; + public final int BYTE_STATE = 2; + + boolean headersSent = false; + // ----------------------------------------------------- Instance Variables + ServletResponseImpl res; + + /** + * The byte buffer. + */ + protected ByteChunk bb; + + + /** + * The chunk buffer. + */ + protected CharChunk cb; + + + /** + * State of the output buffer. + */ + protected int state = 0; + + + /** + * Number of bytes written. + */ + protected int bytesWritten = 0; + + + /** + * Number of chars written. + */ + protected int charsWritten = 0; + + + /** + * Flag which indicates if the output buffer is closed. + */ + protected boolean closed = false; + + + /** + * Do a flush on the next operation. + */ + protected boolean doFlush = false; + + + /** + * Byte chunk used to output bytes. This is just used to wrap the byte[] + * to match the coyote OutputBuffer interface + */ + protected ByteChunk outputChunk = new ByteChunk(); + + + /** + * Encoding to use. + * TODO: isn't it redundant ? enc, gotEnc, conv plus the enc in the bb + */ + protected String enc; + + + /** + * Encoder is set. + */ + protected 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; + + /** + * Suspended flag. All output bytes will be swallowed if this is true. + */ + protected boolean suspended = false; + + private Connector connector; + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor. Allocate the buffer with the default buffer size. + */ + public BodyWriter() { + + this(DEFAULT_BUFFER_SIZE); + + } + + + /** + * Alternate constructor which allows specifying the initial buffer size. + * + * @param size Buffer size to use + */ + public BodyWriter(int size) { + + bb = new ByteChunk(size); + bb.setLimit(size); + bb.setByteOutputChannel(byteFlusher); + cb = new CharChunk(size); + cb.setCharOutputChannel(charFlusher); + cb.setLimit(size); + + } + + public void setConnector(Connector c, ServletResponseImpl res) { + this.res = res; + this.connector = c; + } + + + // ------------------------------------------------------------- Properties + + + /** + * 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 = BYTE_STATE; + headersSent = false; + 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 (state == CHAR_STATE) { + cb.flushBuffer(); + state = BYTE_STATE; + } + connector.beforeClose(res, bb.getLength()); + + doFlush(false); + closed = true; + + connector.finishResponse(res); + } + + + /** + * 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 (!headersSent) { + // If the buffers are empty, commit the response header + connector.sendHeaders(res); + headersSent = true; + } + if (state == CHAR_STATE) { + cb.flushBuffer(); + state = BYTE_STATE; + } + if (state == BYTE_STATE) { + bb.flushBuffer(); + } + doFlush = false; + + if (realFlush) { + connector.realFlush(res); + } + + } + + + // ------------------------------------------------- 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 + */ + private void realWriteBytes(byte buf[], int off, int cnt) + throws IOException { + + if (closed) + return; + + // If we really have something to write + if (cnt > 0) { + // real write to the adapter + outputChunk.setBytes(buf, off, cnt); + try { + connector.doWrite(res, 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 println() throws IOException { + write("\n"); + } + + public void println(String s) throws IOException { + write(s); + write("\n"); + } + + public void print(String s) throws IOException { + write(s); + } + + public void flushChars() + throws IOException { + + cb.flushBuffer(); + state = BYTE_STATE; + + } + + + public boolean flushCharsNeeded() { + return state == CHAR_STATE; + } + + + public void setEncoding(String s) { + enc = s; + } + + + private 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 { + + enc = res.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 = BYTE_STATE; + } + + + public int getBufferSize() { + return bb.getLimit(); + } + + public ByteChunk getByteBuffer() { + return outputChunk; + } + +} +//{ +// public abstract int getBytesWritten(); +// public abstract int getCharsWritten(); +// public abstract void recycle(); +// public abstract void setSuspended(boolean suspended); +// public abstract boolean isSuspended(); +// +// public abstract void reset(); +// public abstract int getBufferSize(); +// public abstract void setBufferSize(int n); +// public abstract void checkConverter() throws IOException; +// public boolean isNew() { +// return getBytesWritten() == 0 && getCharsWritten() == 0; +// } +// public abstract void write(byte[] b, int off, int len) throws IOException; +// public abstract void writeByte(int b) throws IOException; +// +//} \ No newline at end of file diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ClientAbortException.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ClientAbortException.java new file mode 100644 index 000000000..0b9f3657c --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/ClientAbortException.java @@ -0,0 +1,143 @@ +/* + * 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.lite; + +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()); + + } + + +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/Connector.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/Connector.java index d104b6836..245bfc66e 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/Connector.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/Connector.java @@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.tomcat.integration.ObjectManager; +import org.apache.tomcat.util.buf.ByteChunk; /** * What we need to plugin a connector. @@ -26,11 +27,51 @@ public interface Connector { public void setDaemon(boolean b); - public void start(); + public void start() throws IOException; - public void stop(); + public void stop() throws Exception; - public void finishResponse(HttpServletResponse res) throws IOException; + /** + * Called during close() - either on explicit output close, or + * after the request is completed. + * + * @throws IOException + */ + public abstract void finishResponse(HttpServletResponse res) throws IOException; + + /** + * Called before flushing the output during close. + * Content-Length may be updated. + * @param len + * + * @throws IOException + */ + public abstract void beforeClose(HttpServletResponse res, int len) throws IOException; + + /** + * Called when the first flush() is called. + * @throws IOException + */ + public abstract void sendHeaders(HttpServletResponse res) throws IOException; + + /** + * Send data to the client. + * @throws IOException + */ + public abstract void realFlush(HttpServletResponse res) throws IOException; + + /** + * Write to the connector underlying buffer. + * The chunk will be reused (currently). + */ + public abstract void doWrite(HttpServletResponse res, ByteChunk outputChunk2) throws IOException; + + + //public void finishResponse(HttpServletResponse res) throws IOException; + + public void acknowledge(HttpServletResponse res) throws IOException; + + public void reset(HttpServletResponse res); public void recycle(HttpServletRequest req, HttpServletResponse res); @@ -39,4 +80,10 @@ public interface Connector { public void setTomcatLite(TomcatLite tomcatLite); public void setObjectManager(ObjectManager objectManager); + + public String getRemoteHost(HttpServletRequest req); + + public String getRemoteAddr(HttpServletRequest req); + + public int doRead(ServletRequestImpl coyoteRequest, ByteChunk bb) throws IOException; } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletContextImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletContextImpl.java index bce77f753..f65866f5e 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletContextImpl.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletContextImpl.java @@ -37,11 +37,11 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; -import java.util.Map.Entry; import java.util.logging.Level; import java.util.logging.Logger; -import javax.servlet.DispatcherType; +import javax.servlet.Filter; +import javax.servlet.FilterRegistration; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletConfig; @@ -51,8 +51,10 @@ import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; import javax.servlet.SessionCookieConfig; import javax.servlet.SessionTrackingMode; +import javax.servlet.FilterRegistration.Dynamic; import org.apache.tomcat.addons.UserSessionManager; import org.apache.tomcat.integration.ObjectManager; @@ -933,10 +935,8 @@ public class ServletContextImpl implements ServletContext { public void processWebAppData(ServletContextConfig d) throws ServletException { this.contextConfig = d; - Iterator i1 = d.mimeMapping.entrySet().iterator(); - while (i1.hasNext()) { - Entry k = (Entry)i1.next(); - addMimeType((String)k.getKey(), (String)k.getValue()); + for (String k: d.mimeMapping.keySet()) { + addMimeType(k, d.mimeMapping.get(k)); } String[] wFiles = (String[])d.welcomeFileList.toArray(new String[0]); @@ -976,10 +976,8 @@ public class ServletContextImpl implements ServletContext { addServletConfig(sw); } - Iterator i4 = d.servletMapping.entrySet().iterator(); - while (i4.hasNext()) { - Entry/**/ k = (Entry) i4.next(); - addMapping((String) k.getKey(), (String) k.getValue()); + for (String k: d.servletMapping.keySet()) { + addMapping(k, d.servletMapping.get(k)); } Iterator i5 = d.filterMappings.iterator(); @@ -1013,10 +1011,11 @@ public class ServletContextImpl implements ServletContext { addServletConfig(sc); } - public void addServlet(String servletName, Servlet servlet) { + public javax.servlet.Registration.Dynamic addServlet(String servletName, Servlet servlet) { ServletConfigImpl sc = new ServletConfigImpl(this, servletName, null); sc.setServlet(servlet); addServletConfig(sc); + return null; } public void addServletSec(String serlvetName, String runAs, Map roles) { @@ -1375,54 +1374,75 @@ public class ServletContextImpl implements ServletContext { } @Override - public void addFilter(String filterName, String description, String className, - Map initParameters, - boolean isAsyncSupported) { + public EnumSet getDefaultSessionTrackingModes() { + return null; } @Override - public void addFilterMappingForServletNames( - String filterName, - EnumSet dispatcherTypes, - boolean isMatchAfter, - String... servletNames) { + public EnumSet getEffectiveSessionTrackingModes() { + return null; } @Override - public void addFilterMappingForUrlPatterns( - String filterName, - EnumSet dispatcherTypes, - boolean isMatchAfter, - String... urlPatterns) { + public SessionCookieConfig getSessionCookieConfig() { + return null; } @Override - public void addServletMapping(String servletName, String[] urlPatterns) { + public void setSessionTrackingModes(EnumSet sessionTrackingModes) { } @Override - public EnumSet getDefaultSessionTrackingModes() { + public Dynamic addFilter(String filterName, String className) { return null; } @Override - public EnumSet getEffectiveSessionTrackingModes() { + public Dynamic addFilter(String filterName, Filter filter) { return null; } @Override - public SessionCookieConfig getSessionCookieConfig() { + public Dynamic addFilter(String filterName, Class filterClass) { return null; } @Override - public void setSessionCookieConfig(SessionCookieConfig sessionCookieConfig) { + public javax.servlet.Registration.Dynamic addServlet(String servletName, + String className) { + return null; } @Override - public void setSessionTrackingModes( - EnumSet sessionTrackingModes) { + public javax.servlet.Registration.Dynamic addServlet( + String servletName, + Class servletClass) { + return null; + } + + @Override + public T createFilter(Class c) throws ServletException { + return null; } + @Override + public T createServlet(Class c) throws ServletException { + return null; + } + + @Override + public FilterRegistration findFilterRegistration(String filterName) { + return null; + } + + @Override + public ServletRegistration findServletRegistration(String servletName) { + return null; + } + + @Override + public boolean setInitParameter(String name, String value) { + return false; + } } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletOutputStreamImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletOutputStreamImpl.java index 2cd699cf8..53ae9d04a 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletOutputStreamImpl.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletOutputStreamImpl.java @@ -21,7 +21,6 @@ import java.io.IOException; import javax.servlet.ServletOutputStream; -import org.apache.tomcat.lite.coyote.MessageWriter; /** * Coyote implementation of the servlet output stream. @@ -36,13 +35,13 @@ public class ServletOutputStreamImpl // ----------------------------------------------------- Instance Variables - protected MessageWriter ob; + protected BodyWriter ob; // ----------------------------------------------------------- Constructors - public ServletOutputStreamImpl(MessageWriter ob) { + public ServletOutputStreamImpl(BodyWriter ob) { this.ob = ob; } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestImpl.java index 0cd9cd44d..644c4603a 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestImpl.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestImpl.java @@ -36,8 +36,10 @@ import java.util.logging.Level; import javax.security.auth.Subject; import javax.servlet.AsyncContext; import javax.servlet.AsyncListener; +import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; +import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestAttributeEvent; @@ -45,12 +47,11 @@ import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import javax.servlet.http.Part; -import org.apache.coyote.ActionCode; -import org.apache.coyote.Request; import org.apache.tomcat.addons.UserSessionManager; -import org.apache.tomcat.lite.coyote.MessageReader; import org.apache.tomcat.servlets.util.Enumerator; import org.apache.tomcat.servlets.util.LocaleParser; import org.apache.tomcat.servlets.util.RequestUtil; @@ -60,19 +61,19 @@ import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.buf.UriNormalizer; import org.apache.tomcat.util.http.Cookies; import org.apache.tomcat.util.http.FastHttpDateFormat; +import org.apache.tomcat.util.http.HttpRequest; import org.apache.tomcat.util.http.Parameters; import org.apache.tomcat.util.http.ServerCookie; import org.apache.tomcat.util.http.mapper.MappingData; /** + * * Wrapper object for the Coyote request. * * @author Remy Maucherat * @author Craig R. McClanahan - * @version $Revision$ $Date$ */ - public class ServletRequestImpl implements HttpServletRequest { /** @@ -287,21 +288,21 @@ public class ServletRequestImpl implements HttpServletRequest { /** * The associated input buffer. */ - protected MessageReader inputBuffer = new MessageReader(); + protected BodyReader inputBuffer; + Connector connector; /** * ServletInputStream. */ - protected ServletInputStreamImpl inputStream = - new ServletInputStreamImpl(inputBuffer.asInputStream()); + protected ServletInputStreamImpl inputStream; /** * Reader. */ - protected BufferedReader reader = new ServletReaderImpl(inputBuffer); - + protected BufferedReader reader; + /** * Using stream flag. @@ -426,7 +427,7 @@ public class ServletRequestImpl implements HttpServletRequest { public byte[] postData = null; - private Request coyoteRequest; + private HttpRequest httpRequest; /** New IO/buffer model */ @@ -495,6 +496,13 @@ public class ServletRequestImpl implements HttpServletRequest { // Not used } + public void setConnector(Connector c) { + connector = c; + } + + public Connector getConnector() { + return connector; + } /** * Add a Locale to the set of preferred Locales for this Request. The @@ -516,7 +524,7 @@ public class ServletRequestImpl implements HttpServletRequest { * @param values Corresponding values for this request parameter */ public void addParameter(String name, String values[]) { - coyoteRequest.getParameters().addParameterValues(name, values); + httpRequest.getParameters().addParameterValues(name, values); } /** @@ -648,7 +656,7 @@ public class ServletRequestImpl implements HttpServletRequest { * Return the character encoding for this Request. */ public String getCharacterEncoding() { - return (coyoteRequest.getCharacterEncoding()); + return (httpRequest.getCharacterEncoding()); } @@ -656,7 +664,7 @@ public class ServletRequestImpl implements HttpServletRequest { * Return the content length for this Request. */ public int getContentLength() { - return (coyoteRequest.getContentLength()); + return (httpRequest.getContentLength()); } @@ -707,7 +715,7 @@ public class ServletRequestImpl implements HttpServletRequest { * Return the content type for this Request. */ public String getContentType() { - return (coyoteRequest.getContentType()); + return (httpRequest.getContentType()); } @@ -792,7 +800,7 @@ public class ServletRequestImpl implements HttpServletRequest { * @return the URL decoded request URI */ public String getDecodedRequestURI() { - return (coyoteRequest.decodedURI().toString()); + return (httpRequest.decodedURI().toString()); } @@ -802,7 +810,7 @@ public class ServletRequestImpl implements HttpServletRequest { * @return the URL decoded request URI */ public MessageBytes getDecodedRequestURIMB() { - return (coyoteRequest.decodedURI()); + return (httpRequest.decodedURI()); } @@ -823,14 +831,14 @@ public class ServletRequestImpl implements HttpServletRequest { * @param name Name of the requested header */ public String getHeader(String name) { - return coyoteRequest.getHeader(name); + return httpRequest.getHeader(name); } /** * Return the names of all headers received with this request. */ public Enumeration getHeaderNames() { - return coyoteRequest.getMimeHeaders().names(); + return httpRequest.getMimeHeaders().names(); } @@ -841,7 +849,7 @@ public class ServletRequestImpl implements HttpServletRequest { * @param name Name of the requested header */ public Enumeration getHeaders(String name) { - return coyoteRequest.getMimeHeaders().values(name); + return httpRequest.getMimeHeaders().values(name); } /** @@ -891,7 +899,7 @@ public class ServletRequestImpl implements HttpServletRequest { * which the request was received. */ public String getLocalAddr(){ - return coyoteRequest.localAddr().toString(); + return httpRequest.localAddr().toString(); } @@ -940,7 +948,7 @@ public class ServletRequestImpl implements HttpServletRequest { * which the request was received. */ public String getLocalName(){ - return coyoteRequest.localName().toString(); + return httpRequest.localName().toString(); } @@ -949,7 +957,7 @@ public class ServletRequestImpl implements HttpServletRequest { * on which the request was received. */ public int getLocalPort(){ - return coyoteRequest.getLocalPort(); + return httpRequest.getLocalPort(); } @@ -966,7 +974,7 @@ public class ServletRequestImpl implements HttpServletRequest { * Return the HTTP request method used in this Request. */ public String getMethod() { - return coyoteRequest.method().toString(); + return httpRequest.method().toString(); } @@ -982,7 +990,7 @@ public class ServletRequestImpl implements HttpServletRequest { if (!parametersParsed) parseParameters(); - return coyoteRequest.getParameters().getParameter(name); + return httpRequest.getParameters().getParameter(name); } @@ -1023,7 +1031,7 @@ public class ServletRequestImpl implements HttpServletRequest { if (!parametersParsed) parseParameters(); - return coyoteRequest.getParameters().getParameterNames(); + return httpRequest.getParameters().getParameterNames(); } @@ -1039,7 +1047,7 @@ public class ServletRequestImpl implements HttpServletRequest { if (!parametersParsed) parseParameters(); - return coyoteRequest.getParameters().getParameterValues(name); + return httpRequest.getParameters().getParameterValues(name); } @@ -1090,14 +1098,14 @@ public class ServletRequestImpl implements HttpServletRequest { * Return the protocol and version used to make this Request. */ public String getProtocol() { - return coyoteRequest.protocol().toString(); + return httpRequest.protocol().toString(); } /** * Return the query string associated with this request. */ public String getQueryString() { - String queryString = coyoteRequest.queryString().toString(); + String queryString = httpRequest.queryString().toString(); if (queryString == null || queryString.equals("")) { return (null); } else { @@ -1184,10 +1192,10 @@ public class ServletRequestImpl implements HttpServletRequest { * Return the remote IP address making this Request. */ public String getRemoteAddr() { - if (coyoteRequest.remoteAddr().isNull()) { - coyoteRequest.action(ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, coyoteRequest); + if (httpRequest.remoteAddr().isNull()) { + httpRequest.remoteAddr().setString(connector.getRemoteAddr(this)); } - return coyoteRequest.remoteAddr().toString(); + return httpRequest.remoteAddr().toString(); } @@ -1195,10 +1203,10 @@ public class ServletRequestImpl implements HttpServletRequest { * Return the remote host name making this Request. */ public String getRemoteHost() { - if (coyoteRequest.remoteHost().isNull()) { - coyoteRequest.action(ActionCode.ACTION_REQ_HOST_ATTRIBUTE, coyoteRequest); + if (httpRequest.remoteHost().isNull()) { + httpRequest.remoteHost().setString(connector.getRemoteHost(this)); } - return coyoteRequest.remoteHost().toString(); + return httpRequest.remoteHost().toString(); } @@ -1207,7 +1215,7 @@ public class ServletRequestImpl implements HttpServletRequest { * or last proxy that sent the request. */ public int getRemotePort(){ - return coyoteRequest.getRemotePort(); + return httpRequest.getRemotePort(); } @@ -1234,15 +1242,20 @@ public class ServletRequestImpl implements HttpServletRequest { return this; } - public Request getCoyoteRequest() { - return coyoteRequest; + public HttpRequest getHttpRequest() { + return httpRequest; } - public void setCoyoteRequest(Request req) { - this.coyoteRequest = req; - inputBuffer.setRequest(req); + public void setHttpRequest(HttpRequest req, BodyReader in) { + this.httpRequest = req; + inputBuffer = in; + inputStream = new ServletInputStreamImpl(inputBuffer.asInputStream()); + reader = new ServletReaderImpl(inputBuffer); } + public BodyReader getBodyReader() { + return inputBuffer; + } /** * Return a RequestDispatcher that wraps the resource at the specified @@ -1315,16 +1328,16 @@ public class ServletRequestImpl implements HttpServletRequest { * Return the request URI for this request. */ public String getRequestURI() { - return coyoteRequest.requestURI().toString(); + return httpRequest.requestURI().toString(); } /** */ public void setRequestURI(String uri) { - coyoteRequest.decodedURI().setString(uri); + httpRequest.decodedURI().setString(uri); try { - UriNormalizer.decodeRequest(coyoteRequest.decodedURI(), - coyoteRequest.requestURI(), coyoteRequest.getURLDecoder()); + UriNormalizer.decodeRequest(httpRequest.decodedURI(), + httpRequest.requestURI(), httpRequest.getURLDecoder()); } catch(IOException ioe) { ioe.printStackTrace(); return; @@ -1384,7 +1397,7 @@ public class ServletRequestImpl implements HttpServletRequest { * Return the scheme used to make this Request. */ public String getScheme() { - String scheme = coyoteRequest.scheme().toString(); + String scheme = httpRequest.scheme().toString(); if (scheme == null) { scheme = (isSecure() ? "https" : "http"); } @@ -1396,7 +1409,7 @@ public class ServletRequestImpl implements HttpServletRequest { * Return the server name responding to this Request. */ public String getServerName() { - return (coyoteRequest.serverName().toString()); + return (httpRequest.serverName().toString()); } @@ -1404,7 +1417,7 @@ public class ServletRequestImpl implements HttpServletRequest { * Return the server port responding to this Request. */ public int getServerPort() { - return (coyoteRequest.getServerPort()); + return (httpRequest.getServerPort()); } @@ -1600,7 +1613,7 @@ public class ServletRequestImpl implements HttpServletRequest { parameterMap.clear(); mappingData.recycle(); - + httpRequest.recycle(); } @@ -1772,7 +1785,7 @@ public class ServletRequestImpl implements HttpServletRequest { String dummy = new String(buffer, enc); // Save the validated encoding - coyoteRequest.setCharacterEncoding(enc); + httpRequest.setCharacterEncoding(enc); } @@ -1863,7 +1876,7 @@ public class ServletRequestImpl implements HttpServletRequest { * @param method The request method */ public void setMethod(String method) { - coyoteRequest.method().setString(method); + httpRequest.method().setString(method); } @@ -1990,7 +2003,7 @@ public class ServletRequestImpl implements HttpServletRequest { * @param name The server name */ public void setServerName(String name) { - coyoteRequest.serverName().setString(name); + httpRequest.serverName().setString(name); } @@ -2000,7 +2013,7 @@ public class ServletRequestImpl implements HttpServletRequest { * @param port The server port */ public void setServerPort(int port) { - coyoteRequest.setServerPort(port); + httpRequest.setServerPort(port); } @@ -2067,7 +2080,7 @@ public class ServletRequestImpl implements HttpServletRequest { public String toString() { - return coyoteRequest.requestURI().toString(); + return httpRequest.requestURI().toString(); } @@ -2195,7 +2208,7 @@ public class ServletRequestImpl implements HttpServletRequest { cookiesParsed = true; - Cookies serverCookies = coyoteRequest.getCookies(); + Cookies serverCookies = httpRequest.getCookies(); int count = serverCookies.getCookieCount(); if (count <= 0) return; @@ -2271,7 +2284,7 @@ public class ServletRequestImpl implements HttpServletRequest { parametersParsed = true; - Parameters parameters = coyoteRequest.getParameters(); + Parameters parameters = httpRequest.getParameters(); // getCharacterEncoding() may have been overridden to search for // hidden form field containing request encoding @@ -2349,7 +2362,7 @@ public class ServletRequestImpl implements HttpServletRequest { String sessionCookieName = context.getSessionCookieName(); // Parse session id from cookies - Cookies serverCookies = coyoteRequest.getCookies(); + Cookies serverCookies = httpRequest.getCookies(); int count = serverCookies.getCookieCount(); if (count <= 0) return; @@ -2382,9 +2395,8 @@ public class ServletRequestImpl implements HttpServletRequest { * Parse session id in URL. */ protected void parseSessionId() { - Request req = coyoteRequest; ServletRequestImpl request = this; - ByteChunk uriBC = req.requestURI().getByteChunk(); + ByteChunk uriBC = httpRequest.requestURI().getByteChunk(); int semicolon = uriBC.indexOf(match, 0, match.length(), 0); if (semicolon > 0) { @@ -2507,4 +2519,45 @@ public class ServletRequestImpl implements HttpServletRequest { } + @Override + public boolean authenticate(HttpServletResponse response) + throws IOException, ServletException { + return false; + } + + + @Override + public Part getPart(String name) { + return null; + } + + + @Override + public Iterable getParts() { + return null; + } + + + @Override + public void login(String username, String password) throws ServletException { + } + + + @Override + public void logout() throws ServletException { + } + + + @Override + public long getAsyncTimeout() { + return 0; + } + + + @Override + public DispatcherType getDispatcherType() { + return null; + } + + } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java index 4114d1970..0ae93b1e6 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java @@ -1,5 +1,5 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one or more + * ontentLicensed 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 @@ -34,12 +34,11 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import org.apache.coyote.Response; -import org.apache.tomcat.lite.coyote.MessageWriter; import org.apache.tomcat.util.buf.CharChunk; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.buf.UEncoder; import org.apache.tomcat.util.http.FastHttpDateFormat; +import org.apache.tomcat.util.http.HttpResponse; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.http.ServerCookie; @@ -62,56 +61,23 @@ public class ServletResponseImpl "EEE, dd MMM yyyy HH:mm:ss zzz"; // ----------------------------------------------------------- Constructors - - private Response resB; + ServletResponseImpl() { urlEncoder.addSafeCharacter('/'); } - // ----------------------------------------------------- Class Variables - - - /** - * Descriptive information about this Response implementation. - */ - protected static final String info = - "org.apache.tomcat.lite/1.0"; - - - // ----------------------------------------------------- Instance Variables - /** * The date format we will use for creating date headers. */ protected SimpleDateFormat format = null; - // ------------------------------------------------------------- Properties - - - /** - * Set the Connector through which this Request was received. - * - * @param connector The new connector - */ - public void setConnector() { - // default size to size of one ajp-packet - outputBuffer = MessageWriter.getWriter(req.getCoyoteRequest(), getCoyoteResponse(), 4096); - outputStream = new ServletOutputStreamImpl(outputBuffer); - } - - /** - * Coyote response. - */ - //protected org.apache.coyote.Response coyoteResponse; - - /** * The associated output buffer. */ - protected MessageWriter outputBuffer; + protected BodyWriter outputBuffer; /** @@ -168,6 +134,11 @@ public class ServletResponseImpl /** + * The request with which this response is associated. + */ + protected ServletRequestImpl req = null; + + /** * URL encoder. */ protected UEncoder urlEncoder = new UEncoder(); @@ -179,6 +150,27 @@ public class ServletResponseImpl protected CharChunk redirectURLCC = new CharChunk(1024); + private HttpResponse resB; + + + // Cached/derived information - reflected in headers + protected static Locale DEFAULT_LOCALE = Locale.getDefault(); + + public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1"; + + protected Locale locale = DEFAULT_LOCALE; + + // XXX + protected boolean commited = false; + protected String contentType = null; + + /** + * Has the charset been explicitly set. + */ + protected boolean charsetSet = false; + protected String characterEncoding = DEFAULT_CHARACTER_ENCODING; + + // --------------------------------------------------------- Public Methods @@ -188,10 +180,10 @@ public class ServletResponseImpl */ public void recycle() { - outputBuffer.recycle(); usingOutputStream = false; usingWriter = false; appCommitted = false; + commited = false; included = false; error = false; isCharacterEncodingSet = false; @@ -199,7 +191,8 @@ public class ServletResponseImpl cookies.clear(); outputBuffer.recycle(); - + + resB.recycle(); } @@ -210,7 +203,7 @@ public class ServletResponseImpl * Return the number of bytes actually written to the output stream. */ public int getContentCount() { - return outputBuffer.getContentWritten(); + return outputBuffer.getBytesWritten() + outputBuffer.getCharsWritten(); } @@ -229,8 +222,8 @@ public class ServletResponseImpl */ public boolean isAppCommitted() { return (this.appCommitted || isCommitted() || isSuspended() - || ((getContentLength() > 0) - && (getContentCount() >= getContentLength()))); + || ((getHttpResponse().getContentLength() > 0) + && (getContentCount() >= getHttpResponse().getContentLength()))); } @@ -254,21 +247,6 @@ public class ServletResponseImpl /** - * Return descriptive information about this Response implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - return (info); - } - - - /** - * The request with which this response is associated. - */ - protected ServletRequestImpl req = null; - - /** * Return the Request with which this Response is associated. */ public ServletRequestImpl getRequest() { @@ -289,9 +267,6 @@ public class ServletResponseImpl * Return the output stream associated with this Response. */ public OutputStream getStream() { - if (outputStream == null) { - outputStream = new ServletOutputStreamImpl(outputBuffer); - } return outputStream; } @@ -351,27 +326,23 @@ public class ServletResponseImpl public ServletOutputStream createOutputStream() throws IOException { // Probably useless - if (outputStream == null) { - outputStream = new ServletOutputStreamImpl(outputBuffer); - } return outputStream; } - - /** - * Return the content length that was set or calculated for this Response. - */ - public int getContentLength() { - return getCoyoteResponse().getContentLength(); - } - - /** * Return the content type that was set or calculated for this response, * or null if no content type was set. */ public String getContentType() { - return getCoyoteResponse().getContentType(); + String ret = contentType; + + if (ret != null + && characterEncoding != null + && charsetSet) { + ret = ret + ";charset=" + characterEncoding; + } + + return ret; } @@ -426,7 +397,7 @@ public class ServletResponseImpl * Return the character encoding used for this Response. */ public String getCharacterEncoding() { - return (getCoyoteResponse().getCharacterEncoding()); + return characterEncoding; } @@ -445,19 +416,19 @@ public class ServletResponseImpl ("usingWriter"); usingOutputStream = true; - if (outputStream == null) { - outputStream = new ServletOutputStreamImpl(outputBuffer); - } return outputStream; } + public BodyWriter getBodyWriter() { + return outputBuffer; + } /** * Return the Locale assigned to this response. */ public Locale getLocale() { - return (getCoyoteResponse().getLocale()); + return locale; } @@ -503,10 +474,9 @@ public class ServletResponseImpl * Has the output of this response already been committed? */ public boolean isCommitted() { - return (getCoyoteResponse().isCommitted()); + return getHttpResponse().isCommitted(); } - /** * Clear any content written to the buffer. * @@ -518,8 +488,16 @@ public class ServletResponseImpl if (included) return; // Ignore any call from an included servlet - getCoyoteResponse().reset(); - //req.con.reset(); + if (isCommitted()) + throw new IllegalStateException("isCommitted"); + + resB.recycle(); // reset headers, status code, message + req.getConnector().reset(this); + contentType = null; + locale = DEFAULT_LOCALE; + characterEncoding = DEFAULT_CHARACTER_ENCODING; + charsetSet = false; + outputBuffer.reset(); } @@ -577,7 +555,7 @@ public class ServletResponseImpl if (usingWriter && !"ISO-8859-1".equals(getCharacterEncoding())) { return; } - getCoyoteResponse().setContentLength(length); + getHttpResponse().setContentLength(length); } @@ -606,7 +584,7 @@ public class ServletResponseImpl } } - getCoyoteResponse().setContentType(type); + getHttpResponse().setContentType(type); // Check to see if content type contains charset if (type != null) { @@ -654,7 +632,13 @@ public class ServletResponseImpl if (usingWriter) return; - getCoyoteResponse().setCharacterEncoding(charset); + if (isCommitted()) + return; + if (charset == null) + return; + + characterEncoding = charset; + charsetSet=true; isCharacterEncodingSet = true; } @@ -675,7 +659,25 @@ public class ServletResponseImpl if (included) return; - getCoyoteResponse().setLocale(locale); + if (locale == null) { + return; // throw an exception? + } + + // Save the locale for use by getLocale() + this.locale = locale; + + // Set the contentLanguage for header output + String contentLanguage = locale.getLanguage(); + if ((contentLanguage != null) && (contentLanguage.length() > 0)) { + String country = locale.getCountry(); + StringBuffer value = new StringBuffer(contentLanguage); + if ((country != null) && (country.length() > 0)) { + value.append('-'); + value.append(country); + } + contentLanguage = value.toString(); + } + resB.setHeader("Content-Language", contentLanguage); // Ignore any call made after the getWriter has been invoked. // The default should be used @@ -689,7 +691,7 @@ public class ServletResponseImpl Locale2Charset cm = req.getContext().getCharsetMapper(); String charset = cm.getCharset( locale ); if ( charset != null ){ - getCoyoteResponse().setCharacterEncoding(charset); + setCharacterEncoding(charset); } } @@ -716,7 +718,7 @@ public class ServletResponseImpl * @param name Header name to look up */ public String getHeader(String name) { - return getCoyoteResponse().getMimeHeaders().getHeader(name); + return getHttpResponse().getMimeHeaders().getHeader(name); } @@ -724,16 +726,15 @@ public class ServletResponseImpl * Return an array of all the header names set for this response, or * a zero-length array if no headers have been set. */ - public String[] getHeaderNames() { + public Iterable getHeaderNames() { - MimeHeaders headers = getCoyoteResponse().getMimeHeaders(); + MimeHeaders headers = getHttpResponse().getMimeHeaders(); int n = headers.size(); - String[] result = new String[n]; + ArrayList result = new ArrayList(); for (int i = 0; i < n; i++) { - result[i] = headers.getName(i).toString(); + result.add(headers.getName(i).toString()); } return result; - } @@ -746,7 +747,7 @@ public class ServletResponseImpl */ public String[] getHeaderValues(String name) { - Enumeration enumeration = getCoyoteResponse().getMimeHeaders().values(name); + Enumeration enumeration = getHttpResponse().getMimeHeaders().values(name); Vector result = new Vector(); while (enumeration.hasMoreElements()) { result.addElement(enumeration.nextElement()); @@ -763,7 +764,7 @@ public class ServletResponseImpl * for this Response. */ public String getMessage() { - return getCoyoteResponse().getMessage(); + return getHttpResponse().getMessage(); } @@ -771,7 +772,7 @@ public class ServletResponseImpl * Return the HTTP status code associated with this Response. */ public int getStatus() { - return getCoyoteResponse().getStatus(); + return getHttpResponse().getStatus(); } @@ -864,7 +865,7 @@ public class ServletResponseImpl if (included) return; - getCoyoteResponse().addHeader(name, value); + getHttpResponse().addHeader(name, value); } @@ -901,15 +902,15 @@ public class ServletResponseImpl if(cc=='C' || cc=='c') { if(name.equalsIgnoreCase("Content-Type")) { // Will return null if this has not been set - return (getCoyoteResponse().getContentType() != null); + return getContentType() != null; } if(name.equalsIgnoreCase("Content-Length")) { // -1 means not known and is not sent to client - return (getCoyoteResponse().getContentLengthLong() != -1); + return (getHttpResponse().getContentLength() != -1); } } - return getCoyoteResponse().containsHeader(name); + return getHttpResponse().containsHeader(name); } @@ -995,8 +996,7 @@ public class ServletResponseImpl if (included) return; - getCoyoteResponse().acknowledge(); - + req.getConnector().acknowledge(this); } @@ -1039,8 +1039,8 @@ public class ServletResponseImpl setError(); - getCoyoteResponse().setStatus(status); - getCoyoteResponse().setMessage(message); + getHttpResponse().setStatus(status); + getHttpResponse().setMessage(message); // Clear any data content that has been buffered resetBuffer(); @@ -1156,7 +1156,7 @@ public class ServletResponseImpl if (included) return; - getCoyoteResponse().setHeader(name, value); + getHttpResponse().setHeader(name, value); } @@ -1210,8 +1210,8 @@ public class ServletResponseImpl if (included) return; - getCoyoteResponse().setStatus(status); - getCoyoteResponse().setMessage(message); + getHttpResponse().setStatus(status); + getHttpResponse().setMessage(message); } @@ -1425,23 +1425,35 @@ public class ServletResponseImpl return outputBuffer.getBytesWritten(); } - public MessageWriter getOutputBuffer() { + public BodyWriter getOutputBuffer() { return outputBuffer; } + + public void setWriter(BodyWriter ob) { + outputBuffer = ob; + outputStream = new ServletOutputStreamImpl(outputBuffer); + } public CharSequence getResponseHeader(String name) { - MessageBytes v = getCoyoteResponse().getMimeHeaders().getValue(name); + MessageBytes v = getHttpResponse().getMimeHeaders().getValue(name); return (v == null) ? null : v.toString(); } - public Response getCoyoteResponse() { + public HttpResponse getHttpResponse() { return resB; } - public void setCoyoteResponse(Response resB) { + public void setHttpResponse(HttpResponse resB, BodyWriter ob) { this.resB = resB; + setWriter(ob); + } + + + @Override + public Iterable getHeaders(String name) { + return null; } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/TomcatLite.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/TomcatLite.java index 5ddd9cde2..b01220543 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/TomcatLite.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/TomcatLite.java @@ -89,7 +89,7 @@ public class TomcatLite implements Runnable { Map ctxDefaultInitParam = new HashMap(); - Connector coyoteAdapter; + Connector connector; ObjectManager om; @@ -106,7 +106,12 @@ public class TomcatLite implements Runnable { } // --------------- start/stop --------------- - + + public static ObjectManager defaultObjectManager() { + SimpleObjectManager cfg = new SimpleObjectManager(); + cfg.loadResource("org/apache/tomcat/lite/config.properties"); + return cfg; + } /** * Return the object manager associated with this tomcat. * If none set, create a minimal one with the default @@ -114,12 +119,7 @@ public class TomcatLite implements Runnable { */ public ObjectManager getObjectManager() { if (om == null) { - // Defaults. - om = new ObjectManager(); - SimpleObjectManager props = new SimpleObjectManager(om); - // Init defaults. If using a custom OM, you should register - // at the default objects as well. - props.loadResource("org/apache/tomcat/lite/config.properties"); + om = defaultObjectManager(); } return om; } @@ -223,7 +223,12 @@ public class TomcatLite implements Runnable { e.printStackTrace(); } } - stopConnector(); + try { + stopConnector(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } // -------------- Context add/remove -------------- @@ -309,9 +314,9 @@ public class TomcatLite implements Runnable { req.parseSessionId(); try { - UriNormalizer.decodeRequest(req.getCoyoteRequest().decodedURI(), - req.getCoyoteRequest().requestURI(), - req.getCoyoteRequest().getURLDecoder()); + UriNormalizer.decodeRequest(req.getHttpRequest().decodedURI(), + req.getHttpRequest().requestURI(), + req.getHttpRequest().getURLDecoder()); } catch(IOException ioe) { res.setStatus(400); return; @@ -336,7 +341,7 @@ public class TomcatLite implements Runnable { Thread.currentThread().setContextClassLoader(ctx.getClassLoader()); WebappServletMapper mapper = ctx.getMapper(); - mapper.map(req.getCoyoteRequest().decodedURI(), mapRes); + mapper.map(req.getHttpRequest().decodedURI(), mapRes); // Possible redirect MessageBytes redirectPathMB = mapRes.redirectPath; @@ -548,8 +553,8 @@ public class TomcatLite implements Runnable { getConnector().initRequest(req, res); - req.getCoyoteRequest().method().setString("GET"); - req.getCoyoteRequest().protocol().setString("HTTP/1.1"); + req.getHttpRequest().method().setString("GET"); + req.getHttpRequest().protocol().setString("HTTP/1.1"); return req; } @@ -585,42 +590,41 @@ public class TomcatLite implements Runnable { public void endRequest(ServletRequestImpl req, ServletResponseImpl res) throws IOException { res.outputBuffer.flush(); - res.getCoyoteResponse().finish(); + req.getConnector().finishResponse(res); } public Connector getConnector() { - if (coyoteAdapter == null) { - coyoteAdapter = (Connector) getObjectManager().get(Connector.class); - setConnector(coyoteAdapter); + if (connector == null) { + connector = (Connector) getObjectManager().get(Connector.class); + setConnector(connector); } - return coyoteAdapter; + return connector; } public void setConnector(Connector c) { - coyoteAdapter = c; - coyoteAdapter.setTomcatLite(this); - getObjectManager().bind("Connector", coyoteAdapter); + connector = c; + connector.setTomcatLite(this); + getObjectManager().bind("Connector", connector); } public void setDaemon(boolean d) { getConnector(); - if (coyoteAdapter != null) { - coyoteAdapter.setDaemon(d); + if (connector != null) { + connector.setDaemon(d); } } - public void startConnector() { + public void startConnector() throws IOException { getConnector(); - if (coyoteAdapter != null) { - coyoteAdapter.start(); + if (connector != null) { + connector.start(); } } - public void stopConnector() { - getConnector(); - if (coyoteAdapter != null) { - coyoteAdapter.stop(); + public void stopConnector() throws Exception { + if (connector != null) { + connector.stop(); } } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/cli/Main.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/cli/Main.java deleted file mode 100644 index 3abe1f482..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/cli/Main.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.lite.cli; - -import org.apache.tomcat.integration.ObjectManager; -import org.apache.tomcat.integration.jmx.JmxObjectManagerSpi; -import org.apache.tomcat.integration.simple.SimpleObjectManager; -import org.apache.tomcat.lite.TomcatLite; -import org.apache.tomcat.lite.coyote.CoyoteHttp; - -/** - * Run tomcat lite, mostly for demo. In normal use you would - * embed it in an app, or use a small customized launcher. - * - * With no arguments, it'll load only the root context / from - * ./webapps/ROOT - * - * Most configuration can be done using web.xml files, few settings - * can be set by flags. - * - * @author Costin Manolache - */ -public class Main { - - public static void main(String args[]) - throws Exception { - - if (args.length == 0) { - System.err.println("Please specify at least one webapp."); - System.err.println("Example:"); - System.err.println("-context /:webapps/ROOT -port 9999"); - } - - // Enable CLI processing - SimpleObjectManager.setArgs(args); - - TomcatLite lite = new TomcatLite(); - ObjectManager om = lite.getObjectManager(); - - // add JMX support - new JmxObjectManagerSpi().register(om); - - lite.run(); - } -} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/config.properties b/modules/tomcat-lite/java/org/apache/tomcat/lite/config.properties index c6e43e1d3..c1ef53d41 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/config.properties +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/config.properties @@ -2,6 +2,10 @@ # If tomcat is used with a proper framework, you need to bind and configure # those objects in the framework. +Main.(class)=org.apache.tomcat.lite.TomcatLite + +Jmx.(class)=org.apache.tomcat.integration.jmx.JmxObjectManagerSpi + # --- Class names for required plugin interfaces --- org.apache.tomcat.lite.WebappServletMapper.(class)=org.apache.tomcat.lite.WebappServletMapper @@ -13,16 +17,23 @@ org.apache.tomcat.addons.UserSessionManager.(class)=org.apache.tomcat.servlets.s # *.jsp support org.apache.tomcat.addons.UserTemplateClassMapper.(class)=org.apache.tomcat.servlets.jsp.JasperCompilerTemplateClassMapper +org.apache.tomcat.addons.Filesystem.(class)=org.apache.tomcat.integration.simple.LocalFilesystem + # Loader for web.xml - you can have your own custom class using a more efficient # or hardcoded. org.apache.tomcat.lite.ContextPreinitListener.(class)=org.apache.tomcat.lite.webxml.TomcatLiteWebXmlConfig # Connector class -org.apache.tomcat.lite.Connector.(class)=org.apache.tomcat.lite.coyote.CoyoteHttp +org.apache.tomcat.lite.Connector.(class)=org.apache.tomcat.lite.coyote.CoyoteConnector + +# JMX +jmx-connector.(class)=org.apache.tomcat.integration.jmx.JmxObjectManagerSpi # --- Other required settings --- # Customize default and *.jsp mappings default-servlet.(class)=org.apache.tomcat.servlets.file.WebdavServlet jspwildcard-servlet.(class)=org.apache.tomcat.servlets.jsp.WildcardTemplateServlet +filetemplate-servlet.(class)=org.apache.tomcat.servlets.jsp.JspFileTemplateServlet + diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/ClientAbortException.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/ClientAbortException.java deleted file mode 100644 index 2155adf7b..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/ClientAbortException.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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.lite.coyote; - -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$ $Date$ - */ - -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()); - - } - - -} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteConnector.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteConnector.java new file mode 100644 index 000000000..88669e53e --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteConnector.java @@ -0,0 +1,465 @@ +/* + */ +package org.apache.tomcat.lite.coyote; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.ActionHook; +import org.apache.coyote.Adapter; +import org.apache.coyote.ProtocolHandler; +import org.apache.coyote.Request; +import org.apache.coyote.Response; +import org.apache.coyote.http11.Http11NioProtocol; +import org.apache.tomcat.integration.ObjectManager; +import org.apache.tomcat.lite.BodyReader; +import org.apache.tomcat.lite.BodyWriter; +import org.apache.tomcat.lite.ClientAbortException; +import org.apache.tomcat.lite.Connector; +import org.apache.tomcat.lite.ServletRequestImpl; +import org.apache.tomcat.lite.ServletResponseImpl; +import org.apache.tomcat.lite.TomcatLite; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.UriNormalizer; +import org.apache.tomcat.util.http.HttpRequest; +import org.apache.tomcat.util.http.HttpResponse; +import org.apache.tomcat.util.net.SocketStatus; + +public class CoyoteConnector implements Adapter, Connector { + + private TomcatLite lite; + + public CoyoteConnector() { + } + + + + public void acknowledge(HttpServletResponse res) throws IOException { + Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse; + cres.acknowledge(); + } + + public void reset(HttpServletResponse res) { + Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse; + cres.reset(); + } + + public void recycle(HttpServletRequest req, HttpServletResponse res) { + + } + + public static HttpResponse getResponse(final Response cres) { + HttpResponse hres = new HttpResponse() { + public int getStatus() { + return cres.getStatus(); + } + public void setStatus(int i) { + super.setStatus(i); + cres.setStatus(i); + } + public void setMessage(String s) { + super.setMessage(s); + cres.setMessage(s); + } + public String getMessage() { + return cres.getMessage(); + } + public boolean isCommitted() { + return cres.isCommitted(); + } + + public void setCommitted(boolean b) { + cres.setCommitted(b); + } + }; + + hres.setMimeHeaders(cres.getMimeHeaders()); + hres.nativeResponse = cres; + + return hres; + } + + public static HttpRequest getRequest(Request req) { + + HttpRequest httpReq = new HttpRequest(req.scheme(), + req.method(), + req.unparsedURI(), + req.protocol(), + req.getMimeHeaders(), + req.requestURI(), + req.decodedURI(), + req.query(), req.getParameters(), + req.serverName(), + req.getCookies()) { + + }; + httpReq.nativeRequest = req; + + // TODO: anything else computed in coyote ? + + return httpReq; + } + + @Override + public void initRequest(HttpServletRequest hreq, HttpServletResponse hres) { + ServletRequestImpl req = (ServletRequestImpl) hreq; + ServletResponseImpl res = (ServletResponseImpl) hres; + req.setConnector(this); + + Request creq = new Request(); + Response cres = new Response(); + HttpResponse nRes = getResponse(cres); + + BodyWriter out = new BodyWriter(4096); + out.setConnector(this, res); + + res.setHttpResponse(nRes, out); + + cres.setRequest(creq); + cres.setHook(new ActionHook() { + public void action(ActionCode actionCode, + Object param) { + } + }); + + BodyReader in = new BodyReader(); + in.setConnector(this, req); + HttpRequest nReq = getRequest(creq); + req.setHttpRequest(nReq, in); + + } + + + // ---- Coyote Adapter interface --- + + @Override + public void service(Request creq, Response cres) throws Exception { + long t0 = System.currentTimeMillis(); + + // compute decodedURI - not done by connector + UriNormalizer.decodeRequest(creq.decodedURI(), creq.requestURI(), creq.getURLDecoder()); + + // find the facades + ServletRequestImpl req = (ServletRequestImpl) creq.getNote(ADAPTER_REQ_NOTE); + ServletResponseImpl res = (ServletResponseImpl) cres.getNote(ADAPTER_RES_NOTE); + + + if (req == null) { + req = new ServletRequestImpl(); + res = req.getResponse(); + + BodyReader in = new BodyReader(); + in.setConnector(this, req); + + HttpRequest nReq = getRequest(creq); + nReq.setServerPort(creq.getServerPort()); + HttpResponse nRes = getResponse(cres); + + req.setHttpRequest(nReq, in); + BodyWriter out = new BodyWriter(4096); + out.setConnector(this, res); + + res.setHttpResponse(nRes, out); + + creq.setNote(ADAPTER_REQ_NOTE, req); + cres.setNote(ADAPTER_RES_NOTE, res); + + } + req.setConnector(this); + + try { + lite.service(req, res); + } catch(IOException ex) { + throw ex; + } catch( Throwable t ) { + t.printStackTrace(); + } finally { + long t1 = System.currentTimeMillis(); + +// log.info("<<<<<<<< DONE: " + creq.method() + " " + +// creq.decodedURI() + " " + +// res.getStatus() + " " + +// (t1 - t0)); + + // Final processing + // TODO: only if not commet, this doesn't work with the + // other connectors since we don't have the info + // TODO: add this note in the nio/apr connectors + // TODO: play nice with TomcatLite, other adapters that flush/close + if (cres.getNote(COMET_RES_NOTE) == null) { + + if (!res.isCommitted()) { + cres.sendHeaders(); + } + res.getOutputBuffer().flush(); + + BodyWriter mw = res.getBodyWriter(); + //MessageWriter.getWriter(creq, cres, 0); + mw.flush(); + mw.recycle(); + + BodyReader reader = req.getBodyReader(); + //getReader(creq); + reader.recycle(); + + cres.finish(); + + creq.recycle(); + cres.recycle(); + + req.recycle(); + res.recycle(); + } + } + } + + @Override + public boolean event(Request req, Response res, SocketStatus status) + throws Exception { + return false; + } + + + public void setTomcatLite(TomcatLite lite) { + this.lite = lite; + } + + + public String getRemoteHost(HttpServletRequest hreq) { + ServletRequestImpl req = (ServletRequestImpl) hreq; + + Request creq = (Request) req.getHttpRequest().nativeRequest; + creq.action(ActionCode.ACTION_REQ_HOST_ATTRIBUTE, creq); + return creq.remoteHost().toString(); + } + + public String getRemoteAddr(HttpServletRequest hreq) { + ServletRequestImpl req = (ServletRequestImpl) hreq; + + Request creq = (Request) req.getHttpRequest().nativeRequest; + creq.action(ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, creq); + return creq.remoteAddr().toString(); + } + + + @Override + public void beforeClose(HttpServletResponse res, int len) throws IOException { + Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse; + + if ((!cres.isCommitted()) + && (cres.getContentLengthLong() == -1)) { + // Flushing the char buffer + // If this didn't cause a commit of the response, the final content + // length can be calculated + if (!cres.isCommitted()) { + cres.setContentLength(len); + } + } + } + + public int doRead(ServletRequestImpl hreq, ByteChunk bb) throws IOException { + ServletRequestImpl req = (ServletRequestImpl) hreq; + + Request creq = (Request) req.getHttpRequest().nativeRequest; + return creq.doRead(bb); + } + + @Override + public void doWrite(HttpServletResponse res, ByteChunk chunk) + throws IOException { + Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse; + cres.doWrite(chunk); + + } + + + @Override + public void realFlush(HttpServletResponse res) throws IOException { + Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse; + cres.action(ActionCode.ACTION_CLIENT_FLUSH, + cres); + // If some exception occurred earlier, or if some IOE occurred + // here, notify the servlet with an IOE + if (cres.isExceptionPresent()) { + throw new ClientAbortException + (cres.getErrorException()); + } + + } + + + @Override + public void sendHeaders(HttpServletResponse res) throws IOException { + Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse; + + // This should happen before 'prepareResponse' is called !! + // Now update coyote response based on response + // don't set charset/locale - they're computed in lite + cres.setContentType(res.getContentType()); + cres.sendHeaders(); + } + + @Override + public void finishResponse(HttpServletResponse res) throws IOException { + Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse; + cres.finish(); + } + + protected int port = 8800; + protected boolean daemon = false; + + /** + * Note indicating the response is COMET. + */ + public static final int COMET_RES_NOTE = 2; + public static final int COMET_REQ_NOTE = 2; + + public static final int ADAPTER_RES_NOTE = 1; + public static final int ADAPTER_REQ_NOTE = 1; + + protected ProtocolHandler proto; + + //protected Adapter adapter = new MapperAdapter(); + protected int maxThreads = 20; + boolean started = false; + boolean async = false; // use old nio connector + + protected ObjectManager om; + + + public void setObjectManager(ObjectManager om) { + this.om = om; + } + + /** + * 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 ("/".equals(path)) { +// ((MapperAdapter) adapter).setDefaultAdapter(added); +// } else { +// ((MapperAdapter) adapter).getMapper().addWrapper(path, added); +// } +// } + + /** + */ + public void run() { + try { + init(); + start(); + } catch(IOException ex) { + ex.printStackTrace(); + } + } + + public void setDaemon(boolean b) { + daemon = b; + } + + protected void initAdapters() { + if (proto == null) { + addProtocolHandler(port, daemon); + } + // adapter = ... + // Adapter secondaryadapter = ... + //registry.registerComponent(secondaryadapter, ":name=adapter", null); + } + + public void stop() throws Exception { + if (!started) { + return; + } + proto.destroy(); + started = false; + } + +// /** +// * 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 setConnector(ProtocolHandler h) { + this.proto = h; + h.setAttribute("port", Integer.toString(port)); + + om.bind("ProtocolHandler:" + "ep-" + port, proto); + } + + public void addProtocolHandler(int port, boolean daemon) { + Http11NioProtocol proto = new Http11NioProtocol(); + proto.setCompression("on"); + proto.setCompressionMinSize(32); + proto.setPort(port); + proto.getEndpoint().setDaemon(daemon); + setConnector(proto); + setPort(port); + setDaemon(daemon); + } + + public void addProtocolHandler(ProtocolHandler proto, + int port, boolean daemon) { + setConnector(proto); + setPort(port); + setDaemon(daemon); + } + + public void setPort(int port) { + if (proto != null) { + proto.setAttribute("port", Integer.toString(port)); + } + this.port = port; + } + + + public void init() { + //JdkLoggerConfig.loadCustom(); + om.bind("CoyoteConnector:" + "CoyoteConnector-" + port, + this); + } + + + public void start() throws IOException { + try { + if (started) { + return; + } + init(); + initAdapters(); + + // not required - should run fine without a connector. + if (proto != null) { + proto.setAdapter(this); + + proto.init(); + proto.start(); + } + + started = true; + } catch (Throwable e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public boolean getStarted() { + return started; + } + +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteHttp.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteHttp.java deleted file mode 100644 index 722eca1d0..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteHttp.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - */ -package org.apache.tomcat.lite.coyote; - -import java.io.IOException; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.ActionHook; -import org.apache.coyote.Adapter; -import org.apache.coyote.Request; -import org.apache.coyote.Response; -import org.apache.tomcat.integration.ObjectManager; -import org.apache.tomcat.lite.Connector; -import org.apache.tomcat.lite.ServletRequestImpl; -import org.apache.tomcat.lite.ServletResponseImpl; -import org.apache.tomcat.lite.TomcatLite; -import org.apache.tomcat.util.net.SocketStatus; - -public class CoyoteHttp implements Adapter, Connector { - - //private TomcatLite lite; - CoyoteServer coyote; - private TomcatLite lite; - - public CoyoteHttp() { - } - - - @Override - public void finishResponse(HttpServletResponse res) throws IOException { - ((ServletResponseImpl) res).getCoyoteResponse().finish(); - } - - - public void recycle(HttpServletRequest req, HttpServletResponse res) { - - } - - public void setPort(int port) { - if (getConnectors() != null) { - coyote.setPort(port); - } - } - - @Override - public void setDaemon(boolean b) { - if (getConnectors() != null) { - coyote.setDaemon(b); - } - } - - - @Override - public void start() { - if (getConnectors() != null) { - try { - coyote.init(); - coyote.start(); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - - - - @Override - public void stop() { - if (coyote != null) { - try { - coyote.stop(); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - - @Override - public void initRequest(HttpServletRequest hreq, HttpServletResponse hres) { - ServletRequestImpl req = (ServletRequestImpl) hreq; - ServletResponseImpl res = (ServletResponseImpl) hres; - - Request creq = new Request(); - res.setCoyoteResponse(new Response()); - res.getCoyoteResponse().setRequest(creq); - res.getCoyoteResponse().setHook(new ActionHook() { - public void action(ActionCode actionCode, - Object param) { - } - }); - - req.setCoyoteRequest(creq); - - res.setConnector(); - - } - - // Coyote-specific hooking. - // This could be moved out to a separate class, TomcatLite can - // work without it. - public CoyoteServer getConnectors() { - if (coyote == null) { - coyote = new CoyoteServer(); - coyote.addAdapter("/", this); - } - return coyote; - } - - public void setConnectors(CoyoteServer server) { - this.coyote = server; - coyote.addAdapter("/", this); - } - - @Override - public void service(Request req, Response res) throws Exception { - // find the facades - ServletRequestImpl sreq = (ServletRequestImpl) req.getNote(CoyoteServer.ADAPTER_REQ_NOTE); - ServletResponseImpl sres = (ServletResponseImpl) res.getNote(CoyoteServer.ADAPTER_RES_NOTE); - if (sreq == null) { - sreq = new ServletRequestImpl(); - sres = sreq.getResponse(); - - sreq.setCoyoteRequest(req); - sres.setCoyoteResponse(res); - - req.setNote(CoyoteServer.ADAPTER_REQ_NOTE, sreq); - res.setNote(CoyoteServer.ADAPTER_RES_NOTE, sres); - - sres.setConnector(); - - } - - lite.service(sreq, sres); - - if (res.getNote(CoyoteServer.COMET_RES_NOTE) == null) { - if (!sres.isCommitted()) { - res.sendHeaders(); - } - sres.getOutputBuffer().flush(); - res.finish(); - - sreq.recycle(); - sres.recycle(); - } - } - - // ---- Coyote --- - - @Override - public boolean event(Request req, Response res, SocketStatus status) - throws Exception { - return false; - } - - - public void setTomcatLite(TomcatLite lite) { - this.lite = lite; - } - - - @Override - public void setObjectManager(ObjectManager objectManager) { - getConnectors(); - coyote.setObjectManager(objectManager); - } - - - -} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteServer.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteServer.java deleted file mode 100644 index 17c1e62b5..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteServer.java +++ /dev/null @@ -1,188 +0,0 @@ -/* 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.lite.coyote; - -import java.io.IOException; - -import org.apache.coyote.Adapter; -import org.apache.coyote.ProtocolHandler; -import org.apache.coyote.http11.Http11NioProtocol; -import org.apache.tomcat.integration.ObjectManager; - - -/** - * Simple example of embeding coyote servlet. - * - */ -public class CoyoteServer { - protected int port = 8800; - protected boolean daemon = false; - - /** - * Note indicating the response is COMET. - */ - public static final int COMET_RES_NOTE = 2; - public static final int COMET_REQ_NOTE = 2; - - public static final int ADAPTER_RES_NOTE = 1; - public static final int ADAPTER_REQ_NOTE = 1; - - protected ProtocolHandler proto; - - protected Adapter adapter = new MapperAdapter(); - protected int maxThreads = 20; - boolean started = false; - boolean async = false; // use old nio connector - - protected ObjectManager om; - - public CoyoteServer() { - } - - public void setObjectManager(ObjectManager om) { - this.om = om; - } - - /** - * 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 ("/".equals(path)) { - ((MapperAdapter) adapter).setDefaultAdapter(added); - } else { - ((MapperAdapter) adapter).getMapper().addWrapper(path, added); - } - } - - /** - */ - public void run() { - try { - init(); - start(); - } catch(IOException ex) { - ex.printStackTrace(); - } - } - - public void setDaemon(boolean b) { - daemon = b; - } - - public void init() { - //JdkLoggerConfig.loadCustom(); - om.bind("CoyoteServer:" + "CoyoteServer-" + port, - this); - om.bind("CoyoteAdapter", adapter); - } - - protected void initAdapters() { - if (proto == null) { - addProtocolHandler(port, daemon); - } - // adapter = ... - // Adapter secondaryadapter = ... - //registry.registerComponent(secondaryadapter, ":name=adapter", null); - } - - public void stop() throws Exception { - if (!started) { - return; - } - proto.destroy(); - started = false; - } - - /** - * 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(int port) { - if (proto != null) { - proto.setAttribute("port", Integer.toString(port)); - } - this.port = port; - } - - public void setConnector(ProtocolHandler h) { - this.proto = h; - h.setAttribute("port", Integer.toString(port)); - - om.bind("ProtocolHandler:" + "ep-" + port, proto); - } - - public void addProtocolHandler(int port, boolean daemon) { - Http11NioProtocol proto = new Http11NioProtocol(); - proto.setCompression("on"); - proto.setCompressionMinSize(32); - proto.setPort(port); - proto.getEndpoint().setDaemon(daemon); - CoyoteServer server = this; - server.setConnector(proto); - server.setPort(port); - server.setDaemon(daemon); - } - - public void addProtocolHandler(ProtocolHandler proto, - int port, boolean daemon) { - CoyoteServer server = this; - server.setConnector(proto); - server.setPort(port); - server.setDaemon(daemon); - } - - - - public void start() throws IOException { - try { - if (started) { - return; - } - initAdapters(); - - // not required - should run fine without a connector. - if (proto != null) { - proto.setAdapter(adapter); - - proto.init(); - proto.start(); - } - - started = true; - } catch (Throwable e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - - public boolean getStarted() { - return started; - } -} \ No newline at end of file diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteUtils.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteUtils.java deleted file mode 100644 index e97a450b7..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteUtils.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - */ -package org.apache.tomcat.lite.coyote; - -import java.io.IOException; - -import org.apache.coyote.Request; -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.http.mapper.MappingData; - -public class CoyoteUtils { - static ByteChunk space = new ByteChunk(1); - static ByteChunk col = new ByteChunk(1); - static ByteChunk crlf = new ByteChunk(2); - static { - try { - space.append(' '); - col.append(':'); - crlf.append('\r'); - crlf.append('\n'); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - public static String getContextPath(Request request) { - MappingData md = MapperAdapter.getMappingData(request); - String ctxPath = (md.contextPath.isNull()) ? "/" : - md.contextPath.toString(); - return ctxPath; - } - - public static String getPathInfo(Request request) { - MappingData md = MapperAdapter.getMappingData(request); - String ctxPath = (md.pathInfo.isNull()) ? "/" : - md.pathInfo.toString(); - return ctxPath; - } - public static String getServletPath(Request request) { - MappingData md = MapperAdapter.getMappingData(request); - String ctxPath = (md.wrapperPath.isNull()) ? "/" : - md.wrapperPath.toString(); - return ctxPath; - } - - // TODO: collate all notes in a signle file - static int READER_NOTE = 5; - - public static MessageReader getReader(Request req) { - MessageReader r = (MessageReader) req.getNote(READER_NOTE); - if (r == null) { - r = new MessageReader(); - r.setRequest(req); - req.setNote(READER_NOTE, r); - } - return r; - } - - /** - * Convert the request to bytes, ready to send. - */ - public static void serializeRequest(Request req, - ByteChunk reqBuf) throws IOException { - req.method().toBytes(); - if (!req.unparsedURI().isNull()) { - req.unparsedURI().toBytes(); - } - req.protocol().toBytes(); - - reqBuf.append(req.method().getByteChunk()); - reqBuf.append(space); - if (req.unparsedURI().isNull()) { - req.requestURI().toBytes(); - - reqBuf.append(req.requestURI().getByteChunk()); - } else { - reqBuf.append(req.unparsedURI().getByteChunk()); - } - reqBuf.append(space); - reqBuf.append(req.protocol().getByteChunk()); - reqBuf.append(crlf); - // Headers - MimeHeaders mimeHeaders = req.getMimeHeaders(); - boolean hasHost = false; - for (int i = 0; i < mimeHeaders.size(); i++) { - MessageBytes name = mimeHeaders.getName(i); - name.toBytes(); - reqBuf.append(name.getByteChunk()); - if (name.equalsIgnoreCase("host")) { - hasHost = true; - } - reqBuf.append(col); - mimeHeaders.getValue(i).toBytes(); - reqBuf.append(mimeHeaders.getValue(i).getByteChunk()); - reqBuf.append(crlf); - } - if (!hasHost) { - reqBuf.append("Host: localhost\r\n".getBytes(), 0, 17); - } - reqBuf.append(crlf); - } - - -} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/MapperAdapter.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/MapperAdapter.java deleted file mode 100644 index 78ad37f39..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/MapperAdapter.java +++ /dev/null @@ -1,139 +0,0 @@ -/* 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.lite.coyote; - -import java.io.IOException; -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.UriNormalizer; -import org.apache.tomcat.util.http.mapper.BaseMapper; -import org.apache.tomcat.util.http.mapper.MappingData; -import org.apache.tomcat.util.net.SocketStatus; - -/** - * - */ -public class MapperAdapter implements Adapter { - - private BaseMapper mapper=new BaseMapper(); - - static Logger log = Logger.getLogger("Mapper"); - static final int MAP_NOTE = 4; - - public MapperAdapter() { - mapper.setDefaultHostName("localhost"); - mapper.setContext("", new String[] {"index.html"}, - null); - } - - public MapperAdapter(BaseMapper mapper2) { - mapper = mapper2; - } - - public static MappingData getMappingData(Request req) { - MappingData md = (MappingData) req.getNote(MAP_NOTE); - if (md == null) { - md = new MappingData(); - req.setNote(MAP_NOTE, md); - } - return md; - } - - /** - * 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 { - long t0 = System.currentTimeMillis(); - try { - // compute decodedURI - not done by connector - UriNormalizer.decodeRequest(req.decodedURI(), req.requestURI(), req.getURLDecoder()); - MappingData mapRes = getMappingData(req); - mapRes.recycle(); - - mapper.map(req.requestURI(), mapRes); - - Adapter h=(Adapter)mapRes.wrapper; - - if (h != null) { - log.info(">>>>>>>> START: " + req.method() + " " + - req.decodedURI() + " " + - h.getClass().getSimpleName()); - h.service( req, res ); - } else { - res.setStatus(404); - } - } catch(IOException ex) { - throw ex; - } catch( Throwable t ) { - t.printStackTrace(); - } finally { - long t1 = System.currentTimeMillis(); - - log.info("<<<<<<<< DONE: " + req.method() + " " + - req.decodedURI() + " " + - res.getStatus() + " " + - (t1 - t0)); - - // Final processing - // TODO: only if not commet, this doesn't work with the - // other connectors since we don't have the info - // TODO: add this note in the nio/apr connectors - // TODO: play nice with TomcatLite, other adapters that flush/close - if (res.getNote(CoyoteServer.COMET_RES_NOTE) == null) { - MessageWriter mw = MessageWriter.getWriter(req, res, 0); - mw.flush(); - mw.recycle(); - MessageReader reader = CoyoteUtils.getReader(req); - reader.recycle(); - res.finish(); - - req.recycle(); - res.recycle(); - } - } - } - - public BaseMapper 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 diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/MessageReader.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/MessageReader.java deleted file mode 100644 index 5215e5d90..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/MessageReader.java +++ /dev/null @@ -1,519 +0,0 @@ -/* - * 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.lite.coyote; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -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. More data may be added to it while reading. - */ - private ByteChunk bb; - - - /** - * The chunk buffer, will be filled in from the bb. - */ - 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; - - /** - * Encoding to use. - */ - private String enc; - - - /** - * Encoder is set. - */ - private boolean gotEnc = false; - - - /** - * Cached 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; - } - - /** - * Called when a read(char[]) operation is lacking data. It will read - * bytes. - */ - 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, -1); - 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(); - } - } - - - 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) { - conv = new B2CConverter(enc); - encoders.put(enc, conv); - } - } - - public class MRInputStream extends InputStream { - public long skip(long n) - throws IOException { - return MessageReader.this.skip(n); - } - - public void mark(int readAheadLimit) - { - try { - MessageReader.this.mark(readAheadLimit); - } catch (IOException e) { - e.printStackTrace(); - } - } - - - public void reset() - throws IOException { - MessageReader.this.reset(); - } - - - - public int read() - throws IOException { - return MessageReader.this.readByte(); - } - - public int available() throws IOException { - return MessageReader.this.available(); - } - - public int read(final byte[] b) throws IOException { - return MessageReader.this.read(b, 0, b.length); - } - - - public int read(final byte[] b, final int off, final int len) - throws IOException { - - return MessageReader.this.read(b, off, len); - } - - - /** - * Close the stream - * Since we re-cycle, we can't allow the call to super.close() - * which would permantely disable us. - */ - public void close() throws IOException { - MessageReader.this.close(); - } - } - - MRInputStream is = new MRInputStream(); - - public InputStream asInputStream() { - return is; - } -} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/MessageWriter.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/MessageWriter.java deleted file mode 100644 index f53e53446..000000000 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/MessageWriter.java +++ /dev/null @@ -1,694 +0,0 @@ -/* - * 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.lite.coyote; - - -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; - -/* - * 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 println() throws IOException { - write("\n"); - } - - public void println(String s) throws IOException { - write(s); - write("\n"); - } - - public void print(String s) throws IOException { - write(s); - } - - 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; - } - - public ByteChunk getByteBuffer() { - return outputChunk; - } - -} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/TomcatLiteWebXmlConfig.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/TomcatLiteWebXmlConfig.java index dff9e3479..fe2673ea6 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/TomcatLiteWebXmlConfig.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/TomcatLiteWebXmlConfig.java @@ -5,8 +5,8 @@ package org.apache.tomcat.lite.webxml; import javax.servlet.ServletContext; import javax.servlet.ServletException; -import org.apache.tomcat.lite.ServletContextImpl; import org.apache.tomcat.lite.ContextPreinitListener; +import org.apache.tomcat.lite.ServletContextImpl; /** * Default configurator - parse web.xml, init the context. diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/WebXml.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/WebXml.java index 65a3fc119..2611050d2 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/WebXml.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/WebXml.java @@ -4,10 +4,7 @@ package org.apache.tomcat.lite.webxml; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; import java.io.InputStream; -import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.HashMap; @@ -39,16 +36,6 @@ public class WebXml { d = cfg; } - /** - * Serialize the data, for caching. - */ - public void saveWebAppData(String fileName) throws IOException { - ObjectOutputStream oos = - new ObjectOutputStream(new FileOutputStream(fileName)); - oos.writeObject(d); - oos.close(); - } - public ServletContextConfig getWebAppData() { return d; } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/DefaultServlet.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/DefaultServlet.java index d9986b9ba..220069456 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/DefaultServlet.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/DefaultServlet.java @@ -33,7 +33,6 @@ import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Locale; -import java.util.Map; import java.util.StringTokenizer; import javax.servlet.ServletException; @@ -42,6 +41,9 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.tomcat.addons.Filesystem; +import org.apache.tomcat.integration.ObjectManager; +import org.apache.tomcat.integration.simple.ServletHelper; import org.apache.tomcat.servlets.util.Range; /** @@ -56,7 +58,6 @@ public class DefaultServlet extends HttpServlet { // ----------------------------------------------------- Instance Variables - /** * Should we generate directory listings? @@ -126,6 +127,8 @@ public class DefaultServlet extends HttpServlet { // --------------------------------------------------------- Public Methods + protected ObjectManager om; + protected Filesystem fs; /** * Finalize this servlet. @@ -138,6 +141,9 @@ public class DefaultServlet extends HttpServlet { * Initialize this servlet. */ public void init() throws ServletException { + om = ServletHelper.getObjectManager(getServletContext()); + fs = (Filesystem) om.get(Filesystem.class.getName()); + String realPath = getServletContext().getRealPath("/"); basePath = new File(realPath); try { @@ -145,6 +151,7 @@ public class DefaultServlet extends HttpServlet { } catch (IOException e) { basePathName = basePath.getAbsolutePath(); } + log("Init fs " + fs + " base: " + basePathName); // Set our properties from the initialization parameters String value = null; @@ -177,9 +184,42 @@ public class DefaultServlet extends HttpServlet { input = 256; if (output < 256) output = 256; + } + public void setFilesystem(Filesystem fs) { + this.fs = fs; + } + + public Filesystem getFilesystem() { + return fs; + } + + public void setBasePath(String s) { + this.basePathName = s; + this.basePath = new File(s); + } + + public String getBasePath() { + return basePathName; + } + + public void setInput(int i) { + this.input = i; + } + + public void setListings(boolean b) { + this.listings = b; + } + + public void setReadme(String s) { + readmeFile = s; } + public void setFileEncoding(String s) { + fileEncoding = s; + } + + public void loadDefaultMime() throws IOException { File mimeF = new File("/etc/mime.types"); boolean loaded =false; @@ -349,9 +389,9 @@ public class DefaultServlet extends HttpServlet { int cacheSize; public LRUFileCache() { } - protected boolean removeEldestEntity(Map.Entry eldest) { - return size() > cacheSize; - } +// protected boolean removeEldestEntity(Map.Entry eldest) { +// return size() > cacheSize; +// } } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/WebdavServlet.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/WebdavServlet.java index 93563e6ce..68fe8116e 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/WebdavServlet.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/file/WebdavServlet.java @@ -18,10 +18,9 @@ package org.apache.tomcat.servlets.file; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.Writer; import java.text.SimpleDateFormat; import java.util.Date; @@ -121,7 +120,7 @@ public class WebdavServlet extends DefaultServlet { } // TODO: replace it with writeRole - who is enabled to write - protected boolean readOnly = false; + protected boolean readOnly = true; /** * Repository of the lock-null resources. @@ -152,9 +151,16 @@ public class WebdavServlet extends DefaultServlet { } catch (Throwable t) { ; } + log("Starting webdav"); } - + public void setReadonly(boolean ro) { + readOnly = ro; + } + + public boolean getReadonly() { + return readOnly; + } // ------------------------------------------------------ Protected Methods /** @@ -834,7 +840,7 @@ public class WebdavServlet extends DefaultServlet { try { // will override - FileOutputStream fos = new FileOutputStream(resFile); + OutputStream fos = getFilesystem().getOutputStream(resFile.getPath()); CopyUtils.copy(resourceInputStream, fos); } catch(IOException e) { result = false; @@ -1215,8 +1221,8 @@ public class WebdavServlet extends DefaultServlet { } else { try { - CopyUtils.copy( new FileInputStream(object), - new FileOutputStream(dest)); + CopyUtils.copy(getFilesystem().getInputStream(object.getPath()), + getFilesystem().getOutputStream(dest)); } catch(IOException ex ) { errorList.put (source, diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JasperCompilerTemplateClassMapper.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JasperCompilerTemplateClassMapper.java index 278bfbcbb..4c744054c 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JasperCompilerTemplateClassMapper.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/jsp/JasperCompilerTemplateClassMapper.java @@ -26,13 +26,13 @@ import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; -import org.apache.tomcat.InstanceManager; import org.apache.jasper.EmbeddedServletOptions; import org.apache.jasper.JasperException; import org.apache.jasper.JspC; import org.apache.jasper.Options; import org.apache.jasper.compiler.JspRuntimeContext; import org.apache.jasper.servlet.JspServletWrapper; +import org.apache.tomcat.InstanceManager; /** * The actual compiler. Maps and compile a jsp-file to a class. diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/BasicAuthentication.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/BasicAuthentication.java index fa98e5a8d..c17c8296b 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/BasicAuthentication.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/BasicAuthentication.java @@ -23,8 +23,6 @@ import java.security.Principal; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; import org.apache.tomcat.addons.UserAuthentication; @@ -33,7 +31,6 @@ import org.apache.tomcat.addons.UserAuthentication; */ public class BasicAuthentication implements UserAuthentication { - private static Log log = LogFactory.getLog(BasicAuthentication.class); String realm; @Override diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/FormAuthentication.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/FormAuthentication.java index d02908f15..5535790d5 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/FormAuthentication.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/FormAuthentication.java @@ -23,8 +23,6 @@ import java.security.Principal; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; import org.apache.tomcat.addons.UserAuthentication; @@ -33,7 +31,6 @@ import org.apache.tomcat.addons.UserAuthentication; */ public class FormAuthentication implements UserAuthentication { - private static Log log = LogFactory.getLog(FormAuthentication.class); String realm; String url; diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/SimpleUserAuthDB.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/SimpleUserAuthDB.java index a216b8299..0cc215286 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/SimpleUserAuthDB.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/sec/SimpleUserAuthDB.java @@ -18,16 +18,12 @@ package org.apache.tomcat.servlets.sec; -import java.io.IOException; import java.util.Enumeration; import java.util.HashMap; import java.util.Properties; import javax.servlet.ServletConfig; import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; /** * Load user/passwords from a file. diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/HttpSessionImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/HttpSessionImpl.java index 4c73f525b..3885ca151 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/HttpSessionImpl.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/HttpSessionImpl.java @@ -23,6 +23,7 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.logging.Level; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; @@ -362,7 +363,7 @@ public class HttpSessionImpl implements HttpSession, Serializable { try { ((HttpSessionBindingListener) value).valueBound(event); } catch (Throwable t){ - manager.log.error("Listener valueBound() error", t); + manager.log.log(Level.SEVERE, "Listener valueBound() error", t); } } } @@ -377,7 +378,7 @@ public class HttpSessionImpl implements HttpSession, Serializable { ((HttpSessionBindingListener) unbound).valueUnbound (new HttpSessionBindingEvent(getSession(), name)); } catch (Throwable t) { - manager.log.error("Listener valueUnbound()", t); + manager.log.log(Level.SEVERE, "Listener valueUnbound()", t); } } @@ -406,7 +407,7 @@ public class HttpSessionImpl implements HttpSession, Serializable { listener.attributeAdded(event); } } catch (Throwable t) { - manager.log.error("Listener attibuteAdded/Replaced()", t); + manager.log.log(Level.SEVERE, "Listener attibuteAdded/Replaced()", t); } } @@ -462,7 +463,7 @@ public class HttpSessionImpl implements HttpSession, Serializable { try { listener.sessionCreated(event); } catch (Throwable t) { - manager.log.error("listener.sessionCreated()", t); + manager.log.log(Level.SEVERE, "listener.sessionCreated()", t); } } } @@ -592,7 +593,7 @@ public class HttpSessionImpl implements HttpSession, Serializable { try { listener.sessionDestroyed(event); } catch (Throwable t) { - manager.log.error("listener.sessionDestroyed", t); + manager.log.log(Level.SEVERE, "listener.sessionDestroyed", t); } } } @@ -720,7 +721,7 @@ public class HttpSessionImpl implements HttpSession, Serializable { } listener.attributeRemoved(event); } catch (Throwable t) { - manager.log.error("listener.attributeRemoved", t); + manager.log.log(Level.SEVERE, "listener.attributeRemoved", t); } } diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/RandomGenerator.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/RandomGenerator.java index a4a6921b4..54c0063b4 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/RandomGenerator.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/RandomGenerator.java @@ -8,9 +8,8 @@ import java.lang.reflect.Method; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random; - -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Generates random IDs, useable as cookies. @@ -24,7 +23,7 @@ public class RandomGenerator { protected DataInputStream randomIS=null; protected String devRandomSource="/dev/urandom"; - protected static Log log = LogFactory.getLog(RandomGenerator.class); + protected static Logger log = Logger.getLogger(RandomGenerator.class.getName()); /** * The message digest algorithm to be used when generating session @@ -92,17 +91,17 @@ public class RandomGenerator { try { this.digest = MessageDigest.getInstance(algorithm); } catch (NoSuchAlgorithmException e) { - log.error("Algorithm not found", e); + log.log(Level.SEVERE, "Algorithm not found", e); try { this.digest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException f) { - log.error("No message digest available", f); + log.log(Level.SEVERE, "No message digest available", f); this.digest = null; } } long t2=System.currentTimeMillis(); - if( log.isDebugEnabled() ) - log.debug("getDigest() " + (t2-t1)); + if( log.isLoggable(Level.FINEST) ) + log.finest("getDigest() " + (t2-t1)); } return (this.digest); @@ -159,8 +158,6 @@ public class RandomGenerator { if (len == bytes.length) { return; } - if(log.isDebugEnabled()) - log.debug("Got " + len + " " + bytes.length ); } catch (Exception ex) { // Ignore } @@ -169,7 +166,7 @@ public class RandomGenerator { try { randomIS.close(); } catch (Exception e) { - log.warn("Failed to close randomIS."); + log.warning("Failed to close randomIS."); } randomIS = null; @@ -199,14 +196,14 @@ public class RandomGenerator { this.random.setSeed(seed); } catch (Exception e) { // Fall back to the simple case - log.error("Failed to create random " + randomClass, e); + log.log(Level.SEVERE, "Failed to create random " + randomClass, e); this.random = new java.util.Random(); this.random.setSeed(seed); } - if(log.isDebugEnabled()) { + if(log.isLoggable(Level.FINEST)) { long t2=System.currentTimeMillis(); if( (t2-t1) > 100 ) - log.debug("Init random: " + " " + (t2-t1)); + log.finest("Init random: " + " " + (t2-t1)); } } @@ -309,13 +306,13 @@ public class RandomGenerator { if( ! f.exists() ) return; randomIS= new DataInputStream( new FileInputStream(f)); randomIS.readLong(); - if( log.isDebugEnabled() ) - log.debug( "Opening " + devRandomSource ); +// if( log.isDebugEnabled() ) +// log.debug( "Opening " + devRandomSource ); } catch( IOException ex ) { try { randomIS.close(); } catch (Exception e) { - log.warn("Failed to close randomIS."); + log.warning("Failed to close randomIS."); } randomIS=null; diff --git a/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/SimpleSessionManager.java b/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/SimpleSessionManager.java index 72400ea51..2d30d9569 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/SimpleSessionManager.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/servlets/session/SimpleSessionManager.java @@ -23,17 +23,16 @@ import java.util.ArrayList; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Timer; import java.util.TimerTask; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.servlet.ServletContext; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; import org.apache.tomcat.addons.UserSessionManager; // TODO: move 'expiring objects' to a separate utility class @@ -48,7 +47,7 @@ import org.apache.tomcat.addons.UserSessionManager; * @author Craig R. McClanahan */ public class SimpleSessionManager implements UserSessionManager { - protected static Log log = LogFactory.getLog(SimpleSessionManager.class); + protected static Logger log = Logger.getLogger(SimpleSessionManager.class.getName()); protected RandomGenerator randomG = new RandomGenerator(); @@ -89,17 +88,17 @@ public class SimpleSessionManager implements UserSessionManager { protected int expiredSessions = 0; static class SessionLRU extends LinkedHashMap { - protected boolean removeEldestEntry(Map.Entry eldest) { - HttpSessionImpl s = (HttpSessionImpl)eldest.getValue(); - int size = this.size(); - - // TODO: check if eldest is expired or if we're above the limit. - // if eldest is expired, turn a flag to check for more. - - // Note: this doesn't work well for sessions that set shorter - // expiry time, or longer expiry times. - return false; - } +// protected boolean removeEldestEntry(Map.Entry eldest) { +// HttpSessionImpl s = (HttpSessionImpl)eldest.getValue(); +// int size = this.size(); +// +// // TODO: check if eldest is expired or if we're above the limit. +// // if eldest is expired, turn a flag to check for more. +// +// // Note: this doesn't work well for sessions that set shorter +// // expiry time, or longer expiry times. +// return false; +// } } @@ -314,8 +313,8 @@ public class SimpleSessionManager implements UserSessionManager { HttpSessionImpl sessions[] = findSessions(); int expireHere = 0 ; - if(log.isDebugEnabled()) - log.debug("Start expire sessions " + " at " + timeNow + " sessioncount " + sessions.length); + if(log.isLoggable(Level.FINE)) + log.fine("Start expire sessions " + " at " + timeNow + " sessioncount " + sessions.length); for (int i = 0; i < sessions.length; i++) { if (!sessions[i].isValid()) { @@ -325,8 +324,8 @@ public class SimpleSessionManager implements UserSessionManager { } long timeEnd = System.currentTimeMillis(); - if(log.isDebugEnabled()) - log.debug("End expire sessions " + " processingTime " + + if(log.isLoggable(Level.FINE)) + log.fine("End expire sessions " + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere); processingTime += ( timeEnd - timeNow ); diff --git a/modules/tomcat-lite/java/org/apache/tomcat/util/http/HttpRequest.java b/modules/tomcat-lite/java/org/apache/tomcat/util/http/HttpRequest.java new file mode 100644 index 000000000..7ed180d0c --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/util/http/HttpRequest.java @@ -0,0 +1,291 @@ +/* + */ +package org.apache.tomcat.util.http; + +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.buf.UDecoder; + +/** + * Simple request representation, public fields - no I/O or actions, + * just a struct. + * + * Based on Coyote request. + * + * @author Costin Manolache + */ +public class HttpRequest { + + // Same fields as in coyote - this is the primary info from request + + protected MessageBytes schemeMB; + + protected MessageBytes methodMB; + protected MessageBytes unparsedURIMB; + protected MessageBytes protoMB; + protected MimeHeaders headers; + + // Reference to 'real' request object + public Object nativeRequest; + public Object wrapperRequest; + + protected MessageBytes remoteAddrMB; + protected MessageBytes remoteHostMB; + protected int remotePort; + + protected MessageBytes localNameMB; + protected MessageBytes localAddrMB; + protected int localPort; + + protected MessageBytes serverNameMB; + protected int serverPort = -1; + + public HttpRequest() { + schemeMB = + MessageBytes.newInstance(); + methodMB = MessageBytes.newInstance(); + unparsedURIMB = MessageBytes.newInstance(); + decodedUriMB = MessageBytes.newInstance(); + requestURI = MessageBytes.newInstance(); + protoMB = MessageBytes.newInstance(); + headers = new MimeHeaders(); + queryMB = MessageBytes.newInstance(); + serverNameMB = MessageBytes.newInstance(); + + parameters = new Parameters(); + parameters.setQuery(queryMB); + parameters.setURLDecoder(urlDecoder); + //parameters.setHeaders(headers); + cookies = new Cookies(headers); + + initRemote(); + } + + private void initRemote() { + remoteAddrMB = MessageBytes.newInstance(); + localNameMB = MessageBytes.newInstance(); + remoteHostMB = MessageBytes.newInstance(); + localAddrMB = MessageBytes.newInstance(); + } + + + public HttpRequest(MessageBytes scheme, MessageBytes method, + MessageBytes unparsedURI, MessageBytes protocol, + MimeHeaders mimeHeaders, + MessageBytes requestURI, + MessageBytes decodedURI, + MessageBytes query, Parameters params, + MessageBytes serverName, + Cookies cookies) { + this.schemeMB = scheme; + this.methodMB = method; + this.unparsedURIMB = unparsedURI; + this.protoMB = protocol; + this.headers = mimeHeaders; + + this.requestURI = requestURI; + this.decodedUriMB = decodedURI; + this.queryMB = query; + this.parameters = params; + this.serverNameMB = serverName; + this.cookies = cookies; + initRemote(); + } + + + + // ==== Derived fields, computed after request is received === + + protected MessageBytes requestURI; + protected MessageBytes queryMB; + protected MessageBytes decodedUriMB; + + // ----------------- + protected Parameters parameters; + + protected MessageBytes contentTypeMB; + + protected String charEncoding; + protected long contentLength = -1; + + protected Cookies cookies; + + // Avoid object creation: + protected UDecoder urlDecoder = new UDecoder(); + + + public void recycle() { + schemeMB.recycle(); + methodMB.setString("GET"); + unparsedURIMB.recycle(); + protoMB.setString("HTTP/1.1"); + headers.recycle(); + + requestURI.recycle(); + queryMB.recycle(); + decodedUriMB.recycle(); + + parameters.recycle(); + contentTypeMB = null; + charEncoding = null; + contentLength = -1; + remoteAddrMB.recycle(); + remoteHostMB.recycle(); + cookies.recycle(); + } + + public Parameters getParameters() { + return parameters; + } + + // For compatibility with coyote + public MessageBytes decodedURI() { + return decodedUriMB; + } + + public MessageBytes requestURI() { + return requestURI; + } + + public MessageBytes method() { + return methodMB; + } + + public String getHeader(String name) { + return headers.getHeader(name); + } + + public MimeHeaders getMimeHeaders() { + return headers; + } + + /** + * Get the character encoding used for this request. + */ + public String getCharacterEncoding() { + + if (charEncoding != null) + return charEncoding; + + charEncoding = ContentType.getCharsetFromContentType(getContentType()); + return charEncoding; + + } + + + public void setCharacterEncoding(String enc) { + this.charEncoding = enc; + } + + + public void setContentLength(int len) { + this.contentLength = len; + } + + + public int getContentLength() { + long length = getContentLengthLong(); + + if (length < Integer.MAX_VALUE) { + return (int) length; + } + return -1; + } + + public long getContentLengthLong() { + if( contentLength > -1 ) return contentLength; + + MessageBytes clB = headers.getUniqueValue("content-length"); + contentLength = (clB == null || clB.isNull()) ? -1 : clB.getLong(); + + return contentLength; + } + + public String getContentType() { + contentType(); + if ((contentTypeMB == null) || contentTypeMB.isNull()) + return null; + return contentTypeMB.toString(); + } + + + public void setContentType(String type) { + contentTypeMB.setString(type); + } + + + public MessageBytes contentType() { + if (contentTypeMB == null || contentTypeMB.isNull()) + contentTypeMB = headers.getValue("content-type"); + return contentTypeMB; + } + + public int getServerPort() { + return serverPort; + } + + public void setServerPort(int serverPort ) { + this.serverPort=serverPort; + } + + public MessageBytes remoteAddr() { + return remoteAddrMB; + } + + public MessageBytes remoteHost() { + return remoteHostMB; + } + + public MessageBytes localName() { + return localNameMB; + } + + public MessageBytes localAddr() { + return localAddrMB; + } + + public int getRemotePort(){ + return remotePort; + } + + public void setRemotePort(int port){ + this.remotePort = port; + } + + public int getLocalPort(){ + return localPort; + } + + public void setLocalPort(int port){ + this.localPort = port; + } + + public MessageBytes queryString() { + return queryMB; + } + + public MessageBytes protocol() { + return protoMB; + } + + public MessageBytes scheme() { + return schemeMB; + } + + public MessageBytes serverName() { + return serverNameMB; + } + + public MessageBytes unparsedURI() { + return unparsedURIMB; + } + + public Cookies getCookies() { + return cookies; + } + + public UDecoder getURLDecoder() { + return urlDecoder; + } + +} + diff --git a/modules/tomcat-lite/java/org/apache/tomcat/util/http/HttpResponse.java b/modules/tomcat-lite/java/org/apache/tomcat/util/http/HttpResponse.java new file mode 100644 index 000000000..1bcef50e6 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/util/http/HttpResponse.java @@ -0,0 +1,118 @@ +/* + */ +package org.apache.tomcat.util.http; + +import org.apache.tomcat.util.buf.MessageBytes; + +/** + * The data fields in a HTTP response and few helper and accessors. + * No actions - just a struct. + * + * Subset of coyte response. + * + * @author Costin Manolache + */ +public class HttpResponse { + // Primary fields + // in coyote message is String, status is int + protected MessageBytes message = MessageBytes.newInstance(); + protected MessageBytes proto = MessageBytes.newInstance(); + protected MessageBytes statusBuffer = MessageBytes.newInstance(); + protected MimeHeaders headers = new MimeHeaders(); + public Object nativeResponse; + + boolean commited; + + public void recycle() { + getMimeHeaders().recycle(); + message.recycle(); + statusBuffer.setInt(200); + commited = false; + } + + public boolean isCommitted() { + return commited; + } + + public void setCommitted(boolean b) { + commited = b; + } + + // Methods named for compat with coyote + + public void setStatus(int i) { + statusBuffer.setInt(i); + } + + public void setMessage(String s) { + message.setString(s); + } + + public String getMessage() { + return message.toString(); + } + + public MessageBytes getMessageBuffer() { + return message; + } + + public MessageBytes protocol() { + return proto; + } + + public int getStatus() { + return statusBuffer.getInt(); + } + + public MessageBytes getStatusBuffer() { + return statusBuffer; + } + + + public void addHeader(String name, String value) { + getMimeHeaders().addValue(name).setString(value); + } + + public void setHeader(String name, String value) { + getMimeHeaders().setValue(name).setString(value); + } + + public void setMimeHeaders(MimeHeaders resHeaders) { + this.headers = resHeaders; + } + + public MimeHeaders getMimeHeaders() { + return headers; + } + + /** + * Warning: This method always returns false for Content-Type + * and Content-Length. + */ + public boolean containsHeader(String name) { + return headers.getHeader(name) != null; + } + + public void setContentLength(long length) { + MessageBytes clB = getMimeHeaders().getUniqueValue("content-length"); + if (clB == null) { + clB = getMimeHeaders().addValue("content-length"); + } + clB.setLong(length); + } + + public long getContentLength() { + MessageBytes clB = getMimeHeaders().getUniqueValue("content-length"); + return (clB == null || clB.isNull()) ? -1 : clB.getLong(); + } + + public void setContentType(String contentType) { + MessageBytes clB = getMimeHeaders().getUniqueValue("content-type"); + if (clB == null) { + setHeader("content-type", contentType); + } else { + clB.setString(contentType); + } + } + +} \ No newline at end of file diff --git a/modules/tomcat-lite/java/org/apache/tomcat/util/http/MimeMap.java b/modules/tomcat-lite/java/org/apache/tomcat/util/http/MimeMap.java new file mode 100644 index 000000000..07dbe02d6 --- /dev/null +++ b/modules/tomcat-lite/java/org/apache/tomcat/util/http/MimeMap.java @@ -0,0 +1,194 @@ +/* + * 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.util.http; + +import java.net.*; +import java.util.*; + + +/** + * A mime type map that implements the java.net.FileNameMap interface. + * + * @author James Duncan Davidson [duncan@eng.sun.com] + * @author Jason Hunter [jch@eng.sun.com] + */ +public class MimeMap implements FileNameMap { + + // Defaults - all of them are "well-known" types, + // you can add using normal web.xml. + + public static Hashtable defaultMap = + new Hashtable(101); + static { + defaultMap.put("txt", "text/plain"); + defaultMap.put("css", "text/css"); + defaultMap.put("html","text/html"); + defaultMap.put("htm", "text/html"); + defaultMap.put("gif", "image/gif"); + defaultMap.put("jpg", "image/jpeg"); + defaultMap.put("jpe", "image/jpeg"); + defaultMap.put("jpeg", "image/jpeg"); + defaultMap.put("png", "image/png"); + defaultMap.put("java", "text/plain"); + defaultMap.put("body", "text/html"); + defaultMap.put("rtx", "text/richtext"); + defaultMap.put("tsv", "text/tab-separated-values"); + defaultMap.put("etx", "text/x-setext"); + defaultMap.put("ps", "application/x-postscript"); + defaultMap.put("class", "application/java"); + defaultMap.put("csh", "application/x-csh"); + defaultMap.put("sh", "application/x-sh"); + defaultMap.put("tcl", "application/x-tcl"); + defaultMap.put("tex", "application/x-tex"); + defaultMap.put("texinfo", "application/x-texinfo"); + defaultMap.put("texi", "application/x-texinfo"); + defaultMap.put("t", "application/x-troff"); + defaultMap.put("tr", "application/x-troff"); + defaultMap.put("roff", "application/x-troff"); + defaultMap.put("man", "application/x-troff-man"); + defaultMap.put("me", "application/x-troff-me"); + defaultMap.put("ms", "application/x-wais-source"); + defaultMap.put("src", "application/x-wais-source"); + defaultMap.put("zip", "application/zip"); + defaultMap.put("bcpio", "application/x-bcpio"); + defaultMap.put("cpio", "application/x-cpio"); + defaultMap.put("gtar", "application/x-gtar"); + defaultMap.put("shar", "application/x-shar"); + defaultMap.put("sv4cpio", "application/x-sv4cpio"); + defaultMap.put("sv4crc", "application/x-sv4crc"); + defaultMap.put("tar", "application/x-tar"); + defaultMap.put("ustar", "application/x-ustar"); + defaultMap.put("dvi", "application/x-dvi"); + defaultMap.put("hdf", "application/x-hdf"); + defaultMap.put("latex", "application/x-latex"); + defaultMap.put("bin", "application/octet-stream"); + defaultMap.put("oda", "application/oda"); + defaultMap.put("pdf", "application/pdf"); + defaultMap.put("ps", "application/postscript"); + defaultMap.put("eps", "application/postscript"); + defaultMap.put("ai", "application/postscript"); + defaultMap.put("rtf", "application/rtf"); + defaultMap.put("nc", "application/x-netcdf"); + defaultMap.put("cdf", "application/x-netcdf"); + defaultMap.put("cer", "application/x-x509-ca-cert"); + defaultMap.put("exe", "application/octet-stream"); + defaultMap.put("gz", "application/x-gzip"); + defaultMap.put("Z", "application/x-compress"); + defaultMap.put("z", "application/x-compress"); + defaultMap.put("hqx", "application/mac-binhex40"); + defaultMap.put("mif", "application/x-mif"); + defaultMap.put("ief", "image/ief"); + defaultMap.put("tiff", "image/tiff"); + defaultMap.put("tif", "image/tiff"); + defaultMap.put("ras", "image/x-cmu-raster"); + defaultMap.put("pnm", "image/x-portable-anymap"); + defaultMap.put("pbm", "image/x-portable-bitmap"); + defaultMap.put("pgm", "image/x-portable-graymap"); + defaultMap.put("ppm", "image/x-portable-pixmap"); + defaultMap.put("rgb", "image/x-rgb"); + defaultMap.put("xbm", "image/x-xbitmap"); + defaultMap.put("xpm", "image/x-xpixmap"); + defaultMap.put("xwd", "image/x-xwindowdump"); + defaultMap.put("au", "audio/basic"); + defaultMap.put("snd", "audio/basic"); + defaultMap.put("aif", "audio/x-aiff"); + defaultMap.put("aiff", "audio/x-aiff"); + defaultMap.put("aifc", "audio/x-aiff"); + defaultMap.put("wav", "audio/x-wav"); + defaultMap.put("mpeg", "video/mpeg"); + defaultMap.put("mpg", "video/mpeg"); + defaultMap.put("mpe", "video/mpeg"); + defaultMap.put("qt", "video/quicktime"); + defaultMap.put("mov", "video/quicktime"); + defaultMap.put("avi", "video/x-msvideo"); + defaultMap.put("movie", "video/x-sgi-movie"); + defaultMap.put("avx", "video/x-rad-screenplay"); + defaultMap.put("wrl", "x-world/x-vrml"); + defaultMap.put("mpv2", "video/mpeg2"); + + /* Add XML related MIMEs */ + + defaultMap.put("xml", "text/xml"); + defaultMap.put("xsl", "text/xml"); + defaultMap.put("svg", "image/svg+xml"); + defaultMap.put("svgz", "image/svg+xml"); + defaultMap.put("wbmp", "image/vnd.wap.wbmp"); + defaultMap.put("wml", "text/vnd.wap.wml"); + defaultMap.put("wmlc", "application/vnd.wap.wmlc"); + defaultMap.put("wmls", "text/vnd.wap.wmlscript"); + defaultMap.put("wmlscriptc", "application/vnd.wap.wmlscriptc"); + } + + + private Hashtable map = new Hashtable(); + + public void addContentType(String extn, String type) { + map.put(extn, type.toLowerCase()); + } + + public Enumeration getExtensions() { + return map.keys(); + } + + public String getMimeType(String ext) { + return getContentTypeFor(ext); + } + + public String getContentType(String extn) { + String type = (String)map.get(extn.toLowerCase()); + if( type == null ) type=(String)defaultMap.get( extn ); + return type; + } + + public void removeContentType(String extn) { + map.remove(extn.toLowerCase()); + } + + /** Get extension of file, without fragment id + */ + public static String getExtension( String fileName ) { + // play it safe and get rid of any fragment id + // that might be there + int length=fileName.length(); + + int newEnd = fileName.lastIndexOf('#'); + if( newEnd== -1 ) newEnd=length; + // Instead of creating a new string. + // if (i != -1) { + // fileName = fileName.substring(0, i); + // } + int i = fileName.lastIndexOf('.', newEnd ); + if (i != -1) { + return fileName.substring(i + 1, newEnd ); + } else { + // no extension, no content type + return null; + } + } + + public String getContentTypeFor(String fileName) { + String extn=getExtension( fileName ); + if (extn!=null) { + return getContentType(extn); + } else { + // no extension, no content type + return null; + } + } + +} diff --git a/modules/tomcat-lite/java/org/apache/tomcat/util/http/mapper/BaseMapper.java b/modules/tomcat-lite/java/org/apache/tomcat/util/http/mapper/BaseMapper.java index 7c1adc36f..6e6323382 100644 --- a/modules/tomcat-lite/java/org/apache/tomcat/util/http/mapper/BaseMapper.java +++ b/modules/tomcat-lite/java/org/apache/tomcat/util/http/mapper/BaseMapper.java @@ -18,14 +18,14 @@ package org.apache.tomcat.util.http.mapper; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.buf.Ascii; - import java.io.File; import java.io.IOException; -import java.util.List; import java.util.ArrayList; +import java.util.List; + +import org.apache.tomcat.util.buf.Ascii; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.MessageBytes; /** * Mapper, which implements the servlet API mapping rules (which are derived