--- /dev/null
+package org.apache.coyote.lite;
+
+
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.apache.coyote.Adapter;
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+import org.apache.tomcat.lite.http.HttpConnector;
+import org.apache.tomcat.lite.http.HttpRequest;
+import org.apache.tomcat.lite.http.HttpResponse;
+import org.apache.tomcat.lite.http.HttpChannel.HttpService;
+import org.apache.tomcat.lite.io.CBuffer;
+import org.apache.tomcat.lite.io.SocketConnector;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/**
+ * Work in progress - use the refactored http as a coyote connector.
+ * Just basic requests work right now - need to implement all the
+ * methods of coyote.
+ *
+ *
+ * @author Costin Manolache
+ */
+public class LiteProtocolHandler implements ProtocolHandler {
+
+ Adapter adapter;
+
+ @Override
+ public void destroy() throws Exception {
+ }
+
+ @Override
+ public Adapter getAdapter() {
+ return adapter;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return null;
+ }
+
+ @Override
+ public Iterator<String> getAttributeNames() {
+ return null;
+ }
+
+ @Override
+ public void init() throws Exception {
+ }
+
+ @Override
+ public void pause() throws Exception {
+ }
+
+ @Override
+ public void resume() throws Exception {
+ }
+
+ @Override
+ public void setAdapter(Adapter adapter) {
+ this.adapter = adapter;
+
+ }
+
+ int port = 8999;
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ @Override
+ public void setAttribute(String name, Object value) {
+ System.err.println("setAttribute " + name + " " + value);
+ }
+
+ @Override
+ public void start() throws Exception {
+ HttpConnector c = new HttpConnector(new SocketConnector());
+ c.setPort(port);
+
+// c.setDebug(true);
+// c.setDebugHttp(true);
+
+ c.getDispatcher().setDefaultService(new HttpService() {
+ @Override
+ public void service(HttpRequest httpReq, HttpResponse httpRes)
+ throws IOException {
+ coyoteService(httpReq, httpRes);
+ }
+
+ });
+ c.start();
+ }
+
+ private void wrap(MessageBytes dest, CBuffer buffer) {
+ dest.setChars(buffer.array(), buffer.position(),
+ buffer.length());
+ }
+
+ private void coyoteService(HttpRequest httpReq, final HttpResponse httpRes) {
+ Request req = new Request();
+ req.setInputBuffer(new InputBuffer() {
+ @Override
+ public int doRead(ByteChunk chunk, Request request)
+ throws IOException {
+ // TODO
+ return 0;
+ }
+ });
+ Response res = new Response();
+ res.setOutputBuffer(new OutputBuffer() {
+
+ @Override
+ public int doWrite(org.apache.tomcat.util.buf.ByteChunk chunk,
+ Response response) throws IOException {
+ httpRes.getBody().append(chunk.getBuffer(), chunk.getStart(),
+ chunk.getLength());
+ return chunk.getLength();
+ }
+
+ });
+
+ // TODO: turn http request into a coyote request - copy all fields,
+ // add hooks where needed.
+
+ wrap(req.decodedURI(), httpReq.decodedURI());
+ wrap(req.method(), httpReq.method());
+ wrap(req.protocol(), httpReq.protocol());
+ wrap(req.requestURI(), httpReq.requestURI());
+ // Same for response.
+
+ try {
+
+ adapter.service(req, res);
+
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+
+
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.coyote.servlet;
+
+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<String, B2CConverter> encoders =
+ new HashMap<String, B2CConverter>();
+
+
+ /**
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.coyote.servlet;
+
+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(StringBuilder sb)
+ throws IOException {
+
+ if (suspended)
+ return;
+
+ state = CHAR_STATE;
+
+ int len = sb.length();
+ charsWritten += len;
+ cb.append(sb.toString());
+
+ }
+
+
+ /**
+ * 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
--- /dev/null
+en=ISO-8859-1
+fr=ISO-8859-1
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.coyote.servlet;
+
+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() {
+
+ StringBuilder sb = new StringBuilder("ClientAbortException: ");
+ if (message != null) {
+ sb.append(message);
+ if (throwable != null) {
+ sb.append(": ");
+ }
+ }
+ if (throwable != null) {
+ sb.append(throwable.toString());
+ }
+ return (sb.toString());
+
+ }
+
+
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.coyote.servlet;
+
+import java.io.IOException;
+
+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.
+ *
+ * Currently we have lots of deps on coyote Request, but I plan to
+ * change this and allow other HTTP implementations - like MINA, the
+ * experimental async connector, etc. Most important will be
+ * different support for IO - i.e. a more non-blocking mode.
+ * We'll probably keep MessageBytes as wrappers for request/res
+ * properties.
+ *
+ * This interface has no dep on coyote.
+ *
+ */
+public interface Connector {
+
+ public void setDaemon(boolean b);
+
+ public void start() throws IOException;
+
+ public void stop() throws Exception;
+
+ /**
+ * 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);
+
+ void initRequest(HttpServletRequest req, HttpServletResponse res);
+
+ 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;
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.coyote.servlet;
+
+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.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;
+ }
+
+ public boolean asyncDispatch(Request req,Response res, SocketStatus status) throws Exception {
+ // implement me
+ return false;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2009 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.coyote.servlet;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+/**
+ * Wraps the list of filters for the current request. One instance
+ * associated with each RequestImpl, reused.
+ *
+ * Populated by the mapper ( WebappFilterMapper for example ), which
+ * determines the filters for the current request.
+ *
+ * Not thread safe.
+ */
+public final class FilterChainImpl implements FilterChain {
+ private List<FilterConfigImpl> filters = new ArrayList<FilterConfigImpl>();
+
+
+ /**
+ * The int which is used to maintain the current position
+ * in the filter chain.
+ */
+ private int pos = 0;
+
+ /**
+ * The servlet instance to be executed by this chain.
+ */
+ private Servlet servlet = null;
+
+
+ private ServletConfigImpl wrapper;
+
+
+ public FilterChainImpl() {
+ super();
+ }
+
+
+ /**
+ * Invoke the next filter in this chain, passing the specified request
+ * and response. If there are no more filters in this chain, invoke
+ * the <code>service()</code> method of the servlet itself.
+ *
+ * @param request The servlet request we are processing
+ * @param response The servlet response we are creating
+ *
+ * @exception IOException if an input/output error occurs
+ * @exception ServletException if a servlet exception occurs
+ */
+ public void doFilter(ServletRequest request, ServletResponse response)
+ throws IOException, ServletException {
+
+
+ // Call the next filter if there is one
+ if (pos < filters.size()) {
+ FilterConfigImpl filterConfig = filters.get(pos++);
+ Filter filter = null;
+ try {
+ filter = filterConfig.getFilter();
+ filter.doFilter(request, response, this);
+ } catch (IOException e) {
+ throw e;
+ } catch (ServletException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Throwable e) {
+ e.printStackTrace();
+ throw new ServletException("Throwable", e);
+ }
+ return;
+ }
+
+ // We fell off the end of the chain -- call the servlet instance
+ try {
+ if (servlet != null)
+ servlet.service(request, response);
+ } catch (IOException e) {
+ throw e;
+ } catch (ServletException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Throwable e) {
+ throw new ServletException("Throwable", e);
+ }
+ }
+
+
+ // -------------------------------------------------------- Package Methods
+
+
+
+ /**
+ * Add a filter to the set of filters that will be executed in this chain.
+ *
+ * @param filterConfig The FilterConfig for the servlet to be executed
+ */
+ public void addFilter(FilterConfigImpl filterConfig) {
+ filters.add(filterConfig);
+ }
+
+
+ /**
+ * Release references to the filters and wrapper executed by this chain.
+ */
+ public void release() {
+ filters.clear();
+ pos = 0;
+ servlet = null;
+ }
+
+
+ /**
+ * Set the servlet that will be executed at the end of this chain.
+ * Set by the mapper filter
+ */
+ public void setServlet(ServletConfigImpl wrapper, Servlet servlet) {
+ this.wrapper = wrapper;
+ this.servlet = servlet;
+ }
+
+ // ------ Getters for information ------------
+
+ public int getSize() {
+ return filters.size();
+ }
+
+ public FilterConfigImpl getFilter(int i) {
+ return filters.get(i);
+ }
+
+ public Servlet getServlet() {
+ return servlet;
+ }
+
+ public ServletConfigImpl getServletConfig() {
+ return wrapper;
+ }
+
+ public int getPos() {
+ return pos;
+ }
+}
--- /dev/null
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.coyote.servlet;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.FilterRegistration;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.FilterRegistration.Dynamic;
+
+import org.apache.tomcat.servlets.util.Enumerator;
+
+
+/**
+ * A Filter is configured in web.xml by:
+ * - name - used in mappings
+ * - className - used to instantiate the filter
+ * - init params
+ * - other things not used in the servlet container ( icon, descr, etc )
+ *
+ * Alternatively, in API mode you can pass the actual filter.
+ *
+ * @see ServletConfigImpl
+ */
+public final class FilterConfigImpl implements FilterConfig, FilterRegistration {
+
+ DynamicFilterRegistration dynamic = new DynamicFilterRegistration();
+
+ public FilterConfigImpl(ServletContextImpl context) {
+ this.ctx = context;
+ }
+
+ boolean asyncSupported;
+
+ private ServletContextImpl ctx = null;
+
+ /**
+ * The application Filter we are configured for.
+ */
+ private transient Filter filter = null;
+
+ String descryption;
+
+ private String filterName;
+
+ private String filterClassName;
+
+ Map<String, String> initParams;
+
+ private Class<? extends Filter> filterClass;
+
+ public void setData(String filterName, String filterClass,
+ Map<String, String> params) {
+ this.filterName = filterName;
+ this.filterClassName = filterClass;
+ this.initParams = params;
+ }
+
+ public void setFilter(Filter f) {
+ filter = f;
+ }
+
+ public String getFilterName() {
+ return filterName;
+ }
+
+ public void setFilterClass(Class<? extends Filter> filterClass2) {
+ this.filterClass = filterClass2;
+ }
+
+
+ public String getInitParameter(String name) {
+ if (initParams == null) return null;
+ return initParams.get(name);
+ }
+
+ /**
+ * Return an <code>Enumeration</code> of the names of the initialization
+ * parameters for this Filter.
+ */
+ public Enumeration getInitParameterNames() {
+ if (initParams == null)
+ return (new Enumerator(new ArrayList()));
+ else
+ return (new Enumerator(initParams.keySet()));
+ }
+
+
+ /**
+ * Return the ServletContext of our associated web application.
+ */
+ public ServletContext getServletContext() {
+ return ctx;
+ }
+
+ /**
+ * Return the application Filter we are configured for.
+ */
+ public Filter createFilter() throws ClassCastException, ClassNotFoundException,
+ IllegalAccessException, InstantiationException, ServletException {
+
+ // Return the existing filter instance, if any
+ if (filter != null)
+ return filter;
+
+ ClassLoader classLoader = ctx.getClassLoader();
+
+ ClassLoader oldCtxClassLoader =
+ Thread.currentThread().getContextClassLoader();
+ if (classLoader != oldCtxClassLoader) {
+ Thread.currentThread().setContextClassLoader(classLoader);
+ }
+ try {
+ if (filterClass == null) {
+ filterClass = (Class<? extends Filter>) classLoader.loadClass(filterClassName);
+ }
+ this.filter = (Filter) filterClass.newInstance();
+ } finally {
+ if (classLoader != oldCtxClassLoader) {
+ Thread.currentThread().setContextClassLoader(oldCtxClassLoader);
+ }
+ }
+
+ // TODO: resource injection
+
+ return filter;
+ }
+
+ public Filter getFilter() throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException {
+ Filter filter = createFilter();
+ filter.init(this);
+ return (this.filter);
+ }
+
+
+ /**
+ * Release the Filter instance associated with this FilterConfig,
+ * if there is one.
+ */
+ public void release() {
+ if (this.filter != null){
+ filter.destroy();
+ }
+ this.filter = null;
+ }
+
+
+ @Override
+ public void addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes,
+ boolean isMatchAfter,
+ String... servletNames) {
+ if (ctx.startDone) {
+ // Use the context method instead of the servlet API to
+ // add mappings after context init.
+ throw new IllegalStateException();
+ }
+ ArrayList<String> dispatchers = new ArrayList<String>();
+ for (DispatcherType dt: dispatcherTypes) {
+ dispatchers.add(dt.name());
+ }
+ for (String servletName: servletNames) {
+ ctx.getFilterMapper().addMapping(getFilterName(),
+ null, servletName, (String[]) dispatchers.toArray(), isMatchAfter);
+ }
+ }
+
+
+ @Override
+ public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes,
+ boolean isMatchAfter,
+ String... urlPatterns) {
+ if (ctx.startDone) {
+ // Use the context method instead of the servlet API to
+ // add mappings after context init.
+ throw new IllegalStateException();
+ }
+ ArrayList<String> dispatchers = new ArrayList<String>();
+ for (DispatcherType dt: dispatcherTypes) {
+ dispatchers.add(dt.name());
+ }
+ for (String url: urlPatterns) {
+ ctx.getFilterMapper().addMapping(getFilterName(),
+ url, null, (String[]) dispatchers.toArray(), isMatchAfter);
+ }
+ }
+
+
+ @Override
+ public boolean setInitParameter(String name, String value)
+ throws IllegalArgumentException, IllegalStateException {
+ return ServletContextImpl.setInitParameter(ctx, initParams,
+ name, value);
+ }
+
+
+ @Override
+ public Set<String> setInitParameters(Map<String, String> initParameters)
+ throws IllegalArgumentException, IllegalStateException {
+ return ServletContextImpl.setInitParameters(ctx, initParams,
+ initParameters);
+ }
+
+ public Dynamic getDynamic() {
+ return dynamic;
+ }
+
+ public class DynamicFilterRegistration implements Dynamic {
+
+
+ @Override
+ public void addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes,
+ boolean isMatchAfter,
+ String... servletNames) {
+ FilterConfigImpl.this.addMappingForServletNames(dispatcherTypes, isMatchAfter, servletNames);
+ }
+
+
+ @Override
+ public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes,
+ boolean isMatchAfter,
+ String... urlPatterns) {
+ FilterConfigImpl.this.addMappingForUrlPatterns(dispatcherTypes, isMatchAfter, urlPatterns);
+ }
+
+
+ @Override
+ public boolean setInitParameter(String name, String value)
+ throws IllegalArgumentException, IllegalStateException {
+ return ServletContextImpl.setInitParameter(ctx, initParams,
+ name, value);
+ }
+
+
+ @Override
+ public Set<String> setInitParameters(Map<String, String> initParameters)
+ throws IllegalArgumentException, IllegalStateException {
+ return ServletContextImpl.setInitParameters(ctx, initParams,
+ initParameters);
+ }
+
+
+ @Override
+ public void setAsyncSupported(boolean isAsyncSupported)
+ throws IllegalStateException {
+ asyncSupported = isAsyncSupported;
+ }
+
+
+ public void setDescription(String description)
+ throws IllegalStateException {
+ FilterConfigImpl.this.descryption = description;
+ }
+
+ @Override
+ public Collection<String> getUrlPatternMappings() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public Collection<String> getServletNameMappings() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public Map<String, String> getInitParameters() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public String getInitParameter(String name) {
+ if (initParams == null) return null;
+ return initParams.get(name);
+ }
+
+ @Override
+ public String getClassName() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ // implement me
+ return null;
+ }
+ }
+
+ @Override
+ public Collection<String> getUrlPatternMappings() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public Collection<String> getServletNameMappings() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public Map<String, String> getInitParameters() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public String getClassName() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ // implement me
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.coyote.servlet;
+
+import javax.servlet.ServletContext;
+
+import org.apache.tomcat.servlets.jsp.BaseJspLoader;
+
+public class JspLoader extends BaseJspLoader {
+
+ public ClassLoader getClassLoader(ServletContext ctx) {
+ return ((ServletContextImpl) ctx).getClassLoader();
+ }
+
+ public String getClassPath(ServletContext ctx) {
+ return ((ServletContextImpl) ctx).getClassPath();
+ }
+}
--- /dev/null
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.coyote.servlet;
+
+
+import java.io.InputStream;
+import java.util.Locale;
+import java.util.Properties;
+
+
+
+/**
+ * One instance per Context. Holds the
+ *
+ * Utility class that attempts to map from a Locale to the corresponding
+ * character set to be used for interpreting input text (or generating
+ * output text) when the Content-Type header does not include one. You
+ * can customize the behavior of this class by modifying the mapping data
+ * it loads, or by subclassing it (to change the algorithm) and then using
+ * your own version for a particular web application.
+ *
+ * @author Craig R. McClanahan
+ */
+public class Locale2Charset {
+
+
+ // ---------------------------------------------------- Manifest Constants
+
+
+ /**
+ * Default properties resource name.
+ */
+ public static final String DEFAULT_RESOURCE =
+ "/org/apache/coyote/servlet/CharsetMapperDefault.properties";
+
+
+
+ // ---------------------------------------------------------- Constructors
+
+
+ /**
+ * Construct a new CharsetMapper using the default properties resource.
+ */
+ public Locale2Charset() {
+ String name = DEFAULT_RESOURCE;
+ if (defaultMap == null) { // once !
+ try {
+ defaultMap = new Properties();
+ InputStream stream =
+ this.getClass().getResourceAsStream(name);
+ defaultMap.load(stream);
+ stream.close();
+ } catch (Throwable t) {
+ throw new IllegalArgumentException(t.toString());
+ }
+ }
+ map = defaultMap;
+ }
+
+
+ // ---------------------------------------------------- Instance Variables
+
+
+ private static Properties defaultMap; // shared for all apps
+
+ /**
+ * The mapping properties that have been initialized from the specified or
+ * default properties resource.
+ */
+ private Properties map;
+
+
+ // ------------------------------------------------------- Public Methods
+
+
+ /**
+ * Calculate the name of a character set to be assumed, given the specified
+ * Locale and the absence of a character set specified as part of the
+ * content type header.
+ *
+ * @param locale The locale for which to calculate a character set
+ */
+ public String getCharset(Locale locale) {
+ // Match full language_country_variant first, then language_country,
+ // then language only
+ String charset = map.getProperty(locale.toString());
+ if (charset == null) {
+ charset = map.getProperty(locale.getLanguage() + "_"
+ + locale.getCountry());
+ if (charset == null) {
+ charset = map.getProperty(locale.getLanguage());
+ }
+ }
+ return (charset);
+ }
+
+
+ /**
+ * The deployment descriptor can have a
+ * locale-encoding-mapping-list element which describes the
+ * webapp's desired mapping from locale to charset. This method
+ * gets called when processing the web.xml file for a context
+ *
+ * @param locale The locale for a character set
+ * @param charset The charset to be associated with the locale
+ */
+ public void addCharsetMapping(String locale, String charset) {
+ if (map == defaultMap) {
+ // new copy, don't modify original
+ map = new Properties(defaultMap);
+ }
+ map.put(locale, charset);
+ }
+}
--- /dev/null
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.coyote.servlet;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Extended implementation of <strong>HashMap</strong> that includes a
+ * <code>locked</code> property. This class can be used to safely expose
+ * Catalina internal parameter map objects to user classes without having
+ * to clone them in order to avoid modifications. When first created, a
+ * <code>ParmaeterMap</code> instance is not locked.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision$ $Date$
+ */
+
+public final class ParameterMap extends HashMap {
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Construct a new, empty map with the default initial capacity and
+ * load factor.
+ */
+ public ParameterMap() {
+
+ super();
+
+ }
+
+
+ /**
+ * Construct a new, empty map with the specified initial capacity and
+ * default load factor.
+ *
+ * @param initialCapacity The initial capacity of this map
+ */
+ public ParameterMap(int initialCapacity) {
+
+ super(initialCapacity);
+
+ }
+
+
+ /**
+ * Construct a new, empty map with the specified initial capacity and
+ * load factor.
+ *
+ * @param initialCapacity The initial capacity of this map
+ * @param loadFactor The load factor of this map
+ */
+ public ParameterMap(int initialCapacity, float loadFactor) {
+
+ super(initialCapacity, loadFactor);
+
+ }
+
+
+ /**
+ * Construct a new map with the same mappings as the given map.
+ *
+ * @param map Map whose contents are dupliated in the new map
+ */
+ public ParameterMap(Map map) {
+
+ super(map);
+
+ }
+
+
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * The current lock state of this parameter map.
+ */
+ private boolean locked = false;
+
+
+ /**
+ * Return the locked state of this parameter map.
+ */
+ public boolean isLocked() {
+
+ return (this.locked);
+
+ }
+
+
+ /**
+ * Set the locked state of this parameter map.
+ *
+ * @param locked The new locked state
+ */
+ public void setLocked(boolean locked) {
+
+ this.locked = locked;
+
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+
+ /**
+ * Remove all mappings from this map.
+ *
+ * @exception IllegalStateException if this map is currently locked
+ */
+ public void clear() {
+
+ if (locked)
+ throw new IllegalStateException
+ ("parameterMap.locked");
+ super.clear();
+
+ }
+
+
+ /**
+ * Associate the specified value with the specified key in this map. If
+ * the map previously contained a mapping for this key, the old value is
+ * replaced.
+ *
+ * @param key Key with which the specified value is to be associated
+ * @param value Value to be associated with the specified key
+ *
+ * @return The previous value associated with the specified key, or
+ * <code>null</code> if there was no mapping for key
+ *
+ * @exception IllegalStateException if this map is currently locked
+ */
+ public Object put(Object key, Object value) {
+
+ if (locked)
+ throw new IllegalStateException
+ ("parameterMap.locked");
+ return (super.put(key, value));
+
+ }
+
+
+ /**
+ * Copy all of the mappings from the specified map to this one. These
+ * mappings replace any mappings that this map had for any of the keys
+ * currently in the specified Map.
+ *
+ * @param map Mappings to be stored into this map
+ *
+ * @exception IllegalStateException if this map is currently locked
+ */
+ public void putAll(Map map) {
+
+ if (locked)
+ throw new IllegalStateException
+ ("parameterMap.locked");
+ super.putAll(map);
+
+ }
+
+
+ /**
+ * Remove the mapping for this key from the map if present.
+ *
+ * @param key Key whose mapping is to be removed from the map
+ *
+ * @return The previous value associated with the specified key, or
+ * <code>null</code> if there was no mapping for that key
+ *
+ * @exception IllegalStateException if this map is currently locked
+ */
+ public Object remove(Object key) {
+
+ if (locked)
+ throw new IllegalStateException
+ ("parameterMap.locked");
+ return (super.remove(key));
+
+ }
+
+
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.coyote.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestWrapper;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletResponseWrapper;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.mapper.MappingData;
+
+/**
+ *
+ */
+public final class RequestDispatcherImpl implements RequestDispatcher {
+ /**
+ * The request attribute under which the original servlet path is stored
+ * on an forwarded dispatcher request.
+ */
+ public static final String FORWARD_SERVLET_PATH_ATTR =
+ "javax.servlet.forward.servlet_path";
+
+
+ /**
+ * The request attribute under which the original query string is stored
+ * on an forwarded dispatcher request.
+ */
+ public static final String FORWARD_QUERY_STRING_ATTR =
+ "javax.servlet.forward.query_string";
+
+ /**
+ * The request attribute under which the original request URI is stored
+ * on an forwarded dispatcher request.
+ */
+ public static final String FORWARD_REQUEST_URI_ATTR =
+ "javax.servlet.forward.request_uri";
+
+
+ /**
+ * The request attribute under which the original context path is stored
+ * on an forwarded dispatcher request.
+ */
+ public static final String FORWARD_CONTEXT_PATH_ATTR =
+ "javax.servlet.forward.context_path";
+
+
+ /**
+ * The request attribute under which the original path info is stored
+ * on an forwarded dispatcher request.
+ */
+ public static final String FORWARD_PATH_INFO_ATTR =
+ "javax.servlet.forward.path_info";
+
+ /**
+ * The request attribute under which we store the servlet name on a
+ * named dispatcher request.
+ */
+ public static final String NAMED_DISPATCHER_ATTR =
+ "org.apache.catalina.NAMED";
+
+ /**
+ * The request attribute under which the request URI of the included
+ * servlet is stored on an included dispatcher request.
+ */
+ public static final String INCLUDE_REQUEST_URI_ATTR =
+ "javax.servlet.include.request_uri";
+
+
+ /**
+ * The request attribute under which the context path of the included
+ * servlet is stored on an included dispatcher request.
+ */
+ public static final String INCLUDE_CONTEXT_PATH_ATTR =
+ "javax.servlet.include.context_path";
+
+
+ /**
+ * The request attribute under which the path info of the included
+ * servlet is stored on an included dispatcher request.
+ */
+ public static final String INCLUDE_PATH_INFO_ATTR =
+ "javax.servlet.include.path_info";
+
+
+ /**
+ * The request attribute under which the servlet path of the included
+ * servlet is stored on an included dispatcher request.
+ */
+ public static final String INCLUDE_SERVLET_PATH_ATTR =
+ "javax.servlet.include.servlet_path";
+
+
+ /**
+ * The request attribute under which the query string of the included
+ * servlet is stored on an included dispatcher request.
+ */
+ public static final String INCLUDE_QUERY_STRING_ATTR =
+ "javax.servlet.include.query_string";
+
+ /**
+ * The request attribute under which we expose the value of the
+ * <code><jsp-file></code> value associated with this servlet,
+ * if any.
+ */
+ public static final String JSP_FILE_ATTR =
+ "org.apache.catalina.jsp_file";
+
+
+ // ----------------------------------------------------- Instance Variables
+
+ private static Logger log = Logger.getLogger(RequestDispatcherImpl.class.getName());
+
+ private ServletContextImpl ctx = null;
+
+ /**
+ * The servlet name for a named dispatcher.
+ */
+ private String name = null;
+
+ // Path for a path dispatcher
+ private String path;
+
+ /**
+ * MappingData object - per thread for buffering.
+ */
+ private transient ThreadLocal localMappingData = new ThreadLocal();
+
+ /*
+ OrigRequest(ServletRequestImpl) -> include/forward * -> this include
+
+ On the path: user-defined RequestWrapper or our ServletRequestWrapper
+
+ include() is called with a RequestWrapper(->...->origRequest) or origRequest
+
+ Based on params, etc -> we wrap the req / response in ServletRequestWrapper,
+ call filters+servlet. Inside, the req can be wrapped again in
+ userReqWrapper, and other include called.
+
+
+ */
+
+ /**
+ * The outermost request that will be passed on to the invoked servlet.
+ */
+ private ServletRequest outerRequest = null;
+
+ /**
+ * The outermost response that will be passed on to the invoked servlet.
+ */
+ private ServletResponse outerResponse = null;
+
+ /**
+ * The request wrapper we have created and installed (if any).
+ */
+ private ServletRequest wrapRequest = null;
+
+ /**
+ * The response wrapper we have created and installed (if any).
+ */
+ private ServletResponse wrapResponse = null;
+
+ // Parameters used when constructing the dispatcvher
+ /**
+ * The extra path information for this RequestDispatcher.
+ */
+ private String pathInfo = null;
+ /**
+ * The query string parameters for this RequestDispatcher.
+ */
+ private String queryString = null;
+ /**
+ * The request URI for this RequestDispatcher.
+ */
+ private String requestURI = null;
+ /**
+ * The servlet path for this RequestDispatcher.
+ */
+ private String servletPath = null;
+
+ //
+ private String origServletPath = null;
+
+ /**
+ * The Wrapper associated with the resource that will be forwarded to
+ * or included.
+ */
+ private ServletConfigImpl wrapper = null;
+
+ private Servlet servlet;
+
+ /** Named dispatcher
+ */
+ public RequestDispatcherImpl(ServletConfigImpl wrapper, String name) {
+ this.wrapper = wrapper;
+ this.name = name;
+ this.ctx = (ServletContextImpl) wrapper.getServletContext();
+
+ }
+
+ public RequestDispatcherImpl(ServletContextImpl ctx, String path) {
+ this.path = path;
+ this.ctx = ctx;
+ }
+
+
+
+ /**
+ * Forward this request and response to another resource for processing.
+ * Any runtime exception, IOException, or ServletException thrown by the
+ * called servlet will be propogated to the caller.
+ *
+ * @param request The servlet request to be forwarded
+ * @param response The servlet response to be forwarded
+ *
+ * @exception IOException if an input/output error occurs
+ * @exception ServletException if a servlet exception occurs
+ */
+ public void forward(ServletRequest request, ServletResponse response)
+ throws ServletException, IOException
+ {
+ // Reset any output that has been buffered, but keep headers/cookies
+ if (response.isCommitted()) {
+ throw new IllegalStateException("forward(): response.isComitted()");
+ }
+
+ try {
+ response.resetBuffer();
+ } catch (IllegalStateException e) {
+ throw e;
+ }
+
+ // Set up to handle the specified request and response
+ setup(request, response, false);
+
+ // Identify the HTTP-specific request and response objects (if any)
+ HttpServletRequest hrequest = (HttpServletRequest) request;
+
+ ServletRequestWrapperImpl wrequest =
+ (ServletRequestWrapperImpl) wrapRequest();
+
+
+ if (name != null) {
+ wrequest.setRequestURI(hrequest.getRequestURI());
+ wrequest.setContextPath(hrequest.getContextPath());
+ wrequest.setServletPath(hrequest.getServletPath());
+ wrequest.setPathInfo(hrequest.getPathInfo());
+ wrequest.setQueryString(hrequest.getQueryString());
+
+
+ } else { // path based
+ mapPath();
+ if (wrapper == null) {
+ throw new ServletException("Forward not found " +
+ path);
+ }
+ String contextPath = ctx.getContextPath();
+ if (hrequest.getAttribute(FORWARD_REQUEST_URI_ATTR) == null) {
+ wrequest.setAttribute(FORWARD_REQUEST_URI_ATTR,
+ hrequest.getRequestURI());
+ wrequest.setAttribute(FORWARD_CONTEXT_PATH_ATTR,
+ hrequest.getContextPath());
+ wrequest.setAttribute(FORWARD_SERVLET_PATH_ATTR,
+ hrequest.getServletPath());
+ wrequest.setAttribute(FORWARD_PATH_INFO_ATTR,
+ hrequest.getPathInfo());
+ wrequest.setAttribute(FORWARD_QUERY_STRING_ATTR,
+ hrequest.getQueryString());
+ }
+
+ wrequest.setContextPath(contextPath);
+ wrequest.setRequestURI(requestURI);
+ wrequest.setServletPath(servletPath);
+ wrequest.setPathInfo(pathInfo);
+ if (queryString != null) {
+ wrequest.setQueryString(queryString);
+ wrequest.setQueryParams(queryString);
+ }
+ }
+ processRequest(outerRequest, outerResponse);
+
+ wrequest.recycle();
+ unwrapRequest();
+
+ // This is not a real close in order to support error processing
+// if ( log.isDebugEnabled() )
+// log.debug(" Disabling the response for futher output");
+
+ if (response instanceof ServletResponseImpl) {
+ ((ServletResponseImpl) response).flushBuffer();
+ ((ServletResponseImpl) response).setSuspended(true);
+ } else {
+ // Servlet SRV.6.2.2. The Resquest/Response may have been wrapped
+ // and may no longer be instance of RequestFacade
+ if (log.isLoggable(Level.FINE)){
+ log.fine( " The Response is vehiculed using a wrapper: "
+ + response.getClass().getName() );
+ }
+
+ // Close anyway
+ try {
+ PrintWriter writer = response.getWriter();
+ writer.close();
+ } catch (IllegalStateException e) {
+ try {
+ ServletOutputStream stream = response.getOutputStream();
+ stream.close();
+ } catch (IllegalStateException f) {
+ ;
+ } catch (IOException f) {
+ ;
+ }
+ } catch (IOException e) {
+ ;
+ }
+ }
+ }
+
+
+
+ /**
+ * Include the response from another resource in the current response.
+ * Any runtime exception, IOException, or ServletException thrown by the
+ * called servlet will be propogated to the caller.
+ *
+ * @param request The servlet request that is including this one
+ * @param response The servlet response to be appended to
+ *
+ * @exception IOException if an input/output error occurs
+ * @exception ServletException if a servlet exception occurs
+ */
+ public void include(ServletRequest request, ServletResponse response)
+ throws ServletException, IOException
+ {
+
+ // Set up to handle the specified request and response
+ setup(request, response, true);
+
+ // Create a wrapped response to use for this request
+ // this actually gets inserted somewhere in the chain - it's not
+ // the last one, but first non-user response
+ wrapResponse();
+ ServletRequestWrapperImpl wrequest =
+ (ServletRequestWrapperImpl) wrapRequest();
+
+
+ // Handle an HTTP named dispatcher include
+ if (name != null) {
+ wrequest.setAttribute(NAMED_DISPATCHER_ATTR, name);
+ if (servletPath != null) wrequest.setServletPath(servletPath);
+ wrequest.setAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR,
+ new Integer(WebappFilterMapper.INCLUDE));
+ wrequest.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR,
+ origServletPath);
+ } else {
+ mapPath();
+ String contextPath = ctx.getContextPath();
+ if (requestURI != null)
+ wrequest.setAttribute(INCLUDE_REQUEST_URI_ATTR,
+ requestURI);
+ if (contextPath != null)
+ wrequest.setAttribute(INCLUDE_CONTEXT_PATH_ATTR,
+ contextPath);
+ if (servletPath != null)
+ wrequest.setAttribute(INCLUDE_SERVLET_PATH_ATTR,
+ servletPath);
+ if (pathInfo != null)
+ wrequest.setAttribute(INCLUDE_PATH_INFO_ATTR,
+ pathInfo);
+ if (queryString != null) {
+ wrequest.setAttribute(INCLUDE_QUERY_STRING_ATTR,
+ queryString);
+ wrequest.setQueryParams(queryString);
+ }
+
+ wrequest.setAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR,
+ new Integer(WebappFilterMapper.INCLUDE));
+ wrequest.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR,
+ origServletPath);
+ }
+
+ invoke(outerRequest, outerResponse);
+
+ wrequest.recycle();
+ unwrapRequest();
+ unwrapResponse();
+ }
+
+
+ // -------------------------------------------------------- Private Methods
+
+ public void mapPath() {
+ if (path == null || servletPath != null) return;
+
+ // Retrieve the thread local URI, used for mapping
+ // TODO: recycle RequestDispatcher stack and associated objects
+ // instead of this object
+
+ // Retrieve the thread local mapping data
+ MappingData mappingData = (MappingData) localMappingData.get();
+ if (mappingData == null) {
+ mappingData = new MappingData();
+ localMappingData.set(mappingData);
+ }
+
+ // Get query string
+ int pos = path.indexOf('?');
+ if (pos >= 0) {
+ queryString = path.substring(pos + 1);
+ } else {
+ pos = path.length();
+ }
+
+ // Map the URI
+ MessageBytes uriMB = MessageBytes.newInstance();
+ CharChunk charBuffer = new CharChunk();
+ //mappingData.localURIBytes;
+ uriMB.recycle();
+ //CharChunk uriCC = uriMB.getCharChunk();
+ try {
+ /*
+ * Ignore any trailing path params (separated by ';') for mapping
+ * purposes.
+ * This is sometimes broken - path params can be on any path
+ * component, not just last.
+ */
+ int semicolon = path.indexOf(';');
+ if (pos >= 0 && semicolon > pos) {
+ semicolon = -1;
+ }
+ if (ctx.getContextPath().length() > 1 ) {
+ charBuffer.append(ctx.getContextPath());
+ }
+ charBuffer.append(path, 0,
+ semicolon > 0 ? semicolon : pos);
+
+ // Wrap the buffer
+ uriMB.setChars(charBuffer.getBuffer(),
+ charBuffer.getOffset(),
+ charBuffer.getLength());
+
+ // TODO: make charBuffer part of request or something
+ ctx.getMapper().map(uriMB, mappingData);
+
+ // at least default wrapper must be returned
+
+ /*
+ * Append any trailing path params (separated by ';') that were
+ * ignored for mapping purposes, so that they're reflected in the
+ * RequestDispatcher's requestURI
+ */
+ if (semicolon > 0) {
+ // I don't think this will be used in future
+ charBuffer.append(path,
+ semicolon, pos - semicolon);
+ }
+ } catch (Exception e) {
+ log.log(Level.SEVERE, "getRequestDispatcher()", e);
+ }
+
+ wrapper = (ServletConfigImpl) mappingData.wrapper;
+ servletPath = mappingData.wrapperPath.toString();
+ pathInfo = mappingData.pathInfo.toString();
+
+ mappingData.recycle();
+
+ }
+
+
+ /**
+ * Prepare the request based on the filter configuration.
+ * @param request The servlet request we are processing
+ * @param response The servlet response we are creating
+ *
+ * @exception IOException if an input/output error occurs
+ * @exception ServletException if a servlet error occurs
+ */
+ private void processRequest(ServletRequest request,
+ ServletResponse response)
+ throws IOException, ServletException {
+ Integer disInt =
+ (Integer) request.getAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR);
+ if (disInt != null) {
+ if (disInt.intValue() != WebappFilterMapper.ERROR) {
+ outerRequest.setAttribute
+ (WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR,
+ origServletPath);
+ outerRequest.setAttribute
+ (WebappFilterMapper.DISPATCHER_TYPE_ATTR,
+ new Integer(WebappFilterMapper.FORWARD));
+ }
+ invoke(outerRequest, response);
+ }
+
+ }
+
+
+
+
+ /**
+ * Ask the resource represented by this RequestDispatcher to process
+ * the associated request, and create (or append to) the associated
+ * response.
+ * <p>
+ * <strong>IMPLEMENTATION NOTE</strong>: This implementation assumes
+ * that no filters are applied to a forwarded or included resource,
+ * because they were already done for the original request.
+ *
+ * @param request The servlet request we are processing
+ * @param response The servlet response we are creating
+ *
+ * @exception IOException if an input/output error occurs
+ * @exception ServletException if a servlet error occurs
+ */
+ private void invoke(ServletRequest request, ServletResponse response)
+ throws IOException, ServletException {
+
+ // Checking to see if the context classloader is the current context
+ // classloader. If it's not, we're saving it, and setting the context
+ // classloader to the Context classloader
+ ClassLoader oldCCL = Thread.currentThread().getContextClassLoader();
+ ClassLoader contextClassLoader = ctx.getClassLoader();
+
+ if (oldCCL != contextClassLoader) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ } else {
+ oldCCL = null;
+ }
+
+ // Initialize local variables we may need
+ HttpServletResponse hresponse = (HttpServletResponse) response;
+ IOException ioException = null;
+ ServletException servletException = null;
+ RuntimeException runtimeException = null;
+
+ servletException = allocateServlet(hresponse, servletException);
+
+ // Get the FilterChain Here
+ WebappFilterMapper factory =
+ ((ServletContextImpl)wrapper.getServletContext()).getFilterMapper();
+
+ FilterChainImpl filterChain = factory.createFilterChain(request,
+ wrapper,
+ servlet);
+
+ // Call the service() method for the allocated servlet instance
+ try {
+ String jspFile = wrapper.getJspFile();
+ if (jspFile != null)
+ request.setAttribute(JSP_FILE_ATTR, jspFile);
+ else
+ request.removeAttribute(JSP_FILE_ATTR);
+ // for includes/forwards
+ if ((servlet != null) && (filterChain != null)) {
+ filterChain.doFilter(request, response);
+ }
+ } catch (IOException e) {
+ ctx.getLogger().log(Level.WARNING, "RequestDispatcherImpl error " +
+ wrapper.getServletName(), e);
+ ioException = e;
+ } catch (UnavailableException e) {
+ ctx.getLogger().log(Level.WARNING, "RequestDispatcherImpl error " +
+ wrapper.getServletName(), e);
+ servletException = e;
+ wrapper.unavailable(e);
+ } catch (ServletException e) {
+ servletException = e;
+ } catch (RuntimeException e) {
+ ctx.getLogger().log(Level.WARNING, "RequestDispatcherImpl error " +
+ wrapper.getServletName(), e);
+ runtimeException = e;
+ }
+ request.removeAttribute(JSP_FILE_ATTR);
+
+ // Release the filter chain (if any) for this request
+ if (filterChain != null)
+ filterChain.release();
+
+ servletException = servletDealocate(servletException);
+
+ // Reset the old context class loader
+ if (oldCCL != null)
+ Thread.currentThread().setContextClassLoader(oldCCL);
+
+ // Unwrap request/response if needed
+ unwrapRequest();
+ unwrapResponse();
+
+ // Rethrow an exception if one was thrown by the invoked servlet
+ if (ioException != null)
+ throw ioException;
+ if (servletException != null)
+ throw servletException;
+ if (runtimeException != null)
+ throw runtimeException;
+
+ }
+
+ private ServletException servletDealocate(ServletException servletException)
+ {
+ if (servlet != null) {
+ wrapper.deallocate(servlet);
+ }
+ return servletException;
+ }
+
+ private ServletException allocateServlet(HttpServletResponse hresponse,
+ ServletException servletException)
+ throws IOException
+ {
+ boolean unavailable = false;
+
+ // Check for the servlet being marked unavailable
+ if (wrapper.isUnavailable()) {
+ ctx.getLogger().log(Level.WARNING, "isUnavailable() " + wrapper.getServletName());
+ long available = wrapper.getAvailable();
+ if ((available > 0L) && (available < Long.MAX_VALUE))
+ hresponse.setDateHeader("Retry-After", available);
+ hresponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
+ "Unavailable"); // No need to include internal info: wrapper.getServletName();
+ unavailable = true;
+ }
+
+ // Allocate a servlet instance to process this request
+ try {
+ if (!unavailable) {
+ servlet = wrapper.allocate();
+ }
+ } catch (ServletException e) {
+ ctx.getLogger().log(Level.WARNING, "RequestDispatcher: allocate " +
+ wrapper.toString());
+ servletException = e;
+ servlet = null;
+ } catch (Throwable e) {
+ ctx.getLogger().log(Level.WARNING, "allocate() error " + wrapper.getServletName(), e);
+ servletException = new ServletException
+ ("Allocate error " + wrapper.getServletName(), e);
+ servlet = null;
+ }
+ return servletException;
+ }
+
+
+ /**
+ * Set up to handle the specified request and response
+ *
+ * @param request The servlet request specified by the caller
+ * @param response The servlet response specified by the caller
+ * @param including Are we performing an include() as opposed to
+ * a forward()?
+ */
+ private void setup(ServletRequest request, ServletResponse response,
+ boolean including) {
+
+ this.outerRequest = request;
+ this.outerResponse = response;
+ }
+
+
+ /**
+ * Unwrap the request if we have wrapped it. Not sure how it could end
+ * up in the middle.
+ */
+ private void unwrapRequest() {
+ if (wrapRequest == null)
+ return;
+
+ ServletRequest previous = null;
+ ServletRequest current = outerRequest;
+ while (current != null) {
+ // If we run into the container request we are done
+ if (current instanceof ServletRequestImpl)
+ break;
+
+ // Remove the current request if it is our wrapper
+ if (current == wrapRequest) {
+ ServletRequest next =
+ ((ServletRequestWrapper) current).getRequest();
+ if (previous == null)
+ outerRequest = next;
+ else
+ ((ServletRequestWrapper) previous).setRequest(next);
+ break;
+ }
+
+ // Advance to the next request in the chain
+ previous = current;
+ current = ((ServletRequestWrapper) current).getRequest();
+ }
+ }
+
+
+ /**
+ * Unwrap the response if we have wrapped it.
+ */
+ private void unwrapResponse() {
+ if (wrapResponse == null)
+ return;
+
+ ServletResponse previous = null;
+ ServletResponse current = outerResponse;
+ while (current != null) {
+ // If we run into the container response we are done
+ if (current instanceof ServletResponseImpl)
+ break;
+
+ // Remove the current response if it is our wrapper
+ if (current == wrapResponse) {
+ ServletResponse next =
+ ((ServletResponseWrapper) current).getResponse();
+ if (previous == null)
+ outerResponse = next;
+ else
+ ((ServletResponseWrapper) previous).setResponse(next);
+ break;
+ }
+ // Advance to the next response in the chain
+ previous = current;
+ current = ((ServletResponseWrapper) current).getResponse();
+ }
+ }
+
+
+ /**
+ * Create and return a request wrapper that has been inserted in the
+ * appropriate spot in the request chain.
+ */
+ private ServletRequest wrapRequest() {
+ // Locate the request we should insert in front of
+ ServletRequest previous = null;
+ ServletRequest current = outerRequest;
+ while (current != null) {
+ if (!(current instanceof ServletRequestWrapper))
+ break;
+ if (current instanceof ServletRequestWrapperImpl)
+ break;
+ if (current instanceof ServletRequestImpl)
+ break;
+ // user-specified
+ previous = current;
+ current = ((ServletRequestWrapper) current).getRequest();
+ }
+ // now previous will be a user-specified wrapper,
+ // and current one of our own wrappers ( deeper in stack )
+ // ... current USER_previous USER USER
+ // previous is null if the top request is ours.
+
+ // Instantiate a new wrapper at this point and insert it in the chain
+ ServletRequest wrapper = null;
+
+ // Compute a crossContext flag
+ boolean crossContext = isCrossContext();
+ wrapper =
+ new ServletRequestWrapperImpl((HttpServletRequest) current,
+ ctx, crossContext);
+
+ if (previous == null) {
+ // outer becomes the wrapper, includes orig wrapper inside
+ outerRequest = wrapper;
+ } else {
+ // outer remains user-specified sersvlet, delegating to
+ // our wrapper, which delegates to real request or our wrapper.
+ ((ServletRequestWrapper) previous).setRequest(wrapper);
+ }
+ wrapRequest = wrapper;
+ return (wrapper);
+ }
+
+ private boolean isCrossContext() {
+ boolean crossContext = false;
+ if ((outerRequest instanceof ServletRequestWrapperImpl) ||
+ (outerRequest instanceof ServletRequestImpl) ||
+ (outerRequest instanceof HttpServletRequest)) {
+ HttpServletRequest houterRequest =
+ (HttpServletRequest) outerRequest;
+ Object contextPath =
+ houterRequest.getAttribute(INCLUDE_CONTEXT_PATH_ATTR);
+ if (contextPath == null) {
+ // Forward
+ contextPath = houterRequest.getContextPath();
+ }
+ crossContext = !(ctx.getContextPath().equals(contextPath));
+ }
+ return crossContext;
+ }
+
+
+ /**
+ * Create and return a response wrapper that has been inserted in the
+ * appropriate spot in the response chain.
+ *
+ * Side effect: updates outerResponse, wrapResponse.
+ * The chain is updated with a wrapper below lowest user wrapper
+ */
+ private ServletResponse wrapResponse() {
+ // Locate the response we should insert in front of
+ ServletResponse previous = null;
+ ServletResponse current = outerResponse;
+ while (current != null) {
+ if (!(current instanceof ServletResponseWrapper))
+ break;
+ if (current instanceof ServletResponseImpl)
+ break;
+ previous = current;
+ current = ((ServletResponseWrapper) current).getResponse();
+ }
+
+ // Instantiate a new wrapper at this point and insert it in the chain
+ ServletResponse wrapper =
+ new ServletResponseIncludeWrapper(current);
+
+ if (previous == null) {
+ // outer is ours, we can wrap on top
+ outerResponse = wrapper;
+ } else {
+ // outer is user-specified, leave it alone.
+ // we insert ourself below the lowest user-specified response
+ ((ServletResponseWrapper) previous).setResponse(wrapper);
+ }
+ wrapResponse = wrapper;
+ return (wrapper);
+
+ }
+
+
+}
--- /dev/null
+/*
+ * Copyright 1999-2002,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.coyote.servlet;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.MultipartConfigElement;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.ServletSecurityElement;
+import javax.servlet.SingleThreadModel;
+import javax.servlet.UnavailableException;
+
+import org.apache.tomcat.servlets.jsp.BaseJspLoader;
+import org.apache.tomcat.servlets.util.Enumerator;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * Based on Wrapper.
+ *
+ * Standard implementation of the <b>Wrapper</b> interface that represents
+ * an individual servlet definition. No child Containers are allowed, and
+ * the parent Container must be a Context.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ */
+@SuppressWarnings("deprecation")
+public class ServletConfigImpl implements ServletConfig, ServletRegistration {
+
+ ServletDynamicRegistration dynamic = new ServletDynamicRegistration();
+
+ protected boolean asyncSupported;
+
+ private static Logger log=
+ Logger.getLogger(ServletConfigImpl.class.getName());
+
+ private static final String[] DEFAULT_SERVLET_METHODS = new String[] {
+ "GET", "HEAD", "POST" };
+
+ // TODO: refactor all 'stm' to separate class (not implemented)
+ // public static final String SINGLE_THREADED_PROXY =
+ // "org.apache.tomcat.servlets.jsp.SingleThreadedProxyServlet";
+
+ protected String description;
+ protected Map<String, String> initParams = new HashMap<String, String>();
+ protected String servletName;
+ protected String servletClassName;
+ protected String jspFile;
+ protected int loadOnStartup = -1;
+ protected String runAs;
+ protected Map securityRoleRef = new HashMap(); // roleName -> [roleLink]
+
+ /**
+ * The date and time at which this servlet will become available (in
+ * milliseconds since the epoch), or zero if the servlet is available.
+ * If this value equals Long.MAX_VALUE, the unavailability of this
+ * servlet is considered permanent.
+ */
+ private transient long available = 0L;
+
+ private ServletContextImpl ctx;
+
+ /**
+ * The (single) initialized instance of this servlet.
+ */
+ private transient Servlet instance = null;
+
+ /**
+ * Are we unloading our servlet instance at the moment?
+ */
+ private transient boolean unloading = false;
+
+ private Class servletClass = null;
+
+ // Support for SingleThreaded
+ /**
+ * The count of allocations that are currently active (even if they
+ * are for the same instance, as will be true on a non-STM servlet).
+ */
+ private transient int countAllocated = 0;
+
+ private transient boolean singleThreadModel = false;
+ /**
+ * Stack containing the STM instances.
+ */
+ private transient Stack instancePool = null;
+
+
+ // Statistics
+ private transient long loadTime=0;
+ private transient int classLoadTime=0;
+
+ // ------------------------------------------------------------- Properties
+ public ServletConfigImpl(ServletContextImpl ctx, String name,
+ String classname) {
+ this.servletName = name;
+ this.servletClassName = classname;
+ this.ctx = ctx;
+ ctx.facade.notifyAdd(this);
+ }
+
+ /**
+ * Return the available date/time for this servlet, in milliseconds since
+ * the epoch. If this date/time is Long.MAX_VALUE, it is considered to mean
+ * that unavailability is permanent and any request for this servlet will return
+ * an SC_NOT_FOUND error. If this date/time is in the future, any request for
+ * this servlet will return an SC_SERVICE_UNAVAILABLE error. If it is zero,
+ * the servlet is currently available.
+ */
+ public long getAvailable() {
+ return (this.available);
+ }
+
+
+ /**
+ * Set the available date/time for this servlet, in milliseconds since the
+ * epoch. If this date/time is Long.MAX_VALUE, it is considered to mean
+ * that unavailability is permanent and any request for this servlet will return
+ * an SC_NOT_FOUND error. If this date/time is in the future, any request for
+ * this servlet will return an SC_SERVICE_UNAVAILABLE error.
+ *
+ * @param available The new available date/time
+ */
+ public void setAvailable(long available) {
+
+ long oldAvailable = this.available;
+ if (available > System.currentTimeMillis())
+ this.available = available;
+ else
+ this.available = 0L;
+
+ }
+
+
+ /**
+ * Return the number of active allocations of this servlet, even if they
+ * are all for the same instance (as will be true for servlets that do
+ * not implement <code>SingleThreadModel</code>.
+ */
+ public int getCountAllocated() {
+ return (this.countAllocated);
+ }
+
+ /**
+ * Return the jsp-file setting for this servlet.
+ */
+ public String getJspFile() {
+ return jspFile;
+ }
+
+ public void setJspFile(String s) {
+ this.jspFile = s;
+ }
+
+ /**
+ * Return the load-on-startup order value (negative value means
+ * load on first call).
+ */
+ public int getLoadOnStartup() {
+ return loadOnStartup;
+ }
+
+ /**
+ * Return the fully qualified servlet class name for this servlet.
+ */
+ public String getServletClass() {
+ return servletClassName;
+ }
+
+ /**
+ * Is this servlet currently unavailable?
+ */
+ public boolean isUnavailable() {
+ if (available == 0L)
+ return (false);
+ else if (available <= System.currentTimeMillis()) {
+ available = 0L;
+ return (false);
+ } else
+ return (true);
+
+ }
+
+
+ /**
+ * Gets the names of the methods supported by the underlying servlet.
+ *
+ * This is the same set of methods included in the Allow response header
+ * in response to an OPTIONS request method processed by the underlying
+ * servlet.
+ *
+ * @return Array of names of the methods supported by the underlying
+ * servlet
+ */
+ public String[] getServletMethods() throws ServletException {
+
+ Class servletClazz = loadServlet().getClass();
+ if (!javax.servlet.http.HttpServlet.class.isAssignableFrom(
+ servletClazz)) {
+ return DEFAULT_SERVLET_METHODS;
+ }
+
+ HashSet allow = new HashSet();
+ allow.add("TRACE");
+ allow.add("OPTIONS");
+
+ Method[] methods = getAllDeclaredMethods(servletClazz);
+ for (int i=0; methods != null && i<methods.length; i++) {
+ Method m = methods[i];
+
+ if (m.getName().equals("doGet")) {
+ allow.add("GET");
+ allow.add("HEAD");
+ } else if (m.getName().equals("doPost")) {
+ allow.add("POST");
+ } else if (m.getName().equals("doPut")) {
+ allow.add("PUT");
+ } else if (m.getName().equals("doDelete")) {
+ allow.add("DELETE");
+ }
+ }
+
+ String[] methodNames = new String[allow.size()];
+ return (String[]) allow.toArray(methodNames);
+
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Extract the root cause from a servlet exception.
+ *
+ * @param e The servlet exception
+ */
+ public static Throwable getRootCause(ServletException e) {
+ Throwable rootCause = e;
+ Throwable rootCauseCheck = null;
+ // Extra aggressive rootCause finding
+ do {
+ try {
+ rootCauseCheck = (Throwable)IntrospectionUtils.getProperty
+ (rootCause, "rootCause");
+ if (rootCauseCheck!=null)
+ rootCause = rootCauseCheck;
+
+ } catch (ClassCastException ex) {
+ rootCauseCheck = null;
+ }
+ } while (rootCauseCheck != null);
+ return rootCause;
+ }
+
+ /**
+ * MUST be called before service()
+ * This method should be called to get the servlet. After
+ * service(), dealocate should be called. This deals with STM and
+ * update use counters.
+ *
+ * Normally called from RequestDispatcher and TomcatLite.
+ */
+ public Servlet allocate() throws ServletException {
+ // If we are currently unloading this servlet, throw an exception
+ if (unloading)
+ throw new ServletException
+ ("allocate() while unloading " + getServletName());
+
+ Servlet servlet = null;
+ if (instance == null && !singleThreadModel) {
+ // never loaded.
+ synchronized (this) {
+ if (instance == null && !singleThreadModel) {
+ try {
+ servlet = loadServlet();
+ } catch (ServletException e) {
+ throw e;
+ } catch (Throwable e) {
+ throw new ServletException("loadServlet()", e);
+ }
+ if (servlet != null && !singleThreadModel) {
+ setServlet(servlet);
+ }
+ }
+ }
+ }
+
+ // If not SingleThreadedModel, return the same instance every time
+ if (instance != null) {
+ countAllocated++;
+ return (instance);
+ }
+
+ // Simpler policy for ST: unbound number of servlets ( can grow to
+ // one per thread )
+
+ synchronized (instancePool) {
+ if (instancePool.isEmpty()) {
+ try {
+ if (servlet != null) {
+ // this is the first invocation
+ countAllocated++;
+ return servlet;
+ }
+ countAllocated++;
+ Servlet newServlet = loadServlet();
+ log.fine("New STM servet " + newServlet + " " +
+ countAllocated);
+ return newServlet;
+ } catch (ServletException e) {
+ throw e;
+ } catch (Throwable e) {
+ throw new ServletException("allocate " + getServletName(),
+ e);
+ }
+ }
+ log.fine("Get from pool " + instancePool.size() + " " +
+ countAllocated);
+ Servlet s = (Servlet) instancePool.pop();
+ countAllocated++;
+ log.fine("After get " + instancePool.size() + " " + s +
+ " " + countAllocated);
+ return s;
+ }
+ }
+
+
+ /**
+ * MUST be called after service().
+ */
+ public void deallocate(Servlet servlet) {
+ // If not SingleThreadModel, no action is required
+ if (!singleThreadModel) {
+ countAllocated--;
+ return;
+ }
+
+ // Unlock and free this instance
+ synchronized (instancePool) {
+ countAllocated--;
+ if (instancePool.contains(servlet)) {
+ System.err.println("Aleady in pool " + servlet + " "
+ + instancePool.size()+ " " + countAllocated);
+ return;
+ }
+ System.err.println("return pool " + servlet + " " +
+ instancePool.size() + " " + countAllocated);
+ instancePool.push(servlet);
+ }
+ }
+
+ public Servlet newInstance() throws ServletException {
+ String actualClass = servletClassName;
+
+ if (instance != null) {
+ return instance;
+ }
+ if (actualClass == null) {
+ // No explicit name. Try to use the framework
+ if (jspFile != null) {
+
+ // Named JSPs can be handled by a servlet or by the mapper.
+ BaseJspLoader mapper = new JspLoader();
+ try {
+ return mapper.loadProxy(jspFile, ctx, this);
+ } catch (IOException e) {
+ throw new ServletException(e);
+ }
+ }
+ if (actualClass == null) {
+ // Covers 'default-" and "jspwildcard-" servlets as well
+ Servlet res = (Servlet) ctx.getObjectManager().get( servletName +
+ "-servlet");
+ if (res != null) {
+ servletClass = res.getClass();
+ actualClass = servletClass.getName();
+ return res;
+ }
+ }
+
+ //ctx.getObjectManager().getObject(c);
+ //ctx.getObjectManager().getObject(servletName);
+ }
+
+
+ if (servletClass == null) {
+ // set classClass
+ loadClass(actualClass);
+ }
+
+
+ // jsp-file case. Load the JspProxyServlet instead, with the
+ // right params. Note the JspProxyServlet is _not_ jasper,
+ // nor 'jsp' servlet - it is just a proxy with no special
+ // params. It calls the jsp servlet and jasper to generate the
+ // real class.
+
+ // this is quite different from catalina, where an ugly kludge was
+ // used to use the same jsp servlet in 2 roles
+
+ // the jsp proxy is replaced by the web.xml processor
+
+ if (servletClass == null) {
+ unavailable(null);
+ throw new UnavailableException("ClassNotFound: " + actualClass);
+ }
+
+ // Instantiate and initialize an instance of the servlet class itself
+ try {
+ return (Servlet) servletClass.newInstance();
+ } catch (ClassCastException e) {
+ unavailable(null);
+ throw new UnavailableException("ClassCast: (Servlet)" +
+ actualClass);
+ } catch (Throwable e) {
+ unavailable(null);
+
+ // Added extra log statement for Bugzilla 36630:
+ // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630
+ if(log.isLoggable(Level.FINE)) {
+ log.log(Level.FINE, "newInstance() error: servlet-name: " +
+ getServletName() +
+ " servlet-class: " + actualClass, e);
+ }
+
+ // Restore the context ClassLoader
+ throw new ServletException("newInstance() error " + getServletName() +
+ " " + actualClass, e);
+ }
+ }
+
+ /**
+ * Load and initialize an instance of this servlet, if there is not already
+ * at least one initialized instance. This can be used, for example, to
+ * load servlets that are marked in the deployment descriptor to be loaded
+ * at server startup time.
+ */
+ public synchronized Servlet loadServlet() throws ServletException {
+ // Nothing to do if we already have an instance or an instance pool
+ if (!singleThreadModel && (instance != null))
+ return instance;
+
+ long t1=System.currentTimeMillis();
+
+ Servlet servlet = newInstance();
+
+ classLoadTime=(int) (System.currentTimeMillis() -t1);
+
+ // Call the initialization method of this servlet
+ try {
+ servlet.init(this);
+ } catch (UnavailableException f) {
+ unavailable(f);
+ throw f;
+ } catch (ServletException f) {
+ throw f;
+ } catch (Throwable f) {
+ getServletContext().log("StandardWrapper.Throwable", f );
+ throw new ServletException("Servlet.init()", f);
+ }
+
+ // Register our newly initialized instance
+ singleThreadModel = servlet instanceof SingleThreadModel;
+ if (singleThreadModel) {
+ if (instancePool == null)
+ instancePool = new Stack();
+ }
+ loadTime=System.currentTimeMillis() -t1;
+
+ return servlet;
+ }
+
+
+ private void loadClass(String actualClass) throws ServletException {
+ // Complain if no servlet class has been specified
+ if (actualClass == null) {
+ unavailable(null);
+ throw new ServletException("servlet-class missing " +
+ getServletName());
+ }
+
+ ClassLoader classLoader = ctx.getClassLoader();
+ if (classLoader == null )
+ classLoader = this.getClass().getClassLoader();
+
+ // Load the specified servlet class from the appropriate class loader
+ try {
+ servletClass = classLoader.loadClass(actualClass);
+ } catch (ClassNotFoundException e) {
+ servletClass = null;
+ }
+ }
+
+ /**
+ * Return a String representation of this component.
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (ctx != null) {
+ sb.append(ctx.toString());
+ sb.append(".");
+ }
+ sb.append("Servlet[");
+ sb.append(getServletName()).append(" ");
+ sb.append(servletClassName);
+ if (jspFile != null) {
+ sb.append(" jsp=").append(jspFile);
+ }
+ sb.append("]");
+ return (sb.toString());
+ }
+
+
+ /**
+ * Process an UnavailableException, marking this servlet as unavailable
+ * for the specified amount of time.
+ *
+ * @param unavailable The exception that occurred, or <code>null</code>
+ * to mark this servlet as permanently unavailable
+ */
+ public void unavailable(UnavailableException unavailable) {
+ getServletContext().log("UnavailableException:" + getServletName());
+ if (unavailable == null)
+ setAvailable(Long.MAX_VALUE);
+ else if (unavailable.isPermanent())
+ setAvailable(Long.MAX_VALUE);
+ else {
+ int unavailableSeconds = unavailable.getUnavailableSeconds();
+ if (unavailableSeconds <= 0)
+ unavailableSeconds = 60; // Arbitrary default
+ setAvailable(System.currentTimeMillis() +
+ (unavailableSeconds * 1000L));
+ }
+
+ }
+
+
+ /**
+ * Unload all initialized instances of this servlet, after calling the
+ * <code>destroy()</code> method for each instance. This can be used,
+ * for example, prior to shutting down the entire servlet engine, or
+ * prior to reloading all of the classes from the Loader associated with
+ * our Loader's repository.
+ *
+ * @exception ServletException if an exception is thrown by the
+ * destroy() method
+ */
+ public synchronized void unload() throws ServletException {
+ setAvailable(Long.MAX_VALUE);
+
+ // Nothing to do if we have never loaded the instance
+ if (!singleThreadModel && (instance == null))
+ return;
+ unloading = true;
+
+ // Loaf a while if the current instance is allocated
+ // (possibly more than once if non-STM)
+ if (countAllocated > 0) {
+ int nRetries = 0;
+ long delay = ctx.getUnloadDelay() / 20;
+ while ((nRetries < 21) && (countAllocated > 0)) {
+ if ((nRetries % 10) == 0) {
+ log.info("Servlet.unload() timeout " +
+ countAllocated);
+ }
+ try {
+ Thread.sleep(delay);
+ } catch (InterruptedException e) {
+ ;
+ }
+ nRetries++;
+ }
+ }
+
+ ClassLoader oldCtxClassLoader =
+ Thread.currentThread().getContextClassLoader();
+ if (instance != null) {
+ ClassLoader classLoader = instance.getClass().getClassLoader();
+
+ PrintStream out = System.out;
+ // Call the servlet destroy() method
+ try {
+ Thread.currentThread().setContextClassLoader(classLoader);
+ instance.destroy();
+ } catch (Throwable t) {
+ instance = null;
+ //instancePool = null;
+ unloading = false;
+ throw new ServletException("Servlet.destroy() " +
+ getServletName(), t);
+ } finally {
+ // restore the context ClassLoader
+ Thread.currentThread().setContextClassLoader(oldCtxClassLoader);
+ }
+
+ // Deregister the destroyed instance
+ instance = null;
+ }
+ if (singleThreadModel && (instancePool != null)) {
+ try {
+ ClassLoader classLoader = ctx.getClassLoader();
+ Thread.currentThread().setContextClassLoader(classLoader);
+ while (!instancePool.isEmpty()) {
+ ((Servlet) instancePool.pop()).destroy();
+ }
+ } catch (Throwable t) {
+ instancePool = null;
+ unloading = false;
+ throw new ServletException("Servlet.destroy() " + getServletName(), t);
+ } finally {
+ // restore the context ClassLoader
+ Thread.currentThread().setContextClassLoader
+ (oldCtxClassLoader);
+ }
+ instancePool = null;
+ }
+
+ singleThreadModel = false;
+
+ unloading = false;
+ }
+
+
+ /**
+ * Return the initialization parameter value for the specified name,
+ * if any; otherwise return <code>null</code>.
+ *
+ * @param name Name of the initialization parameter to retrieve
+ */
+ public String getInitParameter(String name) {
+ return initParams.get(name);
+ }
+
+
+ /**
+ * Return the set of initialization parameter names defined for this
+ * servlet. If none are defined, an empty Enumeration is returned.
+ */
+ public Enumeration getInitParameterNames() {
+ synchronized (initParams) {
+ return (new Enumerator(initParams.keySet()));
+ }
+ }
+
+
+ /**
+ * Return the servlet context with which this servlet is associated.
+ */
+ public ServletContext getServletContext() {
+ return ctx;
+ }
+
+
+ /**
+ * Return the name of this servlet.
+ */
+ public String getServletName() {
+ return servletName;
+ }
+
+// public long getProcessingTime() {
+// return swValve.getProcessingTime();
+// }
+//
+// public void setProcessingTime(long processingTime) {
+// swValve.setProcessingTime(processingTime);
+// }
+//
+// public long getMaxTime() {
+// return swValve.getMaxTime();
+// }
+//
+// public void setMaxTime(long maxTime) {
+// swValve.setMaxTime(maxTime);
+// }
+//
+// public long getMinTime() {
+// return swValve.getMinTime();
+// }
+//
+// public void setMinTime(long minTime) {
+// swValve.setMinTime(minTime);
+// }
+//
+// public int getRequestCount() {
+// return swValve.getRequestCount();
+// }
+//
+// public void setRequestCount(int requestCount) {
+// swValve.setRequestCount(requestCount);
+// }
+//
+// public int getErrorCount() {
+// return swValve.getErrorCount();
+// }
+//
+// public void setErrorCount(int errorCount) {
+// swValve.setErrorCount(errorCount);
+// }
+//
+// /**
+// * Increment the error count used for monitoring.
+// */
+// public void incrementErrorCount(){
+// swValve.setErrorCount(swValve.getErrorCount() + 1);
+// }
+//
+// public long getLoadTime() {
+// return loadTime;
+// }
+//
+// public void setLoadTime(long loadTime) {
+// this.loadTime = loadTime;
+// }
+//
+// public int getClassLoadTime() {
+// return classLoadTime;
+// }
+
+ // -------------------------------------------------------- Package Methods
+
+
+ // -------------------------------------------------------- Private Methods
+
+ private Method[] getAllDeclaredMethods(Class c) {
+
+ if (c.equals(javax.servlet.http.HttpServlet.class)) {
+ return null;
+ }
+
+ Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
+
+ Method[] thisMethods = c.getDeclaredMethods();
+ if (thisMethods == null) {
+ return parentMethods;
+ }
+
+ if ((parentMethods != null) && (parentMethods.length > 0)) {
+ Method[] allMethods =
+ new Method[parentMethods.length + thisMethods.length];
+ System.arraycopy(parentMethods, 0, allMethods, 0,
+ parentMethods.length);
+ System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
+ thisMethods.length);
+
+ thisMethods = allMethods;
+ }
+
+ return thisMethods;
+ }
+
+ /** Specify the instance. Avoids the class lookup, disables unloading.
+ * Use for embedded case, or to control the allocation.
+ *
+ * @param servlet
+ */
+ public void setServlet(Servlet servlet) {
+ instance = servlet;
+ ctx.getObjectManager().bind("Servlet:" +
+ ctx.getContextPath() + ":" + getServletName(),
+ this);
+ }
+
+ public String getSecurityRoleRef(String role) {
+ return (String)securityRoleRef.get(role);
+ }
+
+ public void setSecurityRoleRef(Map securityRoles) {
+ this.securityRoleRef = securityRoles;
+ }
+
+ public void setConfig(Map initParams) {
+ this.initParams = initParams;
+ }
+
+ public void setLoadOnStartup(int loadOnStartup) {
+ this.loadOnStartup = loadOnStartup;
+ }
+
+ @Override
+ public Set<String> addMapping(String... urlPatterns) {
+ if (ctx.startDone) {
+ // Use the context method instead of the servlet API to
+ // add mappings after context init.
+ throw new IllegalStateException();
+ }
+ Set<String> failed = new HashSet<String>();
+ for (String url: urlPatterns) {
+ if (url == null) {
+ throw new IllegalArgumentException();
+ }
+ if (ctx.contextConfig.servletMapping.get(url) != null) {
+ failed.add(url);
+ } else {
+ ctx.contextConfig.servletMapping.put(url, getServletName());
+ ctx.addMapping(url, this);
+ }
+ }
+ return failed;
+ }
+
+
+ @Override
+ public boolean setInitParameter(String name, String value)
+ throws IllegalArgumentException, IllegalStateException {
+ return ServletContextImpl.setInitParameter(ctx, initParams,
+ name, value);
+ }
+
+
+ @Override
+ public Set<String> setInitParameters(Map<String, String> initParameters)
+ throws IllegalArgumentException, IllegalStateException {
+ return ServletContextImpl.setInitParameters(ctx, initParams,
+ initParameters);
+ }
+
+ public Dynamic getDynamic() {
+ return dynamic;
+ }
+
+ class ServletDynamicRegistration implements Dynamic {
+
+
+ @Override
+ public void setAsyncSupported(boolean isAsyncSupported)
+ throws IllegalStateException {
+ asyncSupported = isAsyncSupported;
+ }
+
+
+ public void setDescription(String description)
+ throws IllegalStateException {
+ ServletConfigImpl.this.description = description;
+ }
+
+ @Override
+ public Set<String> setServletSecurity(ServletSecurityElement constraint) {
+ //implement me
+ return null;
+ }
+
+ @Override
+ public void setLoadOnStartup(int loadOnStartup) {
+ //implement me - here to compile
+ }
+
+ @Override
+ public void setMultipartConfig(MultipartConfigElement multipartConfig) {
+ //implement me - here to compile
+ }
+
+ @Override
+ public void setRunAsRole(String roleName) {
+ //implement me - here to compile
+ }
+
+ @Override
+ public String getRunAsRole() {
+ //implement me - here to compile
+ return null;
+ }
+
+ @Override
+ public Collection<String> getMappings() {
+ //implement me
+ return null;
+ }
+
+ @Override
+ public Set<String> addMapping(String... urlPatterns) {
+ //implement me
+ return null;
+ }
+
+ @Override
+ public Map<String, String> getInitParameters() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public Set<String> setInitParameters(Map<String, String> initParameters)
+ throws IllegalArgumentException, IllegalStateException {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public String getClassName() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public String getInitParameter(String name) {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public boolean setInitParameter(String name, String value)
+ throws IllegalArgumentException, IllegalStateException {
+ // implement me
+ return false;
+ }
+
+ }
+
+ @Override
+ public Collection<String> getMappings() {
+ //implement me
+ return null;
+ }
+
+ public void setServletClass(Class<? extends Servlet> servletClass2) {
+ servletClass = servletClass2;
+ }
+
+
+ @Override
+ public String getRunAsRole() {
+ //implement me
+ return null;
+ }
+
+
+ @Override
+ public Map<String, String> getInitParameters() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public String getClassName() {
+ // implement me
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ // implement me
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.coyote.servlet;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.naming.NamingException;
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterRegistration;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextAttributeEvent;
+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 javax.servlet.descriptor.JspConfigDescriptor;
+
+import org.apache.tomcat.InstanceManager;
+import org.apache.tomcat.servlets.session.UserSessionManager;
+import org.apache.tomcat.integration.ObjectManager;
+import org.apache.tomcat.servlets.config.ConfigLoader;
+import org.apache.tomcat.servlets.config.ServletContextConfig;
+import org.apache.tomcat.servlets.config.ServletContextConfig.FilterData;
+import org.apache.tomcat.servlets.config.ServletContextConfig.FilterMappingData;
+import org.apache.tomcat.servlets.config.ServletContextConfig.ServletData;
+import org.apache.tomcat.servlets.config.deploy.WarDeploy;
+import org.apache.tomcat.servlets.util.Enumerator;
+import org.apache.tomcat.servlets.util.RequestUtil;
+import org.apache.tomcat.servlets.util.UrlUtils;
+import org.apache.tomcat.util.http.MimeMap;
+
+
+/**
+ * Context - initialized from web.xml or using APIs.
+ *
+ * Initialization order:
+ *
+ * - add all listeners
+ * - add all filters
+ * - add all servlets
+ *
+ * - session parameters
+ * -
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision$ $Date$
+ */
+
+public class ServletContextImpl implements ServletContext {
+
+ /**
+ * Empty collection to serve as the basis for empty enumerations.
+ */
+ private transient static final ArrayList empty = new ArrayList();
+
+ transient Logger log;
+
+ /**
+ * Base path - the directory root of the webapp
+ */
+ protected String basePath = null;
+
+ protected String contextPath;
+
+ // All config from web.xml
+ protected ServletContextConfig contextConfig = new ServletContextConfig();
+
+ MimeMap contentTypes = new MimeMap();
+
+ /**
+ * The context attributes for this context.
+ */
+ protected transient Map<String, Object> attributes = new HashMap<String, Object>();
+
+ /**
+ * List of read only attributes for this context.
+ * In catalina - used to protect workdir att. We trust the app, so no need
+ * for extra complexity.
+ */
+ //protected transient HashMap readOnlyAttributes = new HashMap();
+
+ protected transient ArrayList<EventListener> lifecycleListeners = new ArrayList();
+
+ protected UserSessionManager manager;
+
+ HashMap<String, FilterConfigImpl> filters = new HashMap<String, FilterConfigImpl>();
+
+ HashMap<String, ServletConfigImpl> servlets = new HashMap<String, ServletConfigImpl>();
+
+ ArrayList<String> securityRoles = new ArrayList<String>();
+
+ /** Mapper for filters.
+ */
+ protected WebappFilterMapper webappFilterMapper;
+
+ /** Internal mapper for request dispatcher, must have all
+ * context mappings.
+ */
+ protected WebappServletMapper mapper;
+
+ transient Locale2Charset charsetMapper = new Locale2Charset();
+
+ transient TomcatLite facade;
+
+ ObjectManager om;
+
+ private String hostname;
+
+
+ boolean initDone = false;
+
+ boolean startDone = false;
+
+ String jspcServlet = "org.apache.tomcat.servlets.jspc.JspcServlet";
+
+
+ // ------------------------------------------------- ServletContext Methods
+ public ServletContextImpl() {
+ }
+
+ public void setTomcat(TomcatLite facade) {
+ this.facade = facade;
+ }
+
+ /**
+ * Registry/framework interface associated with the context.
+ * Also available as a context attribute.
+ * @return
+ */
+ public ObjectManager getObjectManager() {
+ if (om == null) {
+ om = facade.getObjectManager();
+ }
+ return om;
+ }
+
+ public void setObjectManager(ObjectManager om) {
+ this.om = om;
+ }
+
+ public Locale2Charset getCharsetMapper() {
+ return charsetMapper;
+ }
+
+ /**
+ * Set the context path, starting with "/" - "/" for ROOT
+ * @param path
+ */
+ public void setContextPath(String path) {
+ this.contextPath = path;
+ log = Logger.getLogger("webapp" + path.replace('/', '.'));
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ /** The directory where this app is based. May be null.
+ *
+ * @param basePath
+ */
+ public void setBasePath(String basePath) {
+ this.basePath = basePath;
+ }
+
+ public ServletContextConfig getContextConfig() {
+ return contextConfig;
+ }
+
+ /** The directory where this app is based.
+ *
+ * @param basePath
+ */
+ public String getBasePath() {
+ return basePath;
+ }
+
+ public String getEncodedPath() {
+ return null;
+ }
+
+
+ public boolean getCookies() {
+ return false;
+ }
+
+
+ public ServletContext getServletContext() {
+ return this;
+ }
+
+ public List<EventListener> getListeners() {
+ return lifecycleListeners;
+ }
+
+ public void addListener(Class <? extends EventListener> listenerClass) {
+ // implement me
+ }
+
+ public void addListener(String className) {
+ // implement me
+ }
+
+ public <T extends EventListener> void addListener(T t) {
+ lifecycleListeners.add(t);
+ }
+
+
+ public void removeListener(EventListener listener) {
+ lifecycleListeners.remove(listener);
+ }
+
+
+
+ public Logger getLogger() {
+ return log;
+ }
+
+ public long getUnloadDelay() {
+ return 0;
+ }
+
+ public ServletConfigImpl getServletConfig(String jsp_servlet_name) {
+ return (ServletConfigImpl)servlets.get(jsp_servlet_name);
+ }
+
+ public Map getServletConfigs() {
+ return servlets;
+ }
+
+ /**
+ * Add a servlet to the context.
+ * Called from processWebAppData()
+ *
+ * @param servletConfig
+ */
+ public void addServletConfig(ServletConfigImpl servletConfig) {
+ servlets.put(servletConfig.getServletName(), servletConfig);
+ }
+
+ public boolean getPrivileged() {
+ return false;
+ }
+
+
+ public Map getFilters() {
+ return filters;
+ }
+
+
+ protected boolean getCrossContext() {
+ return true;
+ }
+
+ public void addMimeType(String ext, String type) {
+ contentTypes.addContentType(ext, type);
+ }
+
+ public WebappServletMapper getMapper() {
+ if (mapper == null) {
+ Object customMapper = getObjectManager().get(WebappServletMapper.class);
+ if (customMapper == null) {
+ mapper = new WebappServletMapper();
+ } else {
+ mapper = (WebappServletMapper) customMapper;
+ }
+ mapper.setServletContext(this);
+ }
+
+ return mapper;
+ }
+
+ public WebappFilterMapper getFilterMapper() {
+ if (webappFilterMapper == null) {
+ Object customMapper = getObjectManager().get(WebappFilterMapper.class);
+ if (customMapper == null) {
+ webappFilterMapper = new WebappFilterMapper();
+ } else {
+ webappFilterMapper = (WebappFilterMapper) customMapper;
+ }
+ webappFilterMapper.setServletContext(this);
+ }
+
+ return webappFilterMapper ;
+ }
+
+ public FilterConfigImpl getFilter(String name) {
+ return (FilterConfigImpl)filters.get(name);
+ }
+
+ /**
+ * Return the value of the specified context attribute, if any;
+ * otherwise return <code>null</code>.
+ *
+ * @param name Name of the context attribute to return
+ */
+ public Object getAttribute(String name) {
+ if ("ObjectManager".equals(name)) {
+ return om;
+ }
+ if ("context-listeners".equals(name)) {
+ return lifecycleListeners;
+ }
+ return (attributes.get(name));
+ }
+
+ /**
+ * Return an enumeration of the names of the context attributes
+ * associated with this context.
+ */
+ public Enumeration getAttributeNames() {
+ return new Enumerator(attributes.keySet(), true);
+ }
+
+
+ public void addSecurityRole(String role) {
+ securityRoles.add(role);
+ }
+
+ public List getSecurityRoles() {
+ return securityRoles;
+ }
+
+ /**
+ * Return a <code>ServletContext</code> object that corresponds to a
+ * specified URI on the server. This method allows servlets to gain
+ * access to the context for various parts of the server, and as needed
+ * obtain <code>RequestDispatcher</code> objects or resources from the
+ * context. The given path must be absolute (beginning with a "/"),
+ * and is interpreted based on our virtual host's document root.
+ *
+ * @param uri Absolute URI of a resource on the server
+ */
+ public ServletContext getContext(String uri) {
+ // TODO: support real uri ( http://host/path )
+ // Validate the format of the specified argument
+ if ((uri == null) || (!uri.startsWith("/")))
+ return (null);
+
+ ServletContextImpl child = null;
+ try {
+ child = facade.getContext(this, uri);
+ } catch (IOException e) {
+ } catch (ServletException e) {
+ }
+
+ if (child == null)
+ return (null);
+
+ if (this.getCrossContext()) {
+ // If crossContext is enabled, can always return the context
+ return child.getServletContext();
+ } else if (child == this) {
+ // Can still return the current context
+ return this.getServletContext();
+ } else {
+ // Nothing to return
+ return (null);
+ }
+ }
+
+
+ /**
+ * Return the main path associated with this context.
+ */
+ public String getContextPath() {
+ return contextPath;
+ }
+
+
+ /**
+ * Return the value of the specified initialization parameter, or
+ * <code>null</code> if this parameter does not exist.
+ *
+ * @param name Name of the initialization parameter to retrieve
+ */
+ public String getInitParameter(final String name) {
+ return ((String) contextConfig.contextParam.get(name));
+ }
+
+
+ /**
+ * Return the names of the context's initialization parameters, or an
+ * empty enumeration if the context has no initialization parameters.
+ */
+ public Enumeration getInitParameterNames() {
+ return (new Enumerator(contextConfig.contextParam.keySet()));
+ }
+
+ public void setContextParams(Map newParams) {
+ contextConfig.contextParam = (HashMap) newParams;
+ }
+
+ /**
+ * Return the major version of the Java Servlet API that we implement.
+ */
+ public int getMajorVersion() {
+ return 3;
+ }
+
+
+ /**
+ * Return the minor version of the Java Servlet API that we implement.
+ */
+ public int getMinorVersion() {
+ return 0;
+ }
+
+
+ /**
+ * Return the MIME type of the specified file, or <code>null</code> if
+ * the MIME type cannot be determined.
+ *
+ * @param file Filename for which to identify a MIME type
+ */
+ public String getMimeType(String file) {
+ return contentTypes.getMimeType(file);
+ }
+
+ /**
+ * Return the real path for a given virtual path, if possible; otherwise
+ * return <code>null</code>.
+ *
+ * @param path The path to the desired resource
+ */
+ public String getRealPath(String path) {
+ if (path == null) {
+ return null;
+ }
+
+ File file = new File(basePath, path);
+ return (file.getAbsolutePath());
+ }
+
+ /**
+ * Return a <code>RequestDispatcher</code> object that acts as a
+ * wrapper for the named servlet.
+ *
+ * @param name Name of the servlet for which a dispatcher is requested
+ */
+ public RequestDispatcher getNamedDispatcher(String name) {
+ if (name == null) return null;
+ ServletConfigImpl wrapper =
+ (ServletConfigImpl) this.getServletConfig(name);
+ if (wrapper == null) return null;
+
+ return new RequestDispatcherImpl(wrapper, name);
+ }
+
+
+ /**
+ * Return a <code>RequestDispatcher</code> instance that acts as a
+ * wrapper for the resource at the given path. The path must begin
+ * with a "/" and is interpreted as relative to the current context root.
+ *
+ * @param path The path to the desired resource.
+ */
+ public RequestDispatcher getRequestDispatcher(String path) {
+ if (path == null) return null;
+
+ if (!path.startsWith("/"))
+ throw new IllegalArgumentException(path);
+
+ path = UrlUtils.normalize(path);
+ if (path == null) return (null);
+
+
+ return new RequestDispatcherImpl(this, path);
+ }
+
+ public RequestDispatcher getRequestDispatcher(String path,
+ int type,
+ String dispatcherPath) {
+ RequestDispatcher dispatcher = getRequestDispatcher(path);
+ //((RequestDispatcherImpl)dispatcher);
+ return dispatcher;
+ }
+
+ ThreadLocal requestDispatcherStack = new ThreadLocal();
+
+ private String classPath;
+
+ protected ClassLoader classLoader;
+
+// protected RequestDispatcherImpl getRequestDispatcher() {
+// ArrayList/*<RequestDispatcherImpl>*/ list =
+// (ArrayList)requestDispatcherStack.get();
+// if (list == null) {
+// list = new ArrayList();
+// requestDispatcherStack.set(list);
+// }
+//
+//
+// return null;
+// }
+
+ public void resetDispatcherStack() {
+
+ }
+
+ /**
+ * Return the URL to the resource that is mapped to a specified path.
+ * The path must begin with a "/" and is interpreted as relative to the
+ * current context root.
+ *
+ * @param path The path to the desired resource
+ *
+ * @exception MalformedURLException if the path is not given
+ * in the correct form
+ */
+ public URL getResource(String path)
+ throws MalformedURLException {
+
+ if (path == null || !path.startsWith("/")) {
+ throw new MalformedURLException("getResource() " + path);
+ }
+
+ path = UrlUtils.normalize(path);
+ if (path == null)
+ return (null);
+
+ String libPath = "/WEB-INF/lib/";
+ if ((path.startsWith(libPath)) && (path.endsWith(".jar"))) {
+ File jarFile = null;
+ jarFile = new File(basePath, path);
+ if (jarFile.exists()) {
+ return jarFile.toURL();
+ } else {
+ return null;
+ }
+ } else {
+ File resFile = new File(basePath + path);
+ if (resFile.exists()) {
+ return resFile.toURL();
+ }
+ }
+
+ return (null);
+
+ }
+
+ /**
+ * Return the requested resource as an <code>InputStream</code>. The
+ * path must be specified according to the rules described under
+ * <code>getResource</code>. If no such resource can be identified,
+ * return <code>null</code>.
+ *
+ * @param path The path to the desired resource.
+ */
+ public InputStream getResourceAsStream(String path) {
+
+ path = UrlUtils.normalize(path);
+ if (path == null)
+ return (null);
+
+ File resFile = new File(basePath + path);
+ if (!resFile.exists())
+ return null;
+
+ try {
+ return new FileInputStream(resFile);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+
+ }
+
+
+ /**
+ * Return a Set containing the resource paths of resources member of the
+ * specified collection. Each path will be a String starting with
+ * a "/" character. The returned set is immutable.
+ *
+ * @param path Collection path
+ */
+ public Set getResourcePaths(String path) {
+
+ // Validate the path argument
+ if (path == null) {
+ return null;
+ }
+ if (!path.startsWith("/")) {
+ throw new IllegalArgumentException("getResourcePaths() " + path);
+ }
+
+ path = UrlUtils.normalize(path);
+ if (path == null)
+ return (null);
+
+ File f = new File(basePath + path);
+ File[] files = f.listFiles();
+ if (files == null) return null;
+ if (!path.endsWith("/")) {
+ path = path + "/";
+ }
+
+ HashSet result = new HashSet();
+ for (int i=0; i < files.length; i++) {
+ if (files[i].isDirectory() ) {
+ result.add(path + files[i].getName() + "/");
+ } else {
+ result.add(path + files[i].getName());
+ }
+ }
+ return result;
+ }
+
+
+
+ /**
+ * Return the name and version of the servlet container.
+ */
+ public String getServerInfo() {
+ return "Apache Tomcat Lite";
+ }
+
+ /**
+ * @deprecated As of Java Servlet API 2.1, with no direct replacement.
+ */
+ public Servlet getServlet(String name) {
+ return (null);
+ }
+
+
+ /**
+ * Return the display name of this web application.
+ */
+ public String getServletContextName() {
+ return contextConfig.displayName;
+ }
+
+
+ /**
+ * @deprecated As of Java Servlet API 2.1, with no direct replacement.
+ */
+ public Enumeration getServletNames() {
+ return (new Enumerator(empty));
+ }
+
+
+ /**
+ * @deprecated As of Java Servlet API 2.1, with no direct replacement.
+ */
+ public Enumeration getServlets() {
+ return (new Enumerator(empty));
+ }
+
+
+ /**
+ * Writes the specified message to a servlet log file.
+ *
+ * @param message Message to be written
+ */
+ public void log(String message) {
+ this.getLogger().info(message);
+ }
+
+
+ /**
+ * Writes the specified exception and message to a servlet log file.
+ *
+ * @param exception Exception to be reported
+ * @param message Message to be written
+ *
+ * @deprecated As of Java Servlet API 2.1, use
+ * <code>log(String, Throwable)</code> instead
+ */
+ public void log(Exception exception, String message) {
+ this.getLogger().log(Level.INFO, message, exception);
+ }
+
+
+ /**
+ * Writes the specified message and exception to a servlet log file.
+ *
+ * @param message Message to be written
+ * @param throwable Exception to be reported
+ */
+ public void log(String message, Throwable throwable) {
+ this.getLogger().log(Level.INFO, message, throwable);
+ }
+
+ /**
+ * Remove the context attribute with the specified name, if any.
+ *
+ * @param name Name of the context attribute to be removed
+ */
+ public void removeAttribute(String name) {
+
+ Object value = null;
+ boolean found = false;
+
+ // Remove the specified attribute
+ // Check for read only attribute
+ found = attributes.containsKey(name);
+ if (found) {
+ value = attributes.get(name);
+ attributes.remove(name);
+ } else {
+ return;
+ }
+
+ // Notify interested application event listeners
+ List listeners = this.getListeners();
+ if (listeners.size() == 0)
+ return;
+ ServletContextAttributeEvent event = null;
+ for (int i = 0; i < listeners.size(); i++) {
+ if (!(listeners.get(i) instanceof ServletContextAttributeListener))
+ continue;
+ ServletContextAttributeListener listener =
+ (ServletContextAttributeListener) listeners.get(i);
+ try {
+ if (event == null) {
+ event = new ServletContextAttributeEvent(this.getServletContext(),
+ name, value);
+
+ }
+ listener.attributeRemoved(event);
+ } catch (Throwable t) {
+ // FIXME - should we do anything besides log these?
+ log("ServletContextAttributeListener", t);
+ }
+ }
+ }
+
+
+ /**
+ * Bind the specified value with the specified context attribute name,
+ * replacing any existing value for that name.
+ *
+ * @param name Attribute name to be bound
+ * @param value New attribute value to be bound
+ */
+ public void setAttribute(String name, Object value) {
+ // Name cannot be null
+ if (name == null)
+ throw new IllegalArgumentException
+ ("name == null");
+
+ // Null value is the same as removeAttribute()
+ if (value == null) {
+ removeAttribute(name);
+ return;
+ }
+
+ Object oldValue = null;
+ boolean replaced = false;
+
+ // Add or replace the specified attribute
+ synchronized (attributes) {
+ // Check for read only attribute
+ oldValue = attributes.get(name);
+ if (oldValue != null)
+ replaced = true;
+ attributes.put(name, value);
+ }
+
+ // Notify interested application event listeners
+ List listeners = this.getListeners();
+ if (listeners.size() == 0)
+ return;
+ ServletContextAttributeEvent event = null;
+ for (int i = 0; i < listeners.size(); i++) {
+ if (!(listeners.get(i) instanceof ServletContextAttributeListener))
+ continue;
+ ServletContextAttributeListener listener =
+ (ServletContextAttributeListener) listeners.get(i);
+ try {
+ if (event == null) {
+ if (replaced)
+ event =
+ new ServletContextAttributeEvent(this.getServletContext(),
+ name, oldValue);
+ else
+ event =
+ new ServletContextAttributeEvent(this.getServletContext(),
+ name, value);
+
+ }
+ if (replaced) {
+ listener.attributeReplaced(event);
+ } else {
+ listener.attributeAdded(event);
+ }
+ } catch (Throwable t) {
+ // FIXME - should we do anything besides log these?
+ log("ServletContextAttributeListener error", t);
+ }
+ }
+
+ }
+
+ /**
+ * Clear all application-created attributes.
+ */
+ void clearAttributes() {
+ // Create list of attributes to be removed
+ ArrayList list = new ArrayList();
+ synchronized (attributes) {
+ Iterator iter = attributes.keySet().iterator();
+ while (iter.hasNext()) {
+ list.add(iter.next());
+ }
+ }
+
+ // Remove application originated attributes
+ // (read only attributes will be left in place)
+ Iterator keys = list.iterator();
+ while (keys.hasNext()) {
+ String key = (String) keys.next();
+ removeAttribute(key);
+ }
+ }
+
+ public void initFilters() throws ServletException {
+ Iterator fI = getFilters().values().iterator();
+ while (fI.hasNext()) {
+ FilterConfigImpl fc = (FilterConfigImpl)fI.next();
+ try {
+ fc.getFilter(); // will triger init()
+ } catch (Throwable e) {
+ log.log(Level.WARNING, getContextPath() + " Filter.init() " +
+ fc.getFilterName(), e);
+ }
+
+ }
+ }
+
+ public void initServlets() throws ServletException {
+ Iterator fI = getServletConfigs().values().iterator();
+ Map/*<Integer, List<ServletConfigImpl>>*/ onStartup =
+ new TreeMap/*<Integer, List<ServletConfigImpl>>*/();
+ while (fI.hasNext()) {
+ ServletConfigImpl fc = (ServletConfigImpl)fI.next();
+ if (fc.getLoadOnStartup() > 0 ) {
+ Integer i = new Integer(fc.getLoadOnStartup());
+ List/*<ServletConfigImpl>*/ old = (List)onStartup.get(i);
+ if (old == null) {
+ old = new ArrayList/*<ServletConfigImpl>*/();
+ onStartup.put(i, old);
+ }
+ old.add(fc);
+ }
+ }
+ Iterator keys = onStartup.keySet().iterator();
+ while (keys.hasNext()) {
+ Integer key = (Integer)keys.next();
+ List/*<ServletConfigImpl>*/ servlets = (List)onStartup.get(key);
+ Iterator servletsI = servlets.iterator();
+ while (servletsI.hasNext()) {
+ ServletConfigImpl fc = (ServletConfigImpl) servletsI.next();
+ try {
+ fc.loadServlet();
+ } catch (Throwable e) {
+ log.log(Level.WARNING, "Error initializing " + fc.getServletName(), e);
+ }
+ }
+ }
+ }
+
+ public void initListeners() throws ServletException {
+ Iterator fI = contextConfig.listenerClass.iterator();
+ while (fI.hasNext()) {
+ String listenerClass = (String)fI.next();
+ try {
+ Object l =
+ getClassLoader().loadClass(listenerClass).newInstance();
+ lifecycleListeners.add((EventListener) l);
+ } catch (Throwable e) {
+ log.log(Level.WARNING, "Error initializing listener " + listenerClass, e);
+ }
+ }
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ public void addMapping(String path, String name) {
+ ServletConfigImpl wrapper = getServletConfig(name);
+ addMapping(path, wrapper);
+ }
+
+ public void addMapping(String path, ServletConfig wrapper) {
+ getMapper().addWrapper(getMapper().contextMapElement, path, wrapper);
+ }
+
+
+
+ public void setWelcomeFiles(String[] name) {
+ getMapper().contextMapElement.welcomeResources = name;
+ }
+
+ public String[] getWelcomeFiles() {
+ return getMapper().contextMapElement.welcomeResources;
+ }
+
+ public void setSessionTimeout(int to) {
+ getManager().setSessionTimeout(to);
+ }
+
+ /**
+ * Initialize the context from the parsed config.
+ *
+ * Note that WebAppData is serializable.
+ */
+ public void processWebAppData(ServletContextConfig d) throws ServletException {
+ this.contextConfig = d;
+
+ for (String k: d.mimeMapping.keySet()) {
+ addMimeType(k, d.mimeMapping.get(k));
+ }
+
+ String[] wFiles = (String[])d.welcomeFileList.toArray(new String[0]);
+ if (wFiles.length == 0) {
+ wFiles = new String[] {"index.html" };
+ }
+ if (basePath != null) {
+ getMapper().contextMapElement.resources = new File(getBasePath());
+ }
+ setWelcomeFiles(wFiles);
+
+ Iterator i2 = d.filters.values().iterator();
+ while (i2.hasNext()) {
+ FilterData fd = (FilterData)i2.next();
+ addFilter(fd.name, fd.className, fd.initParams);
+ }
+
+ Iterator i3 = d.servlets.values().iterator();
+ while (i3.hasNext()) {
+ ServletData sd = (ServletData) i3.next();
+ // jsp-file
+ if (sd.className == null) {
+ if (sd.jspFile == null) {
+ log.log(Level.WARNING, "Missing servlet class for " + sd.name);
+ continue;
+ }
+ }
+
+ ServletConfigImpl sw =
+ new ServletConfigImpl(this, sd.name, sd.className);
+ sw.setConfig(sd.initParams);
+ sw.setJspFile(sd.jspFile);
+ sw.setLoadOnStartup(sd.loadOnStartup);
+ //sw.setRunAs(sd.runAs);
+ sw.setSecurityRoleRef(sd.securityRoleRef);
+
+ addServletConfig(sw);
+ }
+
+ for (String k: d.servletMapping.keySet()) {
+ addMapping(k, d.servletMapping.get(k));
+ }
+
+ Iterator i5 = d.filterMappings.iterator();
+ while (i5.hasNext()) {
+ FilterMappingData k = (FilterMappingData) i5.next();
+ String[] disp = new String[k.dispatcher.size()];
+ if (k.urlPattern != null) {
+ addFilterMapping(k.urlPattern,
+ k.filterName,
+ (String[])k.dispatcher.toArray(disp));
+ }
+ if (k.servletName != null) {
+ addFilterServletMapping(k.servletName,
+ k.filterName,
+ (String[])k.dispatcher.toArray(disp));
+ }
+ }
+
+ for (String n: d.localeEncodingMapping.keySet()) {
+ getCharsetMapper().addCharsetMapping(n,
+ d.localeEncodingMapping.get(n));
+ }
+ }
+
+ public void addServlet(String servletName, String servletClass,
+ String jspFile, Map params) {
+ ServletConfigImpl sc = new ServletConfigImpl(this, servletName,
+ servletClass);
+ sc.setJspFile(jspFile);
+ sc.setConfig(params);
+ addServletConfig(sc);
+ }
+
+ @Override
+ public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
+ ServletConfigImpl sc = new ServletConfigImpl(this, servletName, null);
+ sc.setServlet(servlet);
+ addServletConfig(sc);
+ return sc.getDynamic();
+ }
+
+ public void addServletSec(String serlvetName, String runAs, Map roles) {
+ // TODO
+ }
+
+
+
+ public void addFilterMapping(String path, String filterName,
+ String[] dispatcher) {
+ getFilterMapper().addMapping(filterName,
+ path, null, dispatcher, true);
+
+ }
+
+ public void addFilterServletMapping(String servlet,
+ String filterName,
+ String[] dispatcher) {
+ getFilterMapper().addMapping(filterName,
+ null, servlet,
+ dispatcher, true);
+ }
+
+ /**
+ * Called from TomcatLite.init(), required before start.
+ *
+ * Will initialize defaults and load web.xml unless webAppData is
+ * already set and recent. No other processing is done except reading
+ * the config - you can add or alter it before start() is called.
+ *
+ * @throws ServletException
+ */
+ public void init() throws ServletException {
+ if (initDone) {
+ return;
+ }
+ initDone = true;
+ // Load global init params from the facade
+ initEngineDefaults();
+
+ initTempDir();
+
+
+ // Merge in web.xml - or other config source ( programmatic, etc )
+ ConfigLoader cfg = new WarDeploy();
+ contextConfig = cfg.loadConfig(getBasePath());
+
+ processWebAppData(contextConfig);
+
+ // if not defined yet:
+ addDefaultServlets();
+ }
+
+
+ protected void initTempDir() throws ServletException {
+ // We need a base path - at least for temp files, req. by spec
+ if (basePath == null) {
+ basePath = ("/".equals(contextPath)) ?
+ facade.getWork().getAbsolutePath() + "/ROOT" :
+ facade.getWork().getAbsolutePath() + contextPath;
+ }
+
+ File f = new File(basePath + "/WEB-INF/tmp");
+ f.mkdirs();
+ setAttribute("javax.servlet.context.tempdir", f);
+ }
+
+ /**
+ * Static file handler ( default )
+ * *.jsp support
+ *
+ */
+ protected void addDefaultServlets() throws ServletException {
+ if (servlets.get("default") == null) {
+ ServletConfigImpl fileS = new ServletConfigImpl(this,
+ "default", null);
+ addServletConfig(fileS);
+ addMapping("/", fileS);
+ }
+
+ // *.jsp support
+ if (servlets.get("jspwildcard") == null) {
+ ServletConfigImpl fileS = new ServletConfigImpl(this,
+ "jspwildcard", null);
+ fileS.initParams.put("mapper", JspLoader.class.getName());
+ addServletConfig(fileS);
+ addMapping("*.jsp", fileS);
+ }
+
+ ServletConfigImpl jspcS = new ServletConfigImpl(this,
+ "jspc", jspcServlet);
+ addServletConfig(jspcS);
+ }
+
+ protected void initEngineDefaults() throws ServletException {
+
+ // TODO: make this customizable, avoid loading it on startup
+ // Set the class name as default in the addon support
+ for (String sname: facade.ctxDefaultInitParam.keySet()) {
+ String path = facade.ctxDefaultInitParam.get(sname);
+ contextConfig.contextParam.put(sname, path);
+ }
+
+ for (String sname: facade.preloadServlets.keySet()) {
+ String sclass = facade.preloadServlets.get(sname);
+ ServletConfigImpl fileS = new ServletConfigImpl(this, sname, sclass);
+ addServletConfig(fileS);
+ }
+
+ for (String sname: facade.preloadMappings.keySet()) {
+ String path = facade.preloadMappings.get(sname);
+ ServletConfigImpl servletConfig = getServletConfig(sname);
+ addMapping(path, servletConfig);
+ }
+
+ // JSP support
+ setAttribute(InstanceManager.class.getName(),
+ new LiteInstanceManager(getObjectManager()));
+
+ }
+
+ private void addClasspathLib(ArrayList res, File directory) {
+
+ if (!directory.isDirectory() || !directory.exists()
+ || !directory.canRead()) {
+ return;
+ }
+
+ File[] jars = directory.listFiles(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".jar");
+ }
+ });
+
+ for (int j = 0; j < jars.length; j++) {
+ try {
+ URL url = jars[j].toURL();
+ res.add(url);
+ } catch (MalformedURLException e) {
+ }
+ }
+ }
+
+ private void addClasspathDir(ArrayList res, File classesDir) {
+
+ if (classesDir.isDirectory() && classesDir.exists() &&
+ classesDir.canRead()) {
+ try {
+ URL url = classesDir.toURL();
+ res.add(url);
+ } catch (MalformedURLException e) {
+ }
+ }
+ }
+ public String getClassPath() {
+ return classPath;
+ }
+
+ public void start() throws ServletException {
+ if (startDone) {
+ return;
+ }
+ String base = getBasePath();
+
+ ArrayList urls = new ArrayList();
+
+ addClasspathDir(urls, new File(base + "/WEB-INF/classes"));
+ addClasspathDir(urls, new File(base + "/WEB-INF/tmp"));
+ addClasspathLib(urls, new File(base + "/WEB-INF/lib"));
+
+ URL[] urlsA = new URL[urls.size()];
+ urls.toArray(urlsA);
+
+ URLClassLoader parentLoader =
+ getEngine().getContextParentLoader();
+
+ // create a class loader.
+ // TODO: reimplement special 'deploy' dirs
+
+ /*
+ Repository ctxRepo = new Repository();
+ ctxRepo.setParentClassLoader(parentLoader);
+ ctxRepo.addURL(urlsA);
+ repository = ctxRepo;
+ */
+
+ StringBuilder cp = new StringBuilder();
+
+ for (URL cpUrl : urlsA) {
+ cp.append(":").append(cpUrl.getFile());
+ }
+ classPath = cp.toString();
+
+ classLoader = new URLClassLoader(urlsA, parentLoader);
+
+ // JMX should know about us ( TODO: is it too early ? )
+ facade.notifyAdd(this);
+
+ initListeners();
+
+ List listeners = this.getListeners();
+ ServletContextEvent event = null;
+ for (int i = 0; i < listeners.size(); i++) {
+ if (!(listeners.get(i) instanceof ServletContextListener))
+ continue;
+ ServletContextListener listener =
+ (ServletContextListener) listeners.get(i);
+ if (event == null) {
+ event = new ServletContextEvent(this);
+ }
+ try {
+ // May add servlets/filters
+ listener.contextInitialized(event);
+ } catch (Throwable t) {
+ log.log(Level.WARNING, "Context.init() contextInitialized() error:", t);
+ }
+ }
+
+
+ initFilters();
+ initServlets();
+
+ startDone = true;
+ }
+
+ public UserSessionManager getManager() {
+ if (manager == null) {
+ manager = (UserSessionManager) getObjectManager().get(
+ UserSessionManager.class);
+ manager.setContext(this);
+ if (contextConfig.sessionTimeout > 0 ) {
+ manager.setSessionTimeout(contextConfig.sessionTimeout);
+ }
+ }
+ return manager;
+ }
+
+
+ // TODO: configurable ? init-params
+ public String getSessionCookieName() {
+ return "JSESSIONID";
+ }
+
+
+
+ public void destroy() throws ServletException {
+ // destroy filters
+ Iterator fI = filters.values().iterator();
+ while(fI.hasNext()) {
+ FilterConfigImpl fc = (FilterConfigImpl) fI.next();
+ try {
+ fc.getFilter().destroy();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ // destroy servlets
+ fI = servlets.values().iterator();
+ while(fI.hasNext()) {
+ ServletConfigImpl fc = (ServletConfigImpl) fI.next();
+ try {
+ fc.unload();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public TomcatLite getEngine() {
+ return facade;
+ }
+
+ public String findStatusPage(int status) {
+ if (contextConfig.errorPageCode.size() == 0) {
+ return null;
+ }
+ if (status == 200) {
+ return null;
+ }
+
+ return (String) contextConfig.errorPageCode.get(Integer.toString(status));
+ }
+
+ public void handleStatusPage(ServletRequestImpl req,
+ ServletResponseImpl res,
+ int status,
+ String statusPage) {
+ String message = RequestUtil.filter(res.getMessage());
+ if (message == null)
+ message = "";
+ setErrorAttributes(req, status, message);
+ dispatchError(req, res, statusPage);
+ }
+
+ protected void setErrorAttributes(ServletRequestImpl req,
+ int status,
+ String message) {
+ req.setAttribute("javax.servlet.error.status_code",
+ new Integer(status));
+ if (req.getWrapper() != null) {
+ req.setAttribute("javax.servlet.error.servlet_name",
+ req.getWrapper().servletName);
+ }
+ req.setAttribute("javax.servlet.error.request_uri",
+ req.getRequestURI());
+ req.setAttribute("javax.servlet.error.message",
+ message);
+
+ }
+
+ public void handleError(ServletRequestImpl req,
+ ServletResponseImpl res,
+ Throwable t) {
+ Throwable realError = t;
+ if (realError instanceof ServletException) {
+ realError = ((ServletException) realError).getRootCause();
+ if (realError == null) {
+ realError = t;
+ }
+ }
+ //if (realError instanceof ClientAbortException ) {
+
+ String errorPage = findErrorPage(t);
+ if ((errorPage == null) && (realError != t)) {
+ errorPage = findErrorPage(realError);
+ }
+
+ if (errorPage != null) {
+ setErrorAttributes(req, 500, t.getMessage());
+ req.setAttribute("javax.servlet.error.exception", realError);
+ req.setAttribute("javax.servlet.error.exception_type",
+ realError.getClass());
+ dispatchError(req, res, errorPage);
+ } else {
+ log("Unhandled error", t);
+ if (t instanceof ServletException &&
+ ((ServletException)t).getRootCause() != null) {
+ log("RootCause:", ((ServletException)t).getRootCause());
+ }
+ if (res.getStatus() < 500) {
+ res.setStatus(500);
+ }
+ }
+ }
+
+ protected void dispatchError(ServletRequestImpl req,
+ ServletResponseImpl res,
+ String errorPage) {
+ RequestDispatcher rd =
+ getRequestDispatcher(errorPage);
+ try {
+ // will clean up the buffer
+ rd.forward(req, res);
+ return; // handled
+ } catch (ServletException e) {
+ // TODO
+ } catch (IOException e) {
+ // TODO
+ }
+ }
+
+ protected String findErrorPage(Throwable exception) {
+ if (contextConfig.errorPageException.size() == 0) {
+ return null;
+ }
+ if (exception == null)
+ return (null);
+ Class clazz = exception.getClass();
+ String name = clazz.getName();
+ while (!Object.class.equals(clazz)) {
+ String page = (String)contextConfig.errorPageException.get(name);
+ if (page != null)
+ return (page);
+ clazz = clazz.getSuperclass();
+ if (clazz == null)
+ break;
+ name = clazz.getName();
+ }
+ return (null);
+
+ }
+
+
+ @Override
+ public EnumSet<SessionTrackingMode> getDefaultSessionTrackingModes() {
+ return null;
+ }
+
+
+ @Override
+ public EnumSet<SessionTrackingMode> getEffectiveSessionTrackingModes() {
+ return null;
+ }
+
+
+ @Override
+ public SessionCookieConfig getSessionCookieConfig() {
+ return null;
+ }
+
+
+ @Override
+ public void setSessionTrackingModes(EnumSet<SessionTrackingMode> sessionTrackingModes) {
+ }
+
+
+ public void addFilter(String filterName, String filterClass,
+ Map params) {
+ FilterConfigImpl fc = new FilterConfigImpl(this);
+ fc.setData(filterName, filterClass, params);
+ filters.put(filterName, fc);
+ }
+
+
+ @Override
+ public Dynamic addFilter(String filterName, String className) {
+ FilterConfigImpl fc = new FilterConfigImpl(this);
+ fc.setData(filterName, className, new HashMap());
+ filters.put(filterName, fc);
+ return fc.getDynamic();
+ }
+
+
+ @Override
+ public Dynamic addFilter(String filterName, Filter filter) {
+ FilterConfigImpl fc = new FilterConfigImpl(this);
+ fc.setData(filterName, null, new HashMap());
+ fc.setFilter(filter);
+ filters.put(filterName, fc);
+ return fc.getDynamic();
+ }
+
+
+ @Override
+ public Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {
+ FilterConfigImpl fc = new FilterConfigImpl(this);
+ fc.setData(filterName, null, new HashMap());
+ fc.setFilterClass(filterClass);
+ filters.put(filterName, fc);
+ return fc.getDynamic();
+ }
+
+
+ @Override
+ public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName,
+ String className) {
+ ServletConfigImpl sc = new ServletConfigImpl(this, servletName, className);
+ addServletConfig(sc);
+ return sc.getDynamic();
+ }
+
+
+ @Override
+ public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName,
+ Class<? extends Servlet> servletClass) {
+ ServletConfigImpl sc = new ServletConfigImpl(this, servletName, servletClass.getName());
+ sc.setServletClass(servletClass);
+ addServletConfig(sc);
+ return sc.getDynamic();
+ }
+
+ // That's tricky - this filter will have no name. We need to generate one
+ // because our code relies on names.
+ AtomicInteger autoName = new AtomicInteger();
+
+
+ @Override
+ public <T extends Filter> T createFilter(Class<T> c) throws ServletException {
+ FilterConfigImpl fc = new FilterConfigImpl(this);
+ String filterName = "_tomcat_auto_filter_" + autoName.incrementAndGet();
+ fc.setData(filterName, null, new HashMap());
+ fc.setFilterClass(c);
+ filters.put(filterName, fc);
+
+ try {
+ return (T) fc.createFilter();
+ } catch (ClassCastException e) {
+ throw new ServletException(e);
+ } catch (ClassNotFoundException e) {
+ throw new ServletException(e);
+ } catch (IllegalAccessException e) {
+ throw new ServletException(e);
+ } catch (InstantiationException e) {
+ throw new ServletException(e);
+ }
+ }
+
+
+ @Override
+ public <T extends Servlet> T createServlet(Class<T> c) throws ServletException {
+ String filterName = "_tomcat_auto_servlet_" + autoName.incrementAndGet();
+ ServletConfigImpl fc = new ServletConfigImpl(this, filterName, null);
+ fc.setServletClass(c);
+ servlets.put(filterName, fc);
+
+ try {
+ return (T) fc.newInstance();
+ } catch (ClassCastException e) {
+ throw new ServletException(e);
+ }
+ }
+
+
+ public FilterRegistration findFilterRegistration(String filterName) {
+ return filters.get(filterName);
+ }
+
+
+ public ServletRegistration findServletRegistration(String servletName) {
+ return servlets.get(servletName);
+ }
+
+
+ @Override
+ public boolean setInitParameter(String name, String value) {
+ HashMap<String, String> params = contextConfig.contextParam;
+ return setInitParameter(this, params, name, value);
+ }
+
+
+ static Set<String> setInitParameters(ServletContextImpl ctx,
+ Map<String, String> params,
+ Map<String, String> initParameters)
+ throws IllegalArgumentException, IllegalStateException {
+ if (ctx.startDone) {
+ throw new IllegalStateException();
+ }
+ Set<String> result = new HashSet<String>();
+ for (String name: initParameters.keySet()) {
+ String value = initParameters.get(name);
+ if (name == null || value == null) {
+ throw new IllegalArgumentException();
+ }
+ if (!setInitParameter(ctx, params, name, value)) {
+ result.add(name);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * true if the context initialization parameter with the given name and value was set successfully on this ServletContext, and false if it was not set because this ServletContext already contains a context initialization parameter with a matching name
+ * Throws:
+ * java.lang.IllegalStateException - if this ServletContext has already been initialized
+ */
+ static boolean setInitParameter(ServletContextImpl ctx, Map<String, String> params,
+ String name, String value) {
+ if (name == null || value == null) {
+ throw new IllegalArgumentException();
+ }
+ if (ctx.startDone) {
+ throw new IllegalStateException();
+ }
+ String oldValue = params.get(name);
+ if (oldValue != null) {
+ return false;
+ } else {
+ params.put(name, value);
+ return true;
+ }
+ }
+
+ public JspConfigDescriptor getJspConfigDescriptor() {
+ // fix me - just here to compile
+ return null;
+ }
+
+
+
+ public void declareRoles(String... roleNames) {
+ // implement me
+ }
+
+ public <T extends EventListener> T createListener(Class<T> c) throws ServletException {
+ // implement me
+ return null;
+ }
+
+ public Collection<String> getMappings() {
+ // implement me
+ return null;
+ }
+
+ public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
+ // implement me
+ return null;
+ }
+
+ public FilterRegistration getFilterRegistration(String filterName) {
+ // implement me
+ return null;
+ }
+
+ public Map<String, ? extends ServletRegistration> getServletRegistrations() {
+ // implement me
+ return null;
+ }
+
+ public ServletRegistration getServletRegistration(String servletName) {
+ // implement me
+ return null;
+ }
+
+ public int getEffectiveMinorVersion() {
+ // implement me
+ return -1;
+ }
+
+ public int getEffectiveMajorVersion() {
+ // implement me
+ return -1;
+ }
+
+ private final class LiteInstanceManager implements InstanceManager {
+ private ObjectManager om;
+
+ public LiteInstanceManager(ObjectManager objectManager) {
+ this.om = objectManager;
+ }
+
+ @Override
+ public void destroyInstance(Object o)
+ throws IllegalAccessException,
+ InvocationTargetException {
+ }
+
+ @Override
+ public Object newInstance(String className)
+ throws IllegalAccessException,
+ InvocationTargetException, NamingException,
+ InstantiationException,
+ ClassNotFoundException {
+ return om.get(className);
+ }
+
+ @Override
+ public Object newInstance(String fqcn,
+ ClassLoader classLoader)
+ throws IllegalAccessException,
+ InvocationTargetException, NamingException,
+ InstantiationException,
+ ClassNotFoundException {
+ return om.get(fqcn);
+ }
+
+ @Override
+ public void newInstance(Object o)
+ throws IllegalAccessException,
+ InvocationTargetException, NamingException {
+ om.bind(o.getClass().getName(), o);
+ }
+ }
+
+}
+
--- /dev/null
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.coyote.servlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.servlet.ServletInputStream;
+
+
+/**
+ * Wrapper around MessageReader
+ *
+ * @author Remy Maucherat
+ * @author Jean-Francois Arcand
+ * @author Costin Manolache
+ */
+public class ServletInputStreamImpl extends ServletInputStream {
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ protected InputStream ib;
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ public ServletInputStreamImpl(InputStream ib) {
+ this.ib = ib;
+ }
+
+ // --------------------------------------------- ServletInputStream Methods
+
+ public long skip(long n)
+ throws IOException {
+ return ib.skip(n);
+ }
+
+ public void mark(int readAheadLimit)
+ {
+ //try {
+ ib.mark(readAheadLimit);
+// } catch (IOException e) {
+// e.printStackTrace();
+// }
+ }
+
+
+ public void reset()
+ throws IOException {
+ ib.reset();
+ }
+
+
+
+ public int read()
+ throws IOException {
+ return ib.read();
+ }
+
+ public int available() throws IOException {
+ return ib.available();
+ }
+
+ public int read(final byte[] b) throws IOException {
+ return ib.read(b, 0, b.length);
+ }
+
+
+ public int read(final byte[] b, final int off, final int len)
+ throws IOException {
+
+ return ib.read(b, off, len);
+ }
+
+
+ public int readLine(byte[] b, int off, int len) throws IOException {
+ return super.readLine(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 {
+ ib.close();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.coyote.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.ServletOutputStream;
+
+
+/**
+ * Coyote implementation of the servlet output stream.
+ *
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ */
+public class ServletOutputStreamImpl
+ extends ServletOutputStream {
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ protected BodyWriter ob;
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ public ServletOutputStreamImpl(BodyWriter ob) {
+ this.ob = ob;
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Prevent cloning the facade.
+ */
+ protected Object clone()
+ throws CloneNotSupportedException {
+ throw new CloneNotSupportedException();
+ }
+
+
+ // -------------------------------------------------------- Package Methods
+
+
+ /**
+ * Clear facade.
+ */
+ void clear() {
+ ob = null;
+ }
+
+
+ // --------------------------------------------------- OutputStream Methods
+
+
+ public void write(int i)
+ throws IOException {
+ ob.writeByte(i);
+ }
+
+
+ public void write(byte[] b)
+ throws IOException {
+ write(b, 0, b.length);
+ }
+
+
+ public void write(byte[] b, int off, int len)
+ throws IOException {
+ ob.write(b, off, len);
+ }
+
+
+ /**
+ * Will send the buffer to the client.
+ */
+ public void flush()
+ throws IOException {
+ ob.flush();
+ }
+
+
+ public void close()
+ throws IOException {
+ ob.close();
+ }
+
+
+ // -------------------------------------------- ServletOutputStream Methods
+
+
+ public void print(String s)
+ throws IOException {
+ ob.write(s);
+ }
+
+
+}
+
--- /dev/null
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.coyote.servlet;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+
+
+
+/**
+ * Coyote implementation of the buffred reader.
+ *
+ * @author Remy Maucherat
+ */
+public class ServletReaderImpl
+ extends BufferedReader {
+
+
+ // -------------------------------------------------------------- Constants
+
+
+ private static final char[] LINE_SEP = { '\r', '\n' };
+ private static final int MAX_LINE_LENGTH = 4096;
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ protected Reader ib;
+
+
+ protected char[] lineBuffer = null;
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ public ServletReaderImpl(Reader ib) {
+ super(ib, 1);
+ this.ib = ib;
+ }
+
+ public void close()
+ throws IOException {
+ ib.close();
+ }
+
+
+ public int read()
+ throws IOException {
+ return ib.read();
+ }
+
+
+ public int read(char[] cbuf)
+ throws IOException {
+ return ib.read(cbuf, 0, cbuf.length);
+ }
+
+
+ public int read(char[] cbuf, int off, int len)
+ throws IOException {
+ return ib.read(cbuf, off, len);
+ }
+
+
+ public long skip(long n)
+ throws IOException {
+ return ib.skip(n);
+ }
+
+
+ public boolean ready()
+ throws IOException {
+ return ib.ready();
+ }
+
+
+ public boolean markSupported() {
+ return true;
+ }
+
+
+ public void mark(int readAheadLimit)
+ throws IOException {
+ ib.mark(readAheadLimit);
+ }
+
+
+ public void reset()
+ throws IOException {
+ ib.reset();
+ }
+
+
+ // TODO: move the readLine functionality to base coyote IO
+ public String readLine()
+ throws IOException {
+
+ if (lineBuffer == null) {
+ lineBuffer = new char[MAX_LINE_LENGTH];
+ }
+
+ String result = null;
+
+ int pos = 0;
+ int end = -1;
+ int skip = -1;
+ StringBuilder aggregator = null;
+ while (end < 0) {
+ mark(MAX_LINE_LENGTH);
+ while ((pos < MAX_LINE_LENGTH) && (end < 0)) {
+ int nRead = read(lineBuffer, pos, MAX_LINE_LENGTH - pos);
+ if (nRead < 0) {
+ if (pos == 0) {
+ return null;
+ }
+ end = pos;
+ skip = pos;
+ }
+ for (int i = pos; (i < (pos + nRead)) && (end < 0); i++) {
+ if (lineBuffer[i] == LINE_SEP[0]) {
+ end = i;
+ skip = i + 1;
+ char nextchar;
+ if (i == (pos + nRead - 1)) {
+ nextchar = (char) read();
+ } else {
+ nextchar = lineBuffer[i+1];
+ }
+ if (nextchar == LINE_SEP[1]) {
+ skip++;
+ }
+ } else if (lineBuffer[i] == LINE_SEP[1]) {
+ end = i;
+ skip = i + 1;
+ }
+ }
+ if (nRead > 0) {
+ pos += nRead;
+ }
+ }
+ if (end < 0) {
+ if (aggregator == null) {
+ aggregator = new StringBuilder();
+ }
+ aggregator.append(lineBuffer);
+ pos = 0;
+ } else {
+ reset();
+ skip(skip);
+ }
+ }
+
+ if (aggregator == null) {
+ result = new String(lineBuffer, 0, end);
+ } else {
+ aggregator.append(lineBuffer, 0, end);
+ result = aggregator.toString();
+ }
+
+ return result;
+
+ }
+}
--- /dev/null
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.coyote.servlet;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.TreeMap;
+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;
+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.tomcat.servlets.session.UserSessionManager;
+import org.apache.tomcat.servlets.util.Enumerator;
+import org.apache.tomcat.servlets.util.LocaleParser;
+import org.apache.tomcat.servlets.util.RequestUtil;
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.buf.ByteChunk;
+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
+ */
+public class ServletRequestImpl implements HttpServletRequest {
+
+ /**
+ * The request attribute under which we store the array of X509Certificate
+ * objects representing the certificate chain presented by our client,
+ * if any.
+ */
+ public static final String CERTIFICATES_ATTR =
+ "javax.servlet.request.X509Certificate";
+
+ /**
+ * The request attribute under which we store the name of the cipher suite
+ * being used on an SSL connection (as an object of type
+ * java.lang.String).
+ */
+ public static final String CIPHER_SUITE_ATTR =
+ "javax.servlet.request.cipher_suite";
+
+ /**
+ * Request dispatcher state.
+ */
+ public static final String DISPATCHER_TYPE_ATTR =
+ "org.apache.catalina.core.DISPATCHER_TYPE";
+
+ /**
+ * Request dispatcher path.
+ */
+ public static final String DISPATCHER_REQUEST_PATH_ATTR =
+ "org.apache.catalina.core.DISPATCHER_REQUEST_PATH";
+
+ /**
+ * The servlet context attribute under which we store the class path
+ * for our application class loader (as an object of type String),
+ * delimited with the appropriate path delimiter for this platform.
+ */
+ public static final String CLASS_PATH_ATTR =
+ "org.apache.catalina.jsp_classpath";
+
+
+ /**
+ * The request attribute under which we forward a Java exception
+ * (as an object of type Throwable) to an error page.
+ */
+ public static final String EXCEPTION_ATTR =
+ "javax.servlet.error.exception";
+
+
+ /**
+ * The request attribute under which we forward the request URI
+ * (as an object of type String) of the page on which an error occurred.
+ */
+ public static final String EXCEPTION_PAGE_ATTR =
+ "javax.servlet.error.request_uri";
+
+
+ /**
+ * The request attribute under which we forward a Java exception type
+ * (as an object of type Class) to an error page.
+ */
+ public static final String EXCEPTION_TYPE_ATTR =
+ "javax.servlet.error.exception_type";
+
+
+ /**
+ * The request attribute under which we forward an HTTP status message
+ * (as an object of type STring) to an error page.
+ */
+ public static final String ERROR_MESSAGE_ATTR =
+ "javax.servlet.error.message";
+
+
+ /**
+ * The request attribute under which we expose the value of the
+ * <code><jsp-file></code> value associated with this servlet,
+ * if any.
+ */
+ public static final String JSP_FILE_ATTR =
+ "org.apache.catalina.jsp_file";
+
+
+ /**
+ * The request attribute under which we store the key size being used for
+ * this SSL connection (as an object of type java.lang.Integer).
+ */
+ public static final String KEY_SIZE_ATTR =
+ "javax.servlet.request.key_size";
+
+ /**
+ * The request attribute under which we store the session id being used
+ * for this SSL connection (as an object of type java.lang.String).
+ */
+ public static final String SSL_SESSION_ID_ATTR =
+ "javax.servlet.request.ssl_session";
+
+ /**
+ * The request attribute under which we forward a servlet name to
+ * an error page.
+ */
+ public static final String SERVLET_NAME_ATTR =
+ "javax.servlet.error.servlet_name";
+
+
+ /**
+ * The name of the cookie used to pass the session identifier back
+ * and forth with the client.
+ */
+ public static final String SESSION_COOKIE_NAME = "JSESSIONID";
+
+
+ /**
+ * The name of the path parameter used to pass the session identifier
+ * back and forth with the client.
+ */
+ public static final String SESSION_PARAMETER_NAME = "jsessionid";
+
+
+ /**
+ * The request attribute under which we forward an HTTP status code
+ * (as an object of type Integer) to an error page.
+ */
+ public static final String STATUS_CODE_ATTR =
+ "javax.servlet.error.status_code";
+
+
+ /**
+ * The subject under which the AccessControlContext is running.
+ */
+ public static final String SUBJECT_ATTR =
+ "javax.security.auth.subject";
+
+
+ /**
+ * The servlet context attribute under which we store a temporary
+ * working directory (as an object of type File) for use by servlets
+ * within this web application.
+ */
+ public static final String WORK_DIR_ATTR =
+ "javax.servlet.context.tempdir";
+
+ protected static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
+
+
+ /**
+ * The default Locale if none are specified.
+ */
+ protected static Locale defaultLocale = Locale.getDefault();
+
+ // ApplicationFilterFactory. What's the use ???
+ private static Integer REQUEST_INTEGER = new Integer(8);
+
+ /**
+ * The match string for identifying a session ID parameter.
+ */
+ private static final String match = ";" + SESSION_PARAMETER_NAME + "=";
+
+ /**
+ * The set of cookies associated with this Request.
+ */
+ protected Cookie[] cookies = null;
+
+
+ /**
+ * The set of SimpleDateFormat formats to use in getDateHeader().
+ *
+ * Notice that because SimpleDateFormat is not thread-safe, we can't
+ * declare formats[] as a static variable.
+ */
+ protected SimpleDateFormat formats[] = null;
+
+
+ /**
+ * The attributes associated with this Request, keyed by attribute name.
+ */
+ protected HashMap attributes = new HashMap();
+
+
+ /**
+ * List of read only attributes for this Request.
+ */
+ //private HashMap readOnlyAttributes = new HashMap();
+
+
+ /**
+ * The preferred Locales assocaited with this Request.
+ */
+ protected ArrayList locales = new ArrayList();
+
+
+ /**
+ * Authentication type.
+ */
+ protected String authType = null;
+
+ /**
+ * User principal.
+ */
+ protected Principal userPrincipal = null;
+
+
+ /**
+ * The Subject associated with the current AccessControllerContext
+ */
+ protected transient Subject subject = null;
+
+
+ /**
+ * The current dispatcher type.
+ */
+ protected Object dispatcherType = null;
+
+
+ /**
+ * The associated input buffer.
+ */
+ protected BodyReader inputBuffer;
+
+ Connector connector;
+
+ /**
+ * ServletInputStream.
+ */
+ protected ServletInputStreamImpl inputStream;
+
+
+ /**
+ * Reader.
+ */
+ protected BufferedReader reader;
+
+
+ /**
+ * Using stream flag.
+ */
+ protected boolean usingInputStream = false;
+
+
+ /**
+ * Using writer flag.
+ */
+ protected boolean usingReader = false;
+
+
+ /**
+ * Session parsed flag.
+ */
+ protected boolean sessionParsed = false;
+
+
+ /**
+ * Request parameters parsed flag.
+ */
+ protected boolean parametersParsed = false;
+
+
+ /**
+ * Cookies parsed flag.
+ */
+ protected boolean cookiesParsed = false;
+
+
+ /**
+ * Secure flag.
+ */
+ protected boolean secure = false;
+
+
+ /**
+ * Hash map used in the getParametersMap method.
+ */
+ protected ParameterMap parameterMap = new ParameterMap();
+
+
+ /**
+ * The currently active session for this request.
+ */
+ protected HttpSession session = null;
+
+
+ /**
+ * The current request dispatcher path.
+ */
+ protected Object requestDispatcherPath = null;
+
+
+ /**
+ * Was the requested session ID received in a cookie?
+ */
+ protected boolean requestedSessionCookie = false;
+
+
+ /**
+ * The requested session ID (if any) for this request.
+ */
+ protected String requestedSessionId = null;
+
+
+ /**
+ * Was the requested session ID received in a URL?
+ */
+ protected boolean requestedSessionURL = false;
+
+
+ /**
+ * Parse locales.
+ */
+ protected boolean localesParsed = false;
+
+
+ /**
+ * Associated context.
+ */
+ protected ServletContextImpl context = null;
+
+
+
+ // --------------------------------------------------------- Public Methods
+
+ /**
+ * Filter chain associated with the request.
+ */
+ protected FilterChainImpl filterChain = new FilterChainImpl();
+
+ /**
+ * Mapping data.
+ */
+ protected MappingData mappingData = new MappingData();
+
+
+ // -------------------------------------------------------- Request Methods
+
+ /**
+ * The response with which this request is associated.
+ */
+ protected ServletResponseImpl response = new ServletResponseImpl();
+
+ /**
+ * URI byte to char converter (not recycled).
+ */
+ // protected B2CConverter URIConverter = null;
+
+ /**
+ * Associated wrapper.
+ */
+ protected ServletConfigImpl wrapper = null;
+
+ /**
+ * Post data buffer.
+ */
+ public final static int CACHED_POST_LEN = 8192;
+
+ public byte[] postData = null;
+
+
+ private HttpRequest httpRequest;
+
+ /** New IO/buffer model
+ */
+ //protected Http11Connection con;
+
+
+ public ServletRequestImpl() {
+ response.setRequest(this);
+ }
+
+
+// /**
+// * Return the Host within which this Request is being processed.
+// */
+// public Host getHost() {
+// if (getContext() == null)
+// return null;
+// return (Host) getContext().getParent();
+// //return ((Host) mappingData.host);
+// }
+//
+//
+// /**
+// * Set the Host within which this Request is being processed. This
+// * must be called as soon as the appropriate Host is identified, and
+// * before the Request is passed to a context.
+// *
+// * @param host The newly associated Host
+// */
+// public void setHost(Host host) {
+// mappingData.host = host;
+// }
+
+ /**
+ * Add a Cookie to the set of Cookies associated with this Request.
+ *
+ * @param cookie The new cookie
+ */
+ public void addCookie(Cookie cookie) {
+
+ if (!cookiesParsed)
+ parseCookies();
+
+ int size = 0;
+ if (cookies != null) {
+ size = cookies.length;
+ }
+
+ Cookie[] newCookies = new Cookie[size + 1];
+ for (int i = 0; i < size; i++) {
+ newCookies[i] = cookies[i];
+ }
+ newCookies[size] = cookie;
+
+ cookies = newCookies;
+
+ }
+
+ /**
+ * Add a Header to the set of Headers associated with this Request.
+ *
+ * @param name The new header name
+ * @param value The new header value
+ */
+ public void addHeader(String name, String value) {
+ // 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
+ * first added Locale will be the first one returned by getLocales().
+ *
+ * @param locale The new preferred Locale
+ */
+ public void addLocale(Locale locale) {
+ locales.add(locale);
+ }
+
+
+ /**
+ * Add a parameter name and corresponding set of values to this Request.
+ * (This is used when restoring the original request on a form based
+ * login).
+ *
+ * @param name Name of this request parameter
+ * @param values Corresponding values for this request parameter
+ */
+ public void addParameter(String name, String values[]) {
+ httpRequest.getParameters().addParameterValues(name, values);
+ }
+
+ /**
+ * Clear the collection of Cookies associated with this Request.
+ */
+ public void clearCookies() {
+ cookiesParsed = true;
+ cookies = null;
+ }
+
+ /**
+ * Clear the collection of Headers associated with this Request.
+ */
+ public void clearHeaders() {
+ // Not used
+ }
+
+ /**
+ * Clear the collection of Locales associated with this Request.
+ */
+ public void clearLocales() {
+ locales.clear();
+ }
+
+ /**
+ * Clear the collection of parameters associated with this Request.
+ */
+ public void clearParameters() {
+ // Not used
+ }
+
+
+ /**
+ * Create and return a ServletInputStream to read the content
+ * associated with this Request.
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ public ServletInputStream createInputStream()
+ throws IOException {
+ return inputStream;
+ }
+
+ /**
+ * Perform whatever actions are required to flush and close the input
+ * stream or reader, in a single operation.
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ public void finishRequest() throws IOException {
+ // The reader and input stream don't need to be closed
+ }
+
+
+ /**
+ * Return the specified request attribute if it exists; otherwise, return
+ * <code>null</code>.
+ *
+ * @param name Name of the request attribute to return
+ */
+ public Object getAttribute(String name) {
+
+ if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
+ return (dispatcherType == null)
+ ? REQUEST_INTEGER
+ : dispatcherType;
+ } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
+ return (requestDispatcherPath == null)
+ ? getRequestPathMB().toString()
+ : requestDispatcherPath.toString();
+ }
+
+ Object attr=attributes.get(name);
+
+ if(attr!=null)
+ return(attr);
+
+// attr = reqB.getAttribute(name);
+// if(attr != null)
+// return attr;
+// if( isSSLAttribute(name) ) {
+// reqB.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE,
+// reqB);
+// attr = reqB.getAttribute(ServletRequestImpl.CERTIFICATES_ATTR);
+// if( attr != null) {
+// attributes.put(ServletRequestImpl.CERTIFICATES_ATTR, attr);
+// }
+// attr = reqB.getAttribute(ServletRequestImpl.CIPHER_SUITE_ATTR);
+// if(attr != null) {
+// attributes.put(ServletRequestImpl.CIPHER_SUITE_ATTR, attr);
+// }
+// attr = reqB.getAttribute(ServletRequestImpl.KEY_SIZE_ATTR);
+// if(attr != null) {
+// attributes.put(ServletRequestImpl.KEY_SIZE_ATTR, attr);
+// }
+// attr = reqB.getAttribute(ServletRequestImpl.SSL_SESSION_ID_ATTR);
+// if(attr != null) {
+// attributes.put(ServletRequestImpl.SSL_SESSION_ID_ATTR, attr);
+// }
+// attr = attributes.get(name);
+// }
+ return attr;
+ }
+
+ /**
+ * Return the names of all request attributes for this Request, or an
+ * empty <code>Enumeration</code> if there are none.
+ */
+ public Enumeration getAttributeNames() {
+ if (isSecure()) {
+ getAttribute(ServletRequestImpl.CERTIFICATES_ATTR);
+ }
+ return new Enumerator(attributes.keySet(), true);
+ }
+
+
+ /**
+ * Return the authentication type used for this Request.
+ */
+ public String getAuthType() {
+ return (authType);
+ }
+
+
+ // ------------------------------------------------- Request Public Methods
+
+
+ /**
+ * Return the character encoding for this Request.
+ */
+ public String getCharacterEncoding() {
+ return (httpRequest.getCharacterEncoding());
+ }
+
+
+ /**
+ * Return the content length for this Request.
+ */
+ public int getContentLength() {
+ return (httpRequest.getContentLength());
+ }
+
+
+// /**
+// * Return the object bound with the specified name to the internal notes
+// * for this request, or <code>null</code> if no such binding exists.
+// *
+// * @param name Name of the note to be returned
+// */
+// public Object getNote(String name) {
+// return (notes.get(name));
+// }
+//
+//
+// /**
+// * Return an Iterator containing the String names of all notes bindings
+// * that exist for this request.
+// */
+// public Iterator getNoteNames() {
+// return (notes.keySet().iterator());
+// }
+//
+//
+// /**
+// * Remove any object bound to the specified name in the internal notes
+// * for this request.
+// *
+// * @param name Name of the note to be removed
+// */
+// public void removeNote(String name) {
+// notes.remove(name);
+// }
+//
+//
+// /**
+// * Bind an object to a specified name in the internal notes associated
+// * with this request, replacing any existing binding for this name.
+// *
+// * @param name Name to which the object should be bound
+// * @param value Object to be bound to the specified name
+// */
+// public void setNote(String name, Object value) {
+// notes.put(name, value);
+// }
+//
+
+ /**
+ * Return the content type for this Request.
+ */
+ public String getContentType() {
+ return (httpRequest.getContentType());
+ }
+
+
+ /**
+ * Return the Context within which this Request is being processed.
+ */
+ public ServletContextImpl getContext() {
+ return (this.context);
+ }
+
+
+ /**
+ * Return the portion of the request URI used to select the Context
+ * of the Request.
+ */
+ public String getContextPath() {
+ return (mappingData.contextPath.toString());
+ }
+
+
+ /**
+ * Get the context path.
+ *
+ * @return the context path
+ */
+ public MessageBytes getContextPathMB() {
+ return (mappingData.contextPath);
+ }
+
+
+ /**
+ * Return the set of Cookies received with this Request.
+ */
+ public Cookie[] getCookies() {
+
+ if (!cookiesParsed)
+ parseCookies();
+
+ return cookies;
+
+ }
+
+
+ /**
+ * Return the value of the specified date header, if any; otherwise
+ * return -1.
+ *
+ * @param name Name of the requested date header
+ *
+ * @exception IllegalArgumentException if the specified header value
+ * cannot be converted to a date
+ */
+ public long getDateHeader(String name) {
+
+ String value = getHeader(name);
+ if (value == null)
+ return (-1L);
+ if (formats == null) {
+ formats = new SimpleDateFormat[] {
+ new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
+ new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
+ new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
+ };
+ formats[0].setTimeZone(GMT_ZONE);
+ formats[1].setTimeZone(GMT_ZONE);
+ formats[2].setTimeZone(GMT_ZONE);
+ }
+
+ // Attempt to convert the date header in a variety of formats
+ long result = FastHttpDateFormat.parseDate(value, formats);
+ if (result != (-1L)) {
+ return result;
+ }
+ throw new IllegalArgumentException(value);
+
+ }
+
+
+ /**
+ * Get the decoded request URI.
+ *
+ * @return the URL decoded request URI
+ */
+ public String getDecodedRequestURI() {
+ return (httpRequest.decodedURI().toString());
+ }
+
+
+ /**
+ * Get the decoded request URI.
+ *
+ * @return the URL decoded request URI
+ */
+ public MessageBytes getDecodedRequestURIMB() {
+ return (httpRequest.decodedURI());
+ }
+
+
+ /**
+ * Get filter chain associated with the request.
+ */
+ public FilterChainImpl getFilterChain() {
+ return (this.filterChain);
+ }
+
+
+ // ------------------------------------------------- ServletRequest Methods
+
+ /**
+ * Return the first value of the specified header, if any; otherwise,
+ * return <code>null</code>
+ *
+ * @param name Name of the requested header
+ */
+ public String getHeader(String name) {
+ return httpRequest.getHeader(name);
+ }
+
+ /**
+ * Return the names of all headers received with this request.
+ */
+ public Enumeration getHeaderNames() {
+ return httpRequest.getMimeHeaders().names();
+ }
+
+
+ /**
+ * Return all of the values of the specified header, if any; otherwise,
+ * return an empty enumeration.
+ *
+ * @param name Name of the requested header
+ */
+ public Enumeration getHeaders(String name) {
+ return httpRequest.getMimeHeaders().values(name);
+ }
+
+ /**
+ * Return the servlet input stream for this Request. The default
+ * implementation returns a servlet input stream created by
+ * <code>createInputStream()</code>.
+ *
+ * @exception IllegalStateException if <code>getReader()</code> has
+ * already been called for this request
+ * @exception IOException if an input/output error occurs
+ */
+ public ServletInputStream getInputStream() throws IOException {
+
+ if (usingReader)
+ throw new IllegalStateException
+ ("usingReader");
+
+ usingInputStream = true;
+ return inputStream;
+
+ }
+
+
+ /**
+ * Return the value of the specified header as an integer, or -1 if there
+ * is no such header for this request.
+ *
+ * @param name Name of the requested header
+ *
+ * @exception IllegalArgumentException if the specified header value
+ * cannot be converted to an integer
+ */
+ public int getIntHeader(String name) {
+
+ String value = getHeader(name);
+ if (value == null) {
+ return (-1);
+ } else {
+ return (Integer.parseInt(value));
+ }
+
+ }
+
+
+ /**
+ * Returns the Internet Protocol (IP) address of the interface on
+ * which the request was received.
+ */
+ public String getLocalAddr(){
+ return httpRequest.localAddr().toString();
+ }
+
+
+ /**
+ * Return the preferred Locale that the client will accept content in,
+ * based on the value for the first <code>Accept-Language</code> header
+ * that was encountered. If the request did not specify a preferred
+ * language, the server's default Locale is returned.
+ */
+ public Locale getLocale() {
+
+ if (!localesParsed)
+ parseLocales();
+
+ if (locales.size() > 0) {
+ return ((Locale) locales.get(0));
+ } else {
+ return (defaultLocale);
+ }
+
+ }
+
+
+ /**
+ * Return the set of preferred Locales that the client will accept
+ * content in, based on the values for any <code>Accept-Language</code>
+ * headers that were encountered. If the request did not specify a
+ * preferred language, the server's default Locale is returned.
+ */
+ public Enumeration getLocales() {
+
+ if (!localesParsed)
+ parseLocales();
+
+ if (locales.size() > 0)
+ return (new Enumerator(locales));
+ ArrayList results = new ArrayList();
+ results.add(defaultLocale);
+ return (new Enumerator(results));
+
+ }
+
+
+ /**
+ * Returns the host name of the Internet Protocol (IP) interface on
+ * which the request was received.
+ */
+ public String getLocalName(){
+ return httpRequest.localName().toString();
+ }
+
+
+ /**
+ * Returns the Internet Protocol (IP) port number of the interface
+ * on which the request was received.
+ */
+ public int getLocalPort(){
+ return httpRequest.getLocalPort();
+ }
+
+
+ /**
+ * Return mapping data.
+ */
+ public MappingData getMappingData() {
+ return (mappingData);
+ }
+
+
+
+ /**
+ * Return the HTTP request method used in this Request.
+ */
+ public String getMethod() {
+ return httpRequest.method().toString();
+ }
+
+
+ /**
+ * Return the value of the specified request parameter, if any; otherwise,
+ * return <code>null</code>. If there is more than one value defined,
+ * return only the first one.
+ *
+ * @param name Name of the desired request parameter
+ */
+ public String getParameter(String name) {
+
+ if (!parametersParsed)
+ parseParameters();
+
+ return httpRequest.getParameters().getParameter(name);
+
+ }
+
+
+ /**
+ * Returns a <code>Map</code> of the parameters of this request.
+ * Request parameters are extra information sent with the request.
+ * For HTTP servlets, parameters are contained in the query string
+ * or posted form data.
+ *
+ * @return A <code>Map</code> containing parameter names as keys
+ * and parameter values as map values.
+ */
+ public Map getParameterMap() {
+
+ if (parameterMap.isLocked())
+ return parameterMap;
+
+ Enumeration enumeration = getParameterNames();
+ while (enumeration.hasMoreElements()) {
+ String name = enumeration.nextElement().toString();
+ String[] values = getParameterValues(name);
+ parameterMap.put(name, values);
+ }
+
+ parameterMap.setLocked(true);
+
+ return parameterMap;
+
+ }
+
+
+ /**
+ * Return the names of all defined request parameters for this request.
+ */
+ public Enumeration getParameterNames() {
+
+ if (!parametersParsed)
+ parseParameters();
+
+ return httpRequest.getParameters().getParameterNames();
+
+ }
+
+
+ /**
+ * Return the defined values for the specified request parameter, if any;
+ * otherwise, return <code>null</code>.
+ *
+ * @param name Name of the desired request parameter
+ */
+ public String[] getParameterValues(String name) {
+
+ if (!parametersParsed)
+ parseParameters();
+
+ return httpRequest.getParameters().getParameterValues(name);
+
+ }
+
+
+ /**
+ * Return the path information associated with this Request.
+ */
+ public String getPathInfo() {
+ return (mappingData.pathInfo.toString());
+ }
+
+
+ /**
+ * Get the path info.
+ *
+ * @return the path info
+ */
+ public MessageBytes getPathInfoMB() {
+ return (mappingData.pathInfo);
+ }
+
+
+ /**
+ * Return the extra path information for this request, translated
+ * to a real path.
+ */
+ public String getPathTranslated() {
+
+ if (context == null)
+ return (null);
+
+ if (getPathInfo() == null) {
+ return (null);
+ } else {
+ return (context.getServletContext().getRealPath(getPathInfo()));
+ }
+
+ }
+
+ /**
+ * Return the principal that has been authenticated for this Request.
+ */
+ public Principal getPrincipal() {
+ return (userPrincipal);
+ }
+
+ /**
+ * Return the protocol and version used to make this Request.
+ */
+ public String getProtocol() {
+ return httpRequest.protocol().toString();
+ }
+
+ /**
+ * Return the query string associated with this request.
+ */
+ public String getQueryString() {
+ String queryString = httpRequest.queryString().toString();
+ if (queryString == null || queryString.equals("")) {
+ return (null);
+ } else {
+ return queryString;
+ }
+ }
+
+
+ /**
+ * Read the Reader wrapping the input stream for this Request. The
+ * default implementation wraps a <code>BufferedReader</code> around the
+ * servlet input stream returned by <code>createInputStream()</code>.
+ *
+ * @exception IllegalStateException if <code>getInputStream()</code>
+ * has already been called for this request
+ * @exception IOException if an input/output error occurs
+ */
+ public BufferedReader getReader() throws IOException {
+
+ if (usingInputStream)
+ throw new IllegalStateException
+ ("usingInputStream");
+
+ usingReader = true;
+ //inputBuffer.setConverter();// getB2C());
+ return reader;
+
+ }
+
+ /**
+ * Cached list of encoders.
+ */
+ protected HashMap encoders = new HashMap();
+
+ public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1";
+
+ /**
+ * Converter for the encoding associated with the request.
+ * If encoding is changed - a different encoder will be returned.
+ *
+ * Encoders are cached ( per request ) - at least 8K per charset
+ */
+ public B2CConverter getB2C() throws IOException {
+ String enc = getCharacterEncoding();
+ if (enc == null) {
+ enc = DEFAULT_CHARACTER_ENCODING;
+ }
+ B2CConverter conv =
+ (B2CConverter) encoders.get(enc);
+ if (conv == null) {
+ conv = new B2CConverter(enc);
+ encoders.put(enc, conv);
+ }
+ return conv;
+ }
+
+ /**
+ * Return the real path of the specified virtual path.
+ *
+ * @param path Path to be translated
+ *
+ * @deprecated As of version 2.1 of the Java Servlet API, use
+ * <code>ServletContext.getRealPath()</code>.
+ */
+ public String getRealPath(String path) {
+
+ if (context == null)
+ return (null);
+ ServletContext servletContext = context; // .getServletContext();
+ if (servletContext == null)
+ return (null);
+ else {
+ try {
+ return (servletContext.getRealPath(path));
+ } catch (IllegalArgumentException e) {
+ return (null);
+ }
+ }
+
+ }
+
+
+ /**
+ * Return the remote IP address making this Request.
+ */
+ public String getRemoteAddr() {
+ if (httpRequest.remoteAddr().isNull()) {
+ httpRequest.remoteAddr().setString(connector.getRemoteAddr(this));
+ }
+ return httpRequest.remoteAddr().toString();
+ }
+
+
+ /**
+ * Return the remote host name making this Request.
+ */
+ public String getRemoteHost() {
+ if (httpRequest.remoteHost().isNull()) {
+ httpRequest.remoteHost().setString(connector.getRemoteHost(this));
+ }
+ return httpRequest.remoteHost().toString();
+ }
+
+
+ /**
+ * Returns the Internet Protocol (IP) source port of the client
+ * or last proxy that sent the request.
+ */
+ public int getRemotePort(){
+ return httpRequest.getRemotePort();
+ }
+
+
+ /**
+ * Return the name of the remote user that has been authenticated
+ * for this Request.
+ */
+ public String getRemoteUser() {
+
+ if (userPrincipal != null) {
+ return (userPrincipal.getName());
+ } else {
+ return (null);
+ }
+
+ }
+
+
+ /**
+ * Return the <code>ServletRequest</code> for which this object
+ * is the facade. This method must be implemented by a subclass.
+ */
+ public HttpServletRequest getRequest() {
+ return this;
+ }
+
+ public HttpRequest getHttpRequest() {
+ return httpRequest;
+ }
+
+ 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
+ * path, which may be interpreted as relative to the current request path.
+ *
+ * @param path Path of the resource to be wrapped
+ */
+ public RequestDispatcher getRequestDispatcher(String path) {
+
+ if (context == null)
+ return (null);
+
+ // If the path is already context-relative, just pass it through
+ if (path == null)
+ return (null);
+ else if (path.startsWith("/"))
+ return (context.getRequestDispatcher(path));
+
+ // Convert a request-relative path to a context-relative one
+ String servletPath = (String) getAttribute(RequestDispatcherImpl.INCLUDE_SERVLET_PATH_ATTR);
+ if (servletPath == null)
+ servletPath = getServletPath();
+
+ // Add the path info, if there is any
+ String pathInfo = getPathInfo();
+ String requestPath = null;
+
+ if (pathInfo == null) {
+ requestPath = servletPath;
+ } else {
+ requestPath = servletPath + pathInfo;
+ }
+
+ int pos = requestPath.lastIndexOf('/');
+ String relative = null;
+ if (pos >= 0) {
+ relative = RequestUtil.normalize
+ (requestPath.substring(0, pos + 1) + path);
+ } else {
+ relative = RequestUtil.normalize(requestPath + path);
+ }
+
+ return (context.getRequestDispatcher(relative));
+
+ }
+
+
+ /**
+ * Return the session identifier included in this request, if any.
+ */
+ public String getRequestedSessionId() {
+ return (requestedSessionId);
+ }
+
+
+ // ---------------------------------------------------- HttpRequest Methods
+
+
+ /**
+ * Get the request path.
+ *
+ * @return the request path
+ */
+ public MessageBytes getRequestPathMB() {
+ return (mappingData.requestPath);
+ }
+
+
+ /**
+ * Return the request URI for this request.
+ */
+ public String getRequestURI() {
+ return httpRequest.requestURI().toString();
+ }
+
+ /**
+ */
+ public void setRequestURI(String uri) {
+ httpRequest.decodedURI().setString(uri);
+ try {
+ UriNormalizer.decodeRequest(httpRequest.decodedURI(),
+ httpRequest.requestURI(), httpRequest.getURLDecoder());
+ } catch(IOException ioe) {
+ ioe.printStackTrace();
+ return;
+ }
+ }
+
+
+
+ /**
+ * Reconstructs the URL the client used to make the request.
+ * The returned URL contains a protocol, server name, port
+ * number, and server path, but it does not include query
+ * string parameters.
+ * <p>
+ * Because this method returns a <code>StringBuffer</code>,
+ * not a <code>String</code>, you can modify the URL easily,
+ * for example, to append query parameters.
+ * <p>
+ * This method is useful for creating redirect messages and
+ * for reporting errors.
+ *
+ * @return A <code>StringBuffer</code> object containing the
+ * reconstructed URL
+ */
+ public StringBuffer getRequestURL() {
+
+ StringBuffer url = new StringBuffer();
+ String scheme = getScheme();
+ int port = getServerPort();
+ if (port < 0)
+ port = 80; // Work around java.net.URL bug
+
+ url.append(scheme);
+ url.append("://");
+ url.append(getServerName());
+ if ((scheme.equals("http") && (port != 80))
+ || (scheme.equals("https") && (port != 443))) {
+ url.append(':');
+ url.append(port);
+ }
+ url.append(getRequestURI());
+
+ return (url);
+
+ }
+
+
+ /**
+ * Return the Response with which this Request is associated.
+ */
+ public ServletResponseImpl getResponse() {
+ return (this.response);
+ }
+
+
+ /**
+ * Return the scheme used to make this Request.
+ */
+ public String getScheme() {
+ String scheme = httpRequest.scheme().toString();
+ if (scheme == null) {
+ scheme = (isSecure() ? "https" : "http");
+ }
+ return scheme;
+ }
+
+
+ /**
+ * Return the server name responding to this Request.
+ */
+ public String getServerName() {
+ return (httpRequest.serverName().toString());
+ }
+
+
+ /**
+ * Return the server port responding to this Request.
+ */
+ public int getServerPort() {
+ return (httpRequest.getServerPort());
+ }
+
+
+ /**
+ * Return the portion of the request URI used to select the servlet
+ * that will process this request.
+ */
+ public String getServletPath() {
+ return (mappingData.wrapperPath.toString());
+ }
+
+
+ /**
+ * Get the servlet path.
+ *
+ * @return the servlet path
+ */
+ public MessageBytes getServletPathMB() {
+ return (mappingData.wrapperPath);
+ }
+
+
+
+ /**
+ * Return the input stream associated with this Request.
+ */
+ public InputStream getStream() {
+ return inputStream;
+ }
+
+
+ /**
+ * Return the principal that has been authenticated for this Request.
+ */
+ public Principal getUserPrincipal() {
+ return userPrincipal;
+ }
+
+
+ /**
+ * Return the Wrapper within which this Request is being processed.
+ */
+ public ServletConfigImpl getWrapper() {
+ return (this.wrapper);
+ }
+
+
+ /**
+ * Return <code>true</code> if the session identifier included in this
+ * request came from a cookie.
+ */
+ public boolean isRequestedSessionIdFromCookie() {
+
+ if (requestedSessionId != null)
+ return (requestedSessionCookie);
+ else
+ return (false);
+
+ }
+
+
+ /**
+ * Return <code>true</code> if the session identifier included in this
+ * request came from the request URI.
+ *
+ * @deprecated As of Version 2.1 of the Java Servlet API, use
+ * <code>isRequestedSessionIdFromURL()</code> instead.
+ */
+ public boolean isRequestedSessionIdFromUrl() {
+ return (isRequestedSessionIdFromURL());
+ }
+
+
+ /**
+ * Return <code>true</code> if the session identifier included in this
+ * request came from the request URI.
+ */
+ public boolean isRequestedSessionIdFromURL() {
+
+ if (requestedSessionId != null)
+ return (requestedSessionURL);
+ else
+ return (false);
+
+ }
+
+
+ /**
+ * Return <code>true</code> if the session identifier included in this
+ * request identifies a valid session.
+ */
+ public boolean isRequestedSessionIdValid() {
+
+ if (requestedSessionId == null)
+ return (false);
+ if (context == null)
+ return (false);
+ UserSessionManager manager = context.getManager();
+ if (manager == null)
+ return (false);
+ HttpSession session = null;
+ try {
+ session = manager.findSession(requestedSessionId);
+ } catch (IOException e) {
+ session = null;
+ }
+ if ((session != null) && manager.isValid(session))
+ return (true);
+ else
+ return (false);
+
+ }
+
+ /**
+ * Was this request received on a secure connection?
+ */
+ public boolean isSecure() {
+ return (secure);
+ }
+
+
+ /**
+ * Return <code>true</code> if the authenticated user principal
+ * possesses the specified role name.
+ *
+ * @param role Role name to be validated
+ */
+ public boolean isUserInRole(String role) {
+ // Have we got an authenticated principal at all?
+ Principal userPrincipal = getPrincipal();
+ if (userPrincipal == null)
+ return (false);
+
+ // Identify the Realm we will use for checking role assignmenets
+ if (context == null)
+ return (false);
+
+ // Check for a role alias defined in a <security-role-ref> element
+ if (wrapper != null) {
+ String realRole = wrapper.getSecurityRoleRef(role);
+ if (realRole != null) {
+ role = realRole;
+ }
+ }
+
+ if (role.equals(userPrincipal.getName())) {
+ return true;
+ }
+
+ // TODO: check !!!!
+ // Check for a role defined directly as a <security-role>
+ return false;
+ }
+
+ /**
+ * Release all object references, and initialize instance variables, in
+ * preparation for reuse of this object.
+ */
+ public void recycle() {
+
+ wrapper = null;
+
+ dispatcherType = null;
+ requestDispatcherPath = null;
+
+ authType = null;
+ inputBuffer.recycle();
+ usingInputStream = false;
+ usingReader = false;
+ userPrincipal = null;
+ subject = null;
+ sessionParsed = false;
+ parametersParsed = false;
+ cookiesParsed = false;
+ locales.clear();
+ localesParsed = false;
+ secure = false;
+
+ attributes.clear();
+ //notes.clear();
+ cookies = null;
+
+ if (session != null) {
+ context.getManager().endAccess(session);
+ }
+ context = null;
+ session = null;
+ requestedSessionCookie = false;
+ requestedSessionId = null;
+ requestedSessionURL = false;
+
+ parameterMap.setLocked(false);
+ parameterMap.clear();
+
+ mappingData.recycle();
+ httpRequest.recycle();
+ }
+
+
+ /**
+ * Remove the specified request attribute if it exists.
+ *
+ * @param name Name of the request attribute to remove
+ */
+ public void removeAttribute(String name) {
+ Object value = null;
+ boolean found = false;
+
+ // Remove the specified attribute
+ // Check for read only attribute
+ // requests are per thread so synchronization unnecessary
+// if (readOnlyAttributes.containsKey(name)) {
+// return;
+// }
+ found = attributes.containsKey(name);
+ if (found) {
+ value = attributes.get(name);
+ attributes.remove(name);
+ } else {
+ return;
+ }
+
+ // Notify interested application event listeners
+ List listeners = context.getListeners();
+ if (listeners.size() == 0)
+ return;
+ ServletRequestAttributeEvent event = null;
+ for (int i = 0; i < listeners.size(); i++) {
+ if (!(listeners.get(i) instanceof ServletRequestAttributeListener))
+ continue;
+ ServletRequestAttributeListener listener =
+ (ServletRequestAttributeListener) listeners.get(i);
+ try {
+ if (event == null) {
+ event =
+ new ServletRequestAttributeEvent(context.getServletContext(),
+ getRequest(), name, value);
+ }
+ listener.attributeRemoved(event);
+ } catch (Throwable t) {
+ context.getLogger().log(Level.WARNING, "ServletRequestAttributeListner.attributeRemoved()", t);
+ // Error valve will pick this execption up and display it to user
+ attributes.put( ServletRequestImpl.EXCEPTION_ATTR, t );
+ }
+ }
+ }
+
+
+ /**
+ * Set the specified request attribute to the specified value.
+ *
+ * @param name Name of the request attribute to set
+ * @param value The associated value
+ */
+ public void setAttribute(String name, Object value) {
+
+ // Name cannot be null
+ if (name == null)
+ throw new IllegalArgumentException
+ ("setAttribute() name == null");
+
+ // Null value is the same as removeAttribute()
+ if (value == null) {
+ removeAttribute(name);
+ return;
+ }
+
+ if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
+ dispatcherType = value;
+ return;
+ } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
+ requestDispatcherPath = value;
+ return;
+ }
+
+ Object oldValue = null;
+ boolean replaced = false;
+
+ // Add or replace the specified attribute
+ // Check for read only attribute
+ // requests are per thread so synchronization unnecessary
+// if (readOnlyAttributes.containsKey(name)) {
+// return;
+// }
+
+ oldValue = attributes.put(name, value);
+ if (oldValue != null) {
+ replaced = true;
+ }
+
+ // Pass special attributes to the native layer
+// if (name.startsWith("org.apache.tomcat.")) {
+// reqB.setAttribute(name, value);
+// }
+//
+ // Notify interested application event listeners
+ List listeners = context.getListeners();
+ if (listeners.size() == 0)
+ return;
+ ServletRequestAttributeEvent event = null;
+
+ for (int i = 0; i < listeners.size(); i++) {
+ if (!(listeners.get(i) instanceof ServletRequestAttributeListener))
+ continue;
+ ServletRequestAttributeListener listener =
+ (ServletRequestAttributeListener) listeners.get(i);
+ try {
+ if (event == null) {
+ if (replaced)
+ event =
+ new ServletRequestAttributeEvent(context.getServletContext(),
+ getRequest(), name, oldValue);
+ else
+ event =
+ new ServletRequestAttributeEvent(context.getServletContext(),
+ getRequest(), name, value);
+ }
+ if (replaced) {
+ listener.attributeReplaced(event);
+ } else {
+ listener.attributeAdded(event);
+ }
+ } catch (Throwable t) {
+ context.getLogger().log(Level.WARNING, "ServletRequestAttributeListener error", t);
+ // Error valve will pick this execption up and display it to user
+ attributes.put( ServletRequestImpl.EXCEPTION_ATTR, t );
+ }
+ }
+ }
+
+
+ // --------------------------------------------- HttpServletRequest Methods
+
+
+ /**
+ * Set the authentication type used for this request, if any; otherwise
+ * set the type to <code>null</code>. Typical values are "BASIC",
+ * "DIGEST", or "SSL".
+ *
+ * @param type The authentication type used
+ */
+ public void setAuthType(String type) {
+ this.authType = type;
+ }
+
+
+ /**
+ * Overrides the name of the character encoding used in the body of
+ * this request. This method must be called prior to reading request
+ * parameters or reading input using <code>getReader()</code>.
+ *
+ * @param enc The character encoding to be used
+ *
+ * @exception UnsupportedEncodingException if the specified encoding
+ * is not supported
+ *
+ * @since Servlet 2.3
+ */
+ public void setCharacterEncoding(String enc)
+ throws UnsupportedEncodingException {
+
+ // Ensure that the specified encoding is valid
+ byte buffer[] = new byte[1];
+ buffer[0] = (byte) 'a';
+ String dummy = new String(buffer, enc);
+
+ // Save the validated encoding
+ httpRequest.setCharacterEncoding(enc);
+
+ }
+
+
+// public void setConnection(Http11Connection con) {
+// this.con = con;
+// //reqB.messageWriter.setConnection(con);
+// //inputBuffer.setRequest(req);
+// }
+
+
+ /**
+ * Set the content length associated with this Request.
+ *
+ * @param length The new content length
+ */
+ public void setContentLength(int length) {
+ // Not used
+ }
+
+
+ /**
+ * Set the content type (and optionally the character encoding)
+ * associated with this Request. For example,
+ * <code>text/html; charset=ISO-8859-4</code>.
+ *
+ * @param type The new content type
+ */
+ public void setContentType(String type) {
+ // Not used
+ }
+
+
+ /**
+ * Set the Context within which this Request is being processed. This
+ * must be called as soon as the appropriate Context is identified, because
+ * it identifies the value to be returned by <code>getContextPath()</code>,
+ * and thus enables parsing of the request URI.
+ *
+ * @param context The newly associated Context
+ */
+ public void setContext(ServletContextImpl context) {
+ this.context = context;
+ }
+
+
+ /**
+ * Set the context path for this Request. This will normally be called
+ * when the associated Context is mapping the Request to a particular
+ * Wrapper.
+ *
+ * @param path The context path
+ */
+ public void setContextPath(String path) {
+
+ if (path == null) {
+ mappingData.contextPath.setString("");
+ } else {
+ mappingData.contextPath.setString(path);
+ }
+
+ }
+
+
+ /**
+ * Set the set of cookies recieved with this Request.
+ */
+ public void setCookies(Cookie[] cookies) {
+
+ this.cookies = cookies;
+
+ }
+
+
+ /**
+ * Set the decoded request URI.
+ *
+ * @param uri The decoded request URI
+ */
+ public void setDecodedRequestURI(String uri) {
+ // Not used
+ }
+
+
+ /**
+ * Set the HTTP request method used for this Request.
+ *
+ * @param method The request method
+ */
+ public void setMethod(String method) {
+ httpRequest.method().setString(method);
+ }
+
+
+ /**
+ * Set the path information for this Request. This will normally be called
+ * when the associated Context is mapping the Request to a particular
+ * Wrapper.
+ *
+ * @param path The path information
+ */
+ public void setPathInfo(String path) {
+ mappingData.pathInfo.setString(path);
+ }
+
+
+ /**
+ * Set the protocol name and version associated with this Request.
+ *
+ * @param protocol Protocol name and version
+ */
+ public void setProtocol(String protocol) {
+ // Not used
+ }
+
+
+ /**
+ * Set the query string for this Request. This will normally be called
+ * by the HTTP Connector, when it parses the request headers.
+ *
+ * @param query The query string
+ */
+ public void setQueryString(String query) {
+ // Not used
+ }
+
+
+ /**
+ * Set the IP address of the remote client associated with this Request.
+ *
+ * @param remoteAddr The remote IP address
+ */
+ public void setRemoteAddr(String remoteAddr) {
+ // Not used
+ }
+
+
+ /**
+ * Set the fully qualified name of the remote client associated with this
+ * Request.
+ *
+ * @param remoteHost The remote host name
+ */
+ public void setRemoteHost(String remoteHost) {
+ // Not used
+ }
+
+
+ /**
+ * Set a flag indicating whether or not the requested session ID for this
+ * request came in through a cookie. This is normally called by the
+ * HTTP Connector, when it parses the request headers.
+ *
+ * @param flag The new flag
+ */
+ public void setRequestedSessionCookie(boolean flag) {
+
+ this.requestedSessionCookie = flag;
+
+ }
+
+
+ /**
+ * Set the requested session ID for this request. This is normally called
+ * by the HTTP Connector, when it parses the request headers.
+ *
+ * @param id The new session id
+ */
+ public void setRequestedSessionId(String id) {
+
+ this.requestedSessionId = id;
+
+ }
+
+
+ /**
+ * Set a flag indicating whether or not the requested session ID for this
+ * request came in through a URL. This is normally called by the
+ * HTTP Connector, when it parses the request headers.
+ *
+ * @param flag The new flag
+ */
+ public void setRequestedSessionURL(boolean flag) {
+
+ this.requestedSessionURL = flag;
+
+ }
+
+
+ /**
+ * Set the name of the scheme associated with this request. Typical values
+ * are <code>http</code>, <code>https</code>, and <code>ftp</code>.
+ *
+ * @param scheme The scheme
+ */
+ public void setScheme(String scheme) {
+ // Not used
+ }
+
+
+ /**
+ * Set the value to be returned by <code>isSecure()</code>
+ * for this Request.
+ *
+ * @param secure The new isSecure value
+ */
+ public void setSecure(boolean secure) {
+ this.secure = secure;
+ }
+
+
+ /**
+ * Set the name of the server (virtual host) to process this request.
+ *
+ * @param name The server name
+ */
+ public void setServerName(String name) {
+ httpRequest.serverName().setString(name);
+ }
+
+
+ /**
+ * Set the port number of the server to process this request.
+ *
+ * @param port The server port
+ */
+ public void setServerPort(int port) {
+ httpRequest.setServerPort(port);
+ }
+
+
+ /**
+ * Set the servlet path for this Request. This will normally be called
+ * when the associated Context is mapping the Request to a particular
+ * Wrapper.
+ *
+ * @param path The servlet path
+ */
+ public void setServletPath(String path) {
+ if (path != null)
+ mappingData.wrapperPath.setString(path);
+ }
+
+
+ /**
+ * Set the input stream associated with this Request.
+ *
+ * @param stream The new input stream
+ */
+ public void setStream(InputStream stream) {
+ // Ignore
+ }
+
+
+ /**
+ * Set the Principal who has been authenticated for this Request. This
+ * value is also used to calculate the value to be returned by the
+ * <code>getRemoteUser()</code> method.
+ *
+ * @param principal The user Principal
+ */
+ public void setUserPrincipal(Principal principal) {
+
+ if (System.getSecurityManager() != null){
+ HttpSession session = getSession(false);
+ if ( (subject != null) &&
+ (!subject.getPrincipals().contains(principal)) ){
+ subject.getPrincipals().add(principal);
+ } else if (session != null &&
+ session.getAttribute(ServletRequestImpl.SUBJECT_ATTR) == null) {
+ subject = new Subject();
+ subject.getPrincipals().add(principal);
+ }
+ if (session != null){
+ session.setAttribute(ServletRequestImpl.SUBJECT_ATTR, subject);
+ }
+ }
+
+ this.userPrincipal = principal;
+ }
+
+
+ /**
+ * Set the Wrapper within which this Request is being processed. This
+ * must be called as soon as the appropriate Wrapper is identified, and
+ * before the Request is ultimately passed to an application servlet.
+ * @param wrapper The newly associated Wrapper
+ */
+ public void setWrapper(ServletConfigImpl wrapper) {
+ this.wrapper = wrapper;
+ }
+
+
+ public String toString() {
+ return httpRequest.requestURI().toString();
+ }
+
+
+ /**
+ * Configures the given JSESSIONID cookie.
+ *
+ * @param cookie The JSESSIONID cookie to be configured
+ */
+ protected void configureSessionCookie(Cookie cookie) {
+ cookie.setMaxAge(-1);
+ String contextPath = null;
+ if (//!connector.getEmptySessionPath() &&
+ (getContext() != null)) {
+ contextPath = getContext().getEncodedPath();
+ }
+ if ((contextPath != null) && (contextPath.length() > 0)) {
+ cookie.setPath(contextPath);
+ } else {
+ cookie.setPath("/");
+ }
+ if (isSecure()) {
+ cookie.setSecure(true);
+ }
+ }
+
+
+ /**
+ * Return the session associated with this Request, creating one
+ * if necessary.
+ */
+ public HttpSession getSession() {
+ return getSession(true);
+ }
+
+
+ public HttpSession getSession(boolean create) {
+
+ // There cannot be a session if no context has been assigned yet
+ if (context == null)
+ return (null);
+
+
+ // Return the requested session if it exists and is valid
+ UserSessionManager manager = null;
+ if (context != null)
+ manager = context.getManager();
+ if (manager == null)
+ return (null); // Sessions are not supported
+
+ // Return the current session if it exists and is valid
+ if ((session != null) && !manager.isValid(session))
+ session = null;
+ if (session != null)
+ return (session);
+
+
+ if (requestedSessionId != null) {
+ try {
+ session = manager.findSession(requestedSessionId);
+ } catch (IOException e) {
+ session = null;
+ }
+ if ((session != null) && !manager.isValid(session))
+ session = null;
+ if (session != null) {
+ manager.access(session);
+ return (session);
+ }
+ }
+
+ // Create a new session if requested and the response is not committed
+ if (!create)
+ return (null);
+ if ((context != null) && (response != null) &&
+ context.getCookies() &&
+ getResponse().isCommitted()) {
+ throw new IllegalStateException
+ ("isCommited()");
+ }
+
+ // Attempt to reuse session id if one was submitted in a cookie
+ // Do not reuse the session id if it is from a URL, to prevent possible
+ // phishing attacks
+ if (// connector.getEmptySessionPath() &&
+ isRequestedSessionIdFromCookie()) {
+ session = manager.createSession(getRequestedSessionId());
+ } else {
+ session = manager.createSession(null);
+ }
+
+ // Creating a new session cookie based on that session
+ if ((session != null) && (getContext() != null)
+ && getContext().getCookies()) {
+ Cookie cookie = new Cookie(ServletRequestImpl.SESSION_COOKIE_NAME,
+ session.getId());
+ configureSessionCookie(cookie);
+ response.addCookie(cookie);
+ }
+
+ if (session != null) {
+ manager.access(session);
+ return (session);
+ } else {
+ return (null);
+ }
+
+ }
+
+
+ /**
+ * Return the URI converter.
+ */
+// protected B2CConverter getURIConverter() {
+// return URIConverter;
+// }
+//
+
+ // ------------------------------------------------------ Protected Methods
+
+
+ /**
+ * Parse cookies.
+ */
+ protected void parseCookies() {
+
+ cookiesParsed = true;
+
+ Cookies serverCookies = httpRequest.getCookies();
+ int count = serverCookies.getCookieCount();
+ if (count <= 0)
+ return;
+
+ cookies = new Cookie[count];
+
+ int idx=0;
+ for (int i = 0; i < count; i++) {
+ ServerCookie scookie = serverCookies.getCookie(i);
+ try {
+ Cookie cookie = new Cookie(scookie.getName().toString(),
+ scookie.getValue().toString());
+ cookie.setPath(scookie.getPath().toString());
+ cookie.setVersion(scookie.getVersion());
+ String domain = scookie.getDomain().toString();
+ if (domain != null) {
+ cookie.setDomain(scookie.getDomain().toString());
+ }
+ cookies[idx++] = cookie;
+ } catch(IllegalArgumentException e) {
+ // Ignore bad cookie
+ }
+ }
+ if( idx < count ) {
+ Cookie [] ncookies = new Cookie[idx];
+ System.arraycopy(cookies, 0, ncookies, 0, idx);
+ cookies = ncookies;
+ }
+
+ }
+
+ /**
+ * Parse request locales.
+ */
+ protected void parseLocales() {
+
+ localesParsed = true;
+
+ Enumeration values = getHeaders("accept-language");
+
+ while (values.hasMoreElements()) {
+ String value = values.nextElement().toString();
+ parseLocalesHeader(value);
+ }
+
+ }
+
+ /**
+ * Parse accept-language header value.
+ */
+ protected void parseLocalesHeader(String value) {
+
+ TreeMap locales = new LocaleParser().parseLocale(value);
+ // Process the quality values in highest->lowest order (due to
+ // negating the Double value when creating the key)
+ Iterator keys = locales.keySet().iterator();
+ while (keys.hasNext()) {
+ Double key = (Double) keys.next();
+ ArrayList list = (ArrayList) locales.get(key);
+ Iterator values = list.iterator();
+ while (values.hasNext()) {
+ Locale locale = (Locale) values.next();
+ addLocale(locale);
+ }
+ }
+
+ }
+
+ /**
+ * Parse request parameters.
+ */
+ protected void parseParameters() {
+
+ parametersParsed = true;
+
+ Parameters parameters = httpRequest.getParameters();
+
+ // getCharacterEncoding() may have been overridden to search for
+ // hidden form field containing request encoding
+ String enc = getCharacterEncoding();
+
+// boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
+ if (enc != null) {
+ parameters.setEncoding(enc);
+// if (useBodyEncodingForURI) {
+// parameters.setQueryStringEncoding(enc);
+// }
+ } else {
+ parameters.setEncoding(DEFAULT_CHARACTER_ENCODING);
+// if (useBodyEncodingForURI) {
+// parameters.setQueryStringEncoding
+// (DEFAULT_CHARACTER_ENCODING);
+// }
+ }
+
+ parameters.handleQueryParameters();
+
+ if (usingInputStream || usingReader)
+ return;
+
+ if (!getMethod().equalsIgnoreCase("POST"))
+ return;
+
+ String contentType = getContentType();
+ if (contentType == null)
+ contentType = "";
+ int semicolon = contentType.indexOf(';');
+ if (semicolon >= 0) {
+ contentType = contentType.substring(0, semicolon).trim();
+ } else {
+ contentType = contentType.trim();
+ }
+ if (!("application/x-www-form-urlencoded".equals(contentType)))
+ return;
+
+ int len = getContentLength();
+
+ if (len > 0) {
+// int maxPostSize = connector.getMaxPostSize();
+// if ((maxPostSize > 0) && (len > maxPostSize)) {
+// context.getLogger().info
+// (sm.getString("reqB.postTooLarge"));
+// throw new IllegalStateException("Post too large");
+// }
+ try {
+ byte[] formData = null;
+ if (len < CACHED_POST_LEN) {
+ if (postData == null)
+ postData = new byte[CACHED_POST_LEN];
+ formData = postData;
+ } else {
+ formData = new byte[len];
+ }
+ int actualLen = readPostBody(formData, len);
+ if (actualLen == len) {
+ parameters.processParameters(formData, 0, len);
+ }
+ } catch (Throwable t) {
+ ; // Ignore
+ }
+ }
+
+ }
+
+
+ /**
+ * Parse session id in URL. Done in request for performance.
+ * TODO: should be done in manager
+ */
+ protected void parseSessionCookiesId() {
+ String sessionCookieName = context.getSessionCookieName();
+
+ // Parse session id from cookies
+ Cookies serverCookies = httpRequest.getCookies();
+ int count = serverCookies.getCookieCount();
+ if (count <= 0)
+ return;
+
+ for (int i = 0; i < count; i++) {
+ ServerCookie scookie = serverCookies.getCookie(i);
+ if (scookie.getName().equals(sessionCookieName)) {
+ // Override anything requested in the URL
+ if (!isRequestedSessionIdFromCookie()) {
+ // Accept only the first session id cookie
+ //scookie.getValue().convertToAscii();
+
+ setRequestedSessionId
+ (scookie.getValue().toString());
+ setRequestedSessionCookie(true);
+ setRequestedSessionURL(false);
+ } else {
+ if (!isRequestedSessionIdValid()) {
+ // Replace the session id until one is valid
+ //scookie.getValue().convertToAscii();
+ setRequestedSessionId
+ (scookie.getValue().toString());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Parse session id in URL.
+ */
+ protected void parseSessionId() {
+ ServletRequestImpl request = this;
+ ByteChunk uriBC = httpRequest.requestURI().getByteChunk();
+ int semicolon = uriBC.indexOf(match, 0, match.length(), 0);
+
+ if (semicolon > 0) {
+
+ // Parse session ID, and extract it from the decoded request URI
+ int start = uriBC.getStart();
+ int end = uriBC.getEnd();
+
+ int sessionIdStart = semicolon + match.length();
+ int semicolon2 = uriBC.indexOf(';', sessionIdStart);
+ if (semicolon2 >= 0) {
+ request.setRequestedSessionId
+ (new String(uriBC.getBuffer(), start + sessionIdStart,
+ semicolon2 - sessionIdStart));
+ // Extract session ID from request URI
+ byte[] buf = uriBC.getBuffer();
+ for (int i = 0; i < end - start - semicolon2; i++) {
+ buf[start + semicolon + i]
+ = buf[start + i + semicolon2];
+ }
+ uriBC.setBytes(buf, start, end - start - semicolon2 + semicolon);
+ } else {
+ request.setRequestedSessionId
+ (new String(uriBC.getBuffer(), start + sessionIdStart,
+ (end - start) - sessionIdStart));
+ uriBC.setEnd(start + semicolon);
+ }
+ request.setRequestedSessionURL(true);
+
+ } else {
+ request.setRequestedSessionId(null);
+ request.setRequestedSessionURL(false);
+ }
+
+ }
+
+
+ /**
+ * Read post body in an array.
+ */
+ protected int readPostBody(byte body[], int len)
+ throws IOException {
+
+ int offset = 0;
+ do {
+ int inputLen = getStream().read(body, offset, len - offset);
+ if (inputLen <= 0) {
+ return offset;
+ }
+ offset += inputLen;
+ } while ((len - offset) > 0);
+ return len;
+
+ }
+
+
+ /**
+ * Test if a given name is one of the special Servlet-spec SSL attributes.
+ */
+ static boolean isSSLAttribute(String name) {
+ return ServletRequestImpl.CERTIFICATES_ATTR.equals(name) ||
+ ServletRequestImpl.CIPHER_SUITE_ATTR.equals(name) ||
+ ServletRequestImpl.KEY_SIZE_ATTR.equals(name) ||
+ ServletRequestImpl.SSL_SESSION_ID_ATTR.equals(name);
+ }
+
+
+ public void addAsyncListener(AsyncListener listener) {
+ }
+
+
+
+ public void addAsyncListener(AsyncListener listener,
+ ServletRequest servletRequest,
+ ServletResponse servletResponse) {
+ }
+
+
+
+ @Override
+ public AsyncContext getAsyncContext() {
+ return null;
+ }
+
+
+
+ @Override
+ public ServletContext getServletContext() {
+ return null;
+ }
+
+
+
+ @Override
+ public boolean isAsyncStarted() {
+ return false;
+ }
+
+
+
+ @Override
+ public boolean isAsyncSupported() {
+ return false;
+ }
+
+
+ public void setAsyncTimeout(long timeout) {
+ }
+
+
+
+ @Override
+ public AsyncContext startAsync() throws IllegalStateException {
+ return null;
+ }
+
+
+ @Override
+ public AsyncContext startAsync(ServletRequest servletRequest,
+ ServletResponse servletResponse)
+ throws IllegalStateException {
+ return null;
+ }
+
+
+
+ @Override
+ public boolean authenticate(HttpServletResponse response)
+ throws IOException, ServletException {
+ return false;
+ }
+
+
+
+ @Override
+ public Part getPart(String name) {
+ return null;
+ }
+
+
+
+ @Override
+ public void login(String username, String password) throws ServletException {
+ }
+
+
+
+ @Override
+ public void logout() throws ServletException {
+ }
+
+
+
+ public long getAsyncTimeout() {
+ return 0;
+ }
+
+
+
+ @Override
+ public DispatcherType getDispatcherType() {
+ return null;
+ }
+
+
+ @Override
+ public Collection<Part> getParts() throws IOException, ServletException {
+ return null;
+ }
+
+
+}
--- /dev/null
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.coyote.servlet;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpSession;
+
+import org.apache.tomcat.servlets.session.UserSessionManager;
+import org.apache.tomcat.servlets.util.Enumerator;
+import org.apache.tomcat.servlets.util.RequestUtil;
+
+
+/**
+ * Wrapper around a <code>javax.servlet.http.HttpServletRequest</code>
+ * that transforms an application request object (which might be the original
+ * one passed to a servlet, or might be based on the 2.3
+ * <code>javax.servlet.http.HttpServletRequestWrapper</code> class)
+ * back into an internal <code>org.apache.catalina.HttpRequest</code>.
+ * <p>
+ * <strong>WARNING</strong>: Due to Java's lack of support for multiple
+ * inheritance, all of the logic in <code>ApplicationRequest</code> is
+ * duplicated in <code>ApplicationHttpRequest</code>. Make sure that you
+ * keep these two classes in synchronization when making changes!
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ */
+public class ServletRequestWrapperImpl extends HttpServletRequestWrapper {
+
+
+ // ------------------------------------------------------- Static Variables
+
+
+ /**
+ * The set of attribute names that are special for request dispatchers.
+ */
+ protected static final String specials[] =
+ { RequestDispatcherImpl.INCLUDE_REQUEST_URI_ATTR,
+ RequestDispatcherImpl.INCLUDE_CONTEXT_PATH_ATTR,
+ RequestDispatcherImpl.INCLUDE_SERVLET_PATH_ATTR,
+ RequestDispatcherImpl.INCLUDE_PATH_INFO_ATTR,
+ RequestDispatcherImpl.INCLUDE_QUERY_STRING_ATTR,
+ RequestDispatcherImpl.FORWARD_REQUEST_URI_ATTR,
+ RequestDispatcherImpl.FORWARD_CONTEXT_PATH_ATTR,
+ RequestDispatcherImpl.FORWARD_SERVLET_PATH_ATTR,
+ RequestDispatcherImpl.FORWARD_PATH_INFO_ATTR,
+ RequestDispatcherImpl.FORWARD_QUERY_STRING_ATTR };
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Construct a new wrapped request around the specified servlet request.
+ *
+ * @param request The servlet request being wrapped
+ */
+ public ServletRequestWrapperImpl(HttpServletRequest request,
+ ServletContextImpl context,
+ boolean crossContext) {
+
+ super(request);
+ this.context = context;
+ this.crossContext = crossContext;
+ setRequest(request);
+
+ }
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ /**
+ * The context for this request.
+ */
+ protected ServletContextImpl context = null;
+
+
+ /**
+ * The context path for this request.
+ */
+ protected String contextPath = null;
+
+
+ /**
+ * If this request is cross context, since this changes session accesss
+ * behavior.
+ */
+ protected boolean crossContext = false;
+
+
+ /**
+ * The current dispatcher type.
+ */
+ protected Object dispatcherType = null;
+
+
+ /**
+ * Descriptive information about this implementation.
+ */
+ protected static final String info =
+ "org.apache.catalina.core.ApplicationHttpRequest/1.0";
+
+
+ /**
+ * The request parameters for this request. This is initialized from the
+ * wrapped request, but updates are allowed.
+ */
+ protected Map parameters = null;
+
+
+ /**
+ * Have the parameters for this request already been parsed?
+ */
+ private boolean parsedParams = false;
+
+
+ /**
+ * The path information for this request.
+ */
+ protected String pathInfo = null;
+
+
+ /**
+ * The query parameters for the current request.
+ */
+ private String queryParamString = null;
+
+
+ /**
+ * The query string for this request.
+ */
+ protected String queryString = null;
+
+
+ /**
+ * The current request dispatcher path.
+ */
+ protected Object requestDispatcherPath = null;
+
+
+ /**
+ * The request URI for this request.
+ */
+ protected String requestURI = null;
+
+
+ /**
+ * The servlet path for this request.
+ */
+ protected String servletPath = null;
+
+
+ /**
+ * The currently active session for this request.
+ */
+ protected HttpSession session = null;
+
+
+ /**
+ * Special attributes.
+ */
+ protected Object[] specialAttributes = new Object[specials.length];
+
+
+ // ------------------------------------------------- ServletRequest Methods
+
+
+ /**
+ * Override the <code>getAttribute()</code> method of the wrapped request.
+ *
+ * @param name Name of the attribute to retrieve
+ */
+ public Object getAttribute(String name) {
+
+ if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
+ return dispatcherType;
+ } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
+ if ( requestDispatcherPath != null ){
+ return requestDispatcherPath.toString();
+ } else {
+ return null;
+ }
+ }
+
+ int pos = getSpecial(name);
+ if (pos == -1) {
+ return getRequest().getAttribute(name);
+ } else {
+ if ((specialAttributes[pos] == null)
+ && (specialAttributes[5] == null) && (pos >= 5)) {
+ // If it's a forward special attribute, and null, it means this
+ // is an include, so we check the wrapped request since
+ // the request could have been forwarded before the include
+ return getRequest().getAttribute(name);
+ } else {
+ return specialAttributes[pos];
+ }
+ }
+
+ }
+
+
+ /**
+ * Override the <code>getAttributeNames()</code> method of the wrapped
+ * request.
+ */
+ public Enumeration getAttributeNames() {
+ return (new AttributeNamesEnumerator());
+ }
+
+
+ /**
+ * Override the <code>removeAttribute()</code> method of the
+ * wrapped request.
+ *
+ * @param name Name of the attribute to remove
+ */
+ public void removeAttribute(String name) {
+
+ if (!removeSpecial(name))
+ getRequest().removeAttribute(name);
+
+ }
+
+
+ /**
+ * Override the <code>setAttribute()</code> method of the
+ * wrapped request.
+ *
+ * @param name Name of the attribute to set
+ * @param value Value of the attribute to set
+ */
+ public void setAttribute(String name, Object value) {
+
+ if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
+ dispatcherType = value;
+ return;
+ } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
+ requestDispatcherPath = value;
+ return;
+ }
+
+ if (!setSpecial(name, value)) {
+ getRequest().setAttribute(name, value);
+ }
+
+ }
+
+
+ /**
+ * Return a RequestDispatcher that wraps the resource at the specified
+ * path, which may be interpreted as relative to the current request path.
+ *
+ * @param path Path of the resource to be wrapped
+ */
+ public RequestDispatcher getRequestDispatcher(String path) {
+
+ if (context == null)
+ return (null);
+
+ // If the path is already context-relative, just pass it through
+ if (path == null)
+ return (null);
+ else if (path.startsWith("/"))
+ return (context.getServletContext().getRequestDispatcher(path));
+
+ // Convert a request-relative path to a context-relative one
+ String servletPath =
+ (String) getAttribute(RequestDispatcherImpl.INCLUDE_SERVLET_PATH_ATTR);
+ if (servletPath == null)
+ servletPath = getServletPath();
+
+ // Add the path info, if there is any
+ String pathInfo = getPathInfo();
+ String requestPath = null;
+
+ if (pathInfo == null) {
+ requestPath = servletPath;
+ } else {
+ requestPath = servletPath + pathInfo;
+ }
+
+ int pos = requestPath.lastIndexOf('/');
+ String relative = null;
+ if (pos >= 0) {
+ relative = RequestUtil.normalize
+ (requestPath.substring(0, pos + 1) + path);
+ } else {
+ relative = RequestUtil.normalize(requestPath + path);
+ }
+
+ return (context.getServletContext().getRequestDispatcher(relative));
+
+ }
+
+
+ // --------------------------------------------- HttpServletRequest Methods
+
+
+ /**
+ * Override the <code>getContextPath()</code> method of the wrapped
+ * request.
+ */
+ public String getContextPath() {
+
+ return (this.contextPath);
+
+ }
+
+
+ /**
+ * Override the <code>getParameter()</code> method of the wrapped request.
+ *
+ * @param name Name of the requested parameter
+ */
+ public String getParameter(String name) {
+
+ parseParameters();
+
+ Object value = parameters.get(name);
+ if (value == null)
+ return (null);
+ else if (value instanceof String[])
+ return (((String[]) value)[0]);
+ else if (value instanceof String)
+ return ((String) value);
+ else
+ return (value.toString());
+
+ }
+
+
+ /**
+ * Override the <code>getParameterMap()</code> method of the
+ * wrapped request.
+ */
+ public Map getParameterMap() {
+
+ parseParameters();
+ return (parameters);
+
+ }
+
+
+ /**
+ * Override the <code>getParameterNames()</code> method of the
+ * wrapped request.
+ */
+ public Enumeration getParameterNames() {
+
+ parseParameters();
+ return (new Enumerator(parameters.keySet()));
+
+ }
+
+
+ /**
+ * Override the <code>getParameterValues()</code> method of the
+ * wrapped request.
+ *
+ * @param name Name of the requested parameter
+ */
+ public String[] getParameterValues(String name) {
+
+ parseParameters();
+ Object value = parameters.get(name);
+ if (value == null)
+ return ((String[]) null);
+ else if (value instanceof String[])
+ return ((String[]) value);
+ else if (value instanceof String) {
+ String values[] = new String[1];
+ values[0] = (String) value;
+ return (values);
+ } else {
+ String values[] = new String[1];
+ values[0] = value.toString();
+ return (values);
+ }
+
+ }
+
+
+ /**
+ * Override the <code>getPathInfo()</code> method of the wrapped request.
+ */
+ public String getPathInfo() {
+
+ return (this.pathInfo);
+
+ }
+
+
+ /**
+ * Override the <code>getQueryString()</code> method of the wrapped
+ * request.
+ */
+ public String getQueryString() {
+
+ return (this.queryString);
+
+ }
+
+
+ /**
+ * Override the <code>getRequestURI()</code> method of the wrapped
+ * request.
+ */
+ public String getRequestURI() {
+
+ return (this.requestURI);
+
+ }
+
+
+ /**
+ * Override the <code>getRequestURL()</code> method of the wrapped
+ * request.
+ */
+ public StringBuffer getRequestURL() {
+
+ StringBuffer url = new StringBuffer();
+ String scheme = getScheme();
+ int port = getServerPort();
+ if (port < 0)
+ port = 80; // Work around java.net.URL bug
+
+ url.append(scheme);
+ url.append("://");
+ url.append(getServerName());
+ if ((scheme.equals("http") && (port != 80))
+ || (scheme.equals("https") && (port != 443))) {
+ url.append(':');
+ url.append(port);
+ }
+ url.append(getRequestURI());
+
+ return (url);
+
+ }
+
+
+ /**
+ * Override the <code>getServletPath()</code> method of the wrapped
+ * request.
+ */
+ public String getServletPath() {
+
+ return (this.servletPath);
+
+ }
+
+
+ /**
+ * Return the session associated with this Request, creating one
+ * if necessary.
+ */
+ public HttpSession getSession() {
+ return (getSession(true));
+ }
+
+
+ /**
+ * Return the session associated with this Request, creating one
+ * if necessary and requested.
+ *
+ * @param create Create a new session if one does not exist
+ */
+ public HttpSession getSession(boolean create) {
+
+ if (crossContext) {
+
+ // There cannot be a session if no context has been assigned yet
+ if (context == null)
+ return (null);
+ UserSessionManager manager = context.getManager();
+ // Return the current session if it exists and is valid
+ if (session != null && manager.isValid(session)) {
+ return session;
+ }
+
+ HttpSession other = super.getSession(false);
+ if (create && (other == null)) {
+ // First create a session in the first context: the problem is
+ // that the top level request is the only one which can
+ // create the cookie safely
+ other = super.getSession(true);
+ }
+ if (other != null) {
+ HttpSession localSession = null;
+ try {
+ localSession =
+ manager.findSession(other.getId());
+ } catch (IOException e) {
+ // Ignore
+ }
+ if (localSession == null && create) {
+ localSession =
+ context.getManager().createSession(other.getId());
+ }
+ if (localSession != null) {
+ context.getManager().access(localSession);
+ session = localSession;
+ return session;
+ }
+ }
+ return null;
+
+ } else {
+ return super.getSession(create);
+ }
+
+ }
+
+
+ /**
+ * Returns true if the request specifies a JSESSIONID that is valid within
+ * the context of this ApplicationHttpRequest, false otherwise.
+ *
+ * @return true if the request specifies a JSESSIONID that is valid within
+ * the context of this ApplicationHttpRequest, false otherwise.
+ */
+ public boolean isRequestedSessionIdValid() {
+
+ if (crossContext) {
+
+ String requestedSessionId = getRequestedSessionId();
+ if (requestedSessionId == null)
+ return (false);
+ if (context == null)
+ return (false);
+ UserSessionManager manager = context.getManager();
+ if (manager == null)
+ return (false);
+ HttpSession session = null;
+ try {
+ session = manager.findSession(requestedSessionId);
+ } catch (IOException e) {
+ session = null;
+ }
+ if ((session != null) && manager.isValid(session)) {
+ return (true);
+ } else {
+ return (false);
+ }
+
+ } else {
+ return super.isRequestedSessionIdValid();
+ }
+ }
+
+
+ // -------------------------------------------------------- Package Methods
+
+
+ /**
+ * Recycle this request
+ */
+ public void recycle() {
+ if (session != null) {
+ context.getManager().endAccess(session);
+ }
+ }
+
+
+ /**
+ * Return descriptive information about this implementation.
+ */
+ public String getInfo() {
+
+ return (info);
+
+ }
+
+
+ /**
+ * Perform a shallow copy of the specified Map, and return the result.
+ *
+ * @param orig Origin Map to be copied
+ */
+ Map copyMap(Map orig) {
+
+ if (orig == null)
+ return (new HashMap());
+ HashMap dest = new HashMap();
+ Iterator keys = orig.keySet().iterator();
+ while (keys.hasNext()) {
+ String key = (String) keys.next();
+ dest.put(key, orig.get(key));
+ }
+ return (dest);
+
+ }
+
+
+ /**
+ * Set the context path for this request.
+ *
+ * @param contextPath The new context path
+ */
+ void setContextPath(String contextPath) {
+
+ this.contextPath = contextPath;
+
+ }
+
+
+ /**
+ * Set the path information for this request.
+ *
+ * @param pathInfo The new path info
+ */
+ void setPathInfo(String pathInfo) {
+
+ this.pathInfo = pathInfo;
+
+ }
+
+
+ /**
+ * Set the query string for this request.
+ *
+ * @param queryString The new query string
+ */
+ void setQueryString(String queryString) {
+
+ this.queryString = queryString;
+
+ }
+
+
+ /**
+ * Set the request that we are wrapping.
+ *
+ * @param request The new wrapped request
+ */
+ void setRequest(HttpServletRequest request) {
+
+ super.setRequest(request);
+
+ // Initialize the attributes for this request
+ dispatcherType = request.getAttribute(ServletRequestImpl.DISPATCHER_TYPE_ATTR);
+ requestDispatcherPath =
+ request.getAttribute(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR);
+
+ // Initialize the path elements for this request
+ contextPath = request.getContextPath();
+ pathInfo = request.getPathInfo();
+ queryString = request.getQueryString();
+ requestURI = request.getRequestURI();
+ servletPath = request.getServletPath();
+
+ }
+
+
+ /**
+ * Set the request URI for this request.
+ *
+ * @param requestURI The new request URI
+ */
+ void setRequestURI(String requestURI) {
+
+ this.requestURI = requestURI;
+
+ }
+
+
+ /**
+ * Set the servlet path for this request.
+ *
+ * @param servletPath The new servlet path
+ */
+ void setServletPath(String servletPath) {
+
+ this.servletPath = servletPath;
+
+ }
+
+
+ /**
+ * Parses the parameters of this request.
+ *
+ * If parameters are present in both the query string and the request
+ * content, they are merged.
+ */
+ void parseParameters() {
+
+ if (parsedParams) {
+ return;
+ }
+
+ parameters = new HashMap();
+ parameters = copyMap(getRequest().getParameterMap());
+ mergeParameters();
+ parsedParams = true;
+ }
+
+
+ /**
+ * Save query parameters for this request.
+ *
+ * @param queryString The query string containing parameters for this
+ * request
+ */
+ void setQueryParams(String queryString) {
+ this.queryParamString = queryString;
+ }
+
+
+ // ------------------------------------------------------ Protected Methods
+
+
+ /**
+ * Is this attribute name one of the special ones that is added only for
+ * included servlets?
+ *
+ * @param name Attribute name to be tested
+ */
+ protected boolean isSpecial(String name) {
+
+ for (int i = 0; i < specials.length; i++) {
+ if (specials[i].equals(name))
+ return (true);
+ }
+ return (false);
+
+ }
+
+
+ /**
+ * Get a special attribute.
+ *
+ * @return the special attribute pos, or -1 if it is not a special
+ * attribute
+ */
+ protected int getSpecial(String name) {
+ for (int i = 0; i < specials.length; i++) {
+ if (specials[i].equals(name)) {
+ return (i);
+ }
+ }
+ return (-1);
+ }
+
+
+ /**
+ * Set a special attribute.
+ *
+ * @return true if the attribute was a special attribute, false otherwise
+ */
+ protected boolean setSpecial(String name, Object value) {
+ for (int i = 0; i < specials.length; i++) {
+ if (specials[i].equals(name)) {
+ specialAttributes[i] = value;
+ return (true);
+ }
+ }
+ return (false);
+ }
+
+
+ /**
+ * Remove a special attribute.
+ *
+ * @return true if the attribute was a special attribute, false otherwise
+ */
+ protected boolean removeSpecial(String name) {
+ for (int i = 0; i < specials.length; i++) {
+ if (specials[i].equals(name)) {
+ specialAttributes[i] = null;
+ return (true);
+ }
+ }
+ return (false);
+ }
+
+
+ /**
+ * Merge the two sets of parameter values into a single String array.
+ *
+ * @param values1 First set of values
+ * @param values2 Second set of values
+ */
+ protected String[] mergeValues(Object values1, Object values2) {
+
+ ArrayList results = new ArrayList();
+
+ if (values1 == null)
+ ;
+ else if (values1 instanceof String)
+ results.add(values1);
+ else if (values1 instanceof String[]) {
+ String values[] = (String[]) values1;
+ for (int i = 0; i < values.length; i++)
+ results.add(values[i]);
+ } else
+ results.add(values1.toString());
+
+ if (values2 == null)
+ ;
+ else if (values2 instanceof String)
+ results.add(values2);
+ else if (values2 instanceof String[]) {
+ String values[] = (String[]) values2;
+ for (int i = 0; i < values.length; i++)
+ results.add(values[i]);
+ } else
+ results.add(values2.toString());
+
+ String values[] = new String[results.size()];
+ return ((String[]) results.toArray(values));
+
+ }
+
+
+ // ------------------------------------------------------ Private Methods
+
+
+ /**
+ * Merge the parameters from the saved query parameter string (if any), and
+ * the parameters already present on this request (if any), such that the
+ * parameter values from the query string show up first if there are
+ * duplicate parameter names.
+ */
+ private void mergeParameters() {
+
+ if ((queryParamString == null) || (queryParamString.length() < 1))
+ return;
+
+ HashMap queryParameters = new HashMap();
+ String encoding = getCharacterEncoding();
+ if (encoding == null)
+ encoding = "ISO-8859-1";
+ try {
+ RequestUtil.parseParameters
+ (queryParameters, queryParamString, encoding);
+ } catch (Exception e) {
+ ;
+ }
+ Iterator keys = parameters.keySet().iterator();
+ while (keys.hasNext()) {
+ String key = (String) keys.next();
+ Object value = queryParameters.get(key);
+ if (value == null) {
+ queryParameters.put(key, parameters.get(key));
+ continue;
+ }
+ queryParameters.put
+ (key, mergeValues(value, parameters.get(key)));
+ }
+ parameters = queryParameters;
+
+ }
+
+
+ // ----------------------------------- AttributeNamesEnumerator Inner Class
+
+
+ /**
+ * Utility class used to expose the special attributes as being available
+ * as request attributes.
+ */
+ protected class AttributeNamesEnumerator implements Enumeration {
+
+ protected int pos = -1;
+ protected int last = -1;
+ protected Enumeration parentEnumeration = null;
+ protected String next = null;
+
+ public AttributeNamesEnumerator() {
+ parentEnumeration = getRequest().getAttributeNames();
+ for (int i = 0; i < specialAttributes.length; i++) {
+ if (getAttribute(specials[i]) != null) {
+ last = i;
+ }
+ }
+ }
+
+ public boolean hasMoreElements() {
+ return ((pos != last) || (next != null)
+ || ((next = findNext()) != null));
+ }
+
+ public Object nextElement() {
+ if (pos != last) {
+ for (int i = pos + 1; i <= last; i++) {
+ if (getAttribute(specials[i]) != null) {
+ pos = i;
+ return (specials[i]);
+ }
+ }
+ }
+ String result = next;
+ if (next != null) {
+ next = findNext();
+ } else {
+ throw new NoSuchElementException();
+ }
+ return result;
+ }
+
+ protected String findNext() {
+ String result = null;
+ while ((result == null) && (parentEnumeration.hasMoreElements())) {
+ String current = (String) parentEnumeration.nextElement();
+ if (!isSpecial(current)) {
+ result = current;
+ }
+ }
+ return result;
+ }
+
+ }
+
+
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.coyote.servlet;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+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;
+
+/**
+ * Wrapper object for the Coyote response.
+ *
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ * @version $Revision$ $Date$
+ */
+
+public class ServletResponseImpl
+ implements HttpServletResponse {
+
+ /**
+ * Format for http response header date field
+ * From DateTool
+ */
+ public static final String HTTP_RESPONSE_DATE_HEADER =
+ "EEE, dd MMM yyyy HH:mm:ss zzz";
+
+ // ----------------------------------------------------------- Constructors
+
+
+ ServletResponseImpl() {
+ urlEncoder.addSafeCharacter('/');
+ }
+
+
+ /**
+ * The date format we will use for creating date headers.
+ */
+ protected SimpleDateFormat format = null;
+
+
+ /**
+ * The associated output buffer.
+ */
+ protected BodyWriter outputBuffer;
+
+
+ /**
+ * The associated output stream.
+ */
+ protected ServletOutputStreamImpl outputStream;
+
+
+ /**
+ * The associated writer.
+ */
+ protected PrintWriter writer;
+
+
+ /**
+ * The application commit flag.
+ */
+ protected boolean appCommitted = false;
+
+
+ /**
+ * The included flag.
+ */
+ protected boolean included = false;
+
+
+ /**
+ * The characterEncoding flag
+ */
+ private boolean isCharacterEncodingSet = false;
+
+ /**
+ * The error flag.
+ */
+ protected boolean error = false;
+
+
+ /**
+ * The set of Cookies associated with this Response.
+ */
+ protected ArrayList cookies = new ArrayList();
+
+
+ /**
+ * Using output stream flag.
+ */
+ protected boolean usingOutputStream = false;
+
+
+ /**
+ * Using writer flag.
+ */
+ protected boolean usingWriter = false;
+
+
+ /**
+ * The request with which this response is associated.
+ */
+ protected ServletRequestImpl req = null;
+
+ /**
+ * URL encoder.
+ */
+ protected UEncoder urlEncoder = new UEncoder();
+
+
+ /**
+ * Recyclable buffer to hold the redirect URL.
+ */
+ 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
+
+
+ /**
+ * Release all object references, and initialize instance variables, in
+ * preparation for reuse of this object.
+ */
+ public void recycle() {
+
+ usingOutputStream = false;
+ usingWriter = false;
+ appCommitted = false;
+ commited = false;
+ included = false;
+ error = false;
+ isCharacterEncodingSet = false;
+
+ cookies.clear();
+
+ outputBuffer.recycle();
+
+ resB.recycle();
+ }
+
+
+ // ------------------------------------------------------- Response Methods
+
+
+ /**
+ * Return the number of bytes actually written to the output stream.
+ */
+ public int getContentCount() {
+ return outputBuffer.getBytesWritten() + outputBuffer.getCharsWritten();
+ }
+
+
+ /**
+ * Set the application commit flag.
+ *
+ * @param appCommitted The new application committed flag value
+ */
+ public void setAppCommitted(boolean appCommitted) {
+ this.appCommitted = appCommitted;
+ }
+
+
+ /**
+ * Application commit flag accessor.
+ */
+ public boolean isAppCommitted() {
+ return (this.appCommitted || isCommitted() || isSuspended()
+ || ((getHttpResponse().getContentLength() > 0)
+ && (getContentCount() >= getHttpResponse().getContentLength())));
+ }
+
+
+ /**
+ * Return the "processing inside an include" flag.
+ */
+ public boolean getIncluded() {
+ return included;
+ }
+
+
+ /**
+ * Set the "processing inside an include" flag.
+ *
+ * @param included <code>true</code> if we are currently inside a
+ * RequestDispatcher.include(), else <code>false</code>
+ */
+ public void setIncluded(boolean included) {
+ this.included = included;
+ }
+
+
+ /**
+ * Return the Request with which this Response is associated.
+ */
+ public ServletRequestImpl getRequest() {
+ return (this.req);
+ }
+
+ /**
+ * Set the Request with which this Response is associated.
+ *
+ * @param request The new associated request
+ */
+ public void setRequest(ServletRequestImpl request) {
+ this.req = (ServletRequestImpl) request;
+ }
+
+
+ /**
+ * Return the output stream associated with this Response.
+ */
+ public OutputStream getStream() {
+ return outputStream;
+ }
+
+
+ /**
+ * Set the output stream associated with this Response.
+ *
+ * @param stream The new output stream
+ */
+ public void setStream(OutputStream stream) {
+ // This method is evil
+ }
+
+
+ /**
+ * Set the suspended flag.
+ *
+ * @param suspended The new suspended flag value
+ */
+ public void setSuspended(boolean suspended) throws IOException {
+ //coyoteResponse.setCommitted(true);
+ flushBuffer();
+ outputBuffer.setSuspended(suspended);
+ }
+
+
+ /**
+ * Suspended flag accessor.
+ */
+ public boolean isSuspended() {
+ return outputBuffer.isSuspended();
+ }
+
+
+ /**
+ * Set the error flag.
+ */
+ public void setError() {
+ error = true;
+ }
+
+
+ /**
+ * Error flag accessor.
+ */
+ public boolean isError() {
+ return error;
+ }
+
+
+ /**
+ * Create and return a ServletOutputStream to write the content
+ * associated with this Response.
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ public ServletOutputStream createOutputStream()
+ throws IOException {
+ // Probably useless
+ return outputStream;
+ }
+
+ /**
+ * Return the content type that was set or calculated for this response,
+ * or <code>null</code> if no content type was set.
+ */
+ public String getContentType() {
+ String ret = contentType;
+
+ if (ret != null
+ && characterEncoding != null
+ && charsetSet) {
+ ret = ret + ";charset=" + characterEncoding;
+ }
+
+ return ret;
+ }
+
+
+ /**
+ * Return a PrintWriter that can be used to render error messages,
+ * regardless of whether a stream or writer has already been acquired.
+ *
+ * @return Writer which can be used for error reports. If the response is
+ * not an error report returned using sendError or triggered by an
+ * unexpected exception thrown during the servlet processing
+ * (and only in that case), null will be returned if the response stream
+ * has already been used.
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ public PrintWriter getReporter() throws IOException {
+ if (outputBuffer.isNew()) {
+ outputBuffer.checkConverter();
+ if (writer == null) {
+ writer = new ServletWriterImpl(outputBuffer);
+ }
+ return writer;
+ } else {
+ return null;
+ }
+ }
+
+
+ // ------------------------------------------------ ServletResponse Methods
+
+
+ /**
+ * Flush the buffer and commit this response.
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ public void flushBuffer()
+ throws IOException {
+ outputBuffer.flush();
+ }
+
+
+ /**
+ * Return the actual buffer size used for this Response.
+ */
+ public int getBufferSize() {
+ return outputBuffer.getBufferSize();
+ }
+
+
+ /**
+ * Return the character encoding used for this Response.
+ */
+ public String getCharacterEncoding() {
+ return characterEncoding;
+ }
+
+
+ /**
+ * Return the servlet output stream associated with this Response.
+ *
+ * @exception IllegalStateException if <code>getWriter</code> has
+ * already been called for this response
+ * @exception IOException if an input/output error occurs
+ */
+ public ServletOutputStream getOutputStream()
+ throws IOException {
+
+ if (usingWriter)
+ throw new IllegalStateException
+ ("usingWriter");
+
+ usingOutputStream = true;
+ return outputStream;
+
+ }
+
+ public BodyWriter getBodyWriter() {
+ return outputBuffer;
+ }
+
+ /**
+ * Return the Locale assigned to this response.
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+
+ /**
+ * Return the writer associated with this Response.
+ *
+ * @exception IllegalStateException if <code>getOutputStream</code> has
+ * already been called for this response
+ * @exception IOException if an input/output error occurs
+ */
+ public PrintWriter getWriter()
+ throws IOException {
+
+ if (usingOutputStream)
+ throw new IllegalStateException
+ ("usingOutputStream");
+
+ /*
+ * If the response's character encoding has not been specified as
+ * described in <code>getCharacterEncoding</code> (i.e., the method
+ * just returns the default value <code>ISO-8859-1</code>),
+ * <code>getWriter</code> updates it to <code>ISO-8859-1</code>
+ * (with the effect that a subsequent call to getContentType() will
+ * include a charset=ISO-8859-1 component which will also be
+ * reflected in the Content-Type response header, thereby satisfying
+ * the Servlet spec requirement that containers must communicate the
+ * character encoding used for the servlet response's writer to the
+ * client).
+ */
+ setCharacterEncoding(getCharacterEncoding());
+
+ usingWriter = true;
+ outputBuffer.checkConverter();
+ if (writer == null) {
+ writer = new ServletWriterImpl(outputBuffer);
+ }
+ return writer;
+
+ }
+
+
+ /**
+ * Has the output of this response already been committed?
+ */
+ public boolean isCommitted() {
+ return getHttpResponse().isCommitted();
+ }
+
+ /**
+ * Clear any content written to the buffer.
+ *
+ * @exception IllegalStateException if this response has already
+ * been committed
+ */
+ public void reset() {
+
+ if (included)
+ return; // Ignore any call from an included servlet
+
+ 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();
+ }
+
+
+ /**
+ * Reset the data buffer but not any status or header information.
+ *
+ * @exception IllegalStateException if the response has already
+ * been committed
+ */
+ public void resetBuffer() {
+
+ if (isCommitted())
+ throw new IllegalStateException("isCommitted");
+
+ outputBuffer.reset();
+
+ }
+
+
+ /**
+ * Set the buffer size to be used for this Response.
+ *
+ * @param size The new buffer size
+ *
+ * @exception IllegalStateException if this method is called after
+ * output has been committed for this response
+ */
+ public void setBufferSize(int size) {
+
+ if (isCommitted() || !outputBuffer.isNew())
+ throw new IllegalStateException
+ ("isCommitted || !isNew");
+
+ outputBuffer.setBufferSize(size);
+
+ }
+
+
+ /**
+ * Set the content length (in bytes) for this Response.
+ * Ignored for writers if non-ISO-8859-1 encoding ( we could add more
+ * encodings that are constant.
+ */
+ public void setContentLength(int length) {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ // writers can use variable-length encoding.
+ if (usingWriter && !"ISO-8859-1".equals(getCharacterEncoding())) {
+ return;
+ }
+ getHttpResponse().setContentLength(length);
+
+ }
+
+
+ /**
+ * Set the content type for this Response.
+ *
+ * @param type The new content type
+ */
+ public void setContentType(String type) {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ // Ignore charset if getWriter() has already been called
+ if (usingWriter) {
+ if (type != null) {
+ int index = type.indexOf(";");
+ if (index != -1) {
+ type = type.substring(0, index);
+ }
+ }
+ }
+
+ getHttpResponse().setContentType(type);
+
+ // Check to see if content type contains charset
+ if (type != null) {
+ int index = type.indexOf(";");
+ if (index != -1) {
+ int len = type.length();
+ index++;
+ while (index < len && Character.isSpace(type.charAt(index))) {
+ index++;
+ }
+ if (index+7 < len
+ && type.charAt(index) == 'c'
+ && type.charAt(index+1) == 'h'
+ && type.charAt(index+2) == 'a'
+ && type.charAt(index+3) == 'r'
+ && type.charAt(index+4) == 's'
+ && type.charAt(index+5) == 'e'
+ && type.charAt(index+6) == 't'
+ && type.charAt(index+7) == '=') {
+ isCharacterEncodingSet = true;
+ }
+ }
+ }
+ }
+
+
+ /*
+ * Overrides the name of the character encoding used in the body
+ * of the request. This method must be called prior to reading
+ * request parameters or reading input using getReader().
+ *
+ * @param charset String containing the name of the chararacter encoding.
+ */
+ public void setCharacterEncoding(String charset) {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ // Ignore any call made after the getWriter has been invoked
+ // The default should be used
+ if (usingWriter)
+ return;
+
+ if (isCommitted())
+ return;
+ if (charset == null)
+ return;
+
+ characterEncoding = charset;
+ charsetSet=true;
+ isCharacterEncodingSet = true;
+ }
+
+
+
+ /**
+ * Set the Locale that is appropriate for this response, including
+ * setting the appropriate character encoding.
+ *
+ * @param locale The new locale
+ */
+ public void setLocale(Locale locale) {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ 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
+ if (usingWriter)
+ return;
+
+ if (isCharacterEncodingSet) {
+ return;
+ }
+
+ Locale2Charset cm = req.getContext().getCharsetMapper();
+ String charset = cm.getCharset( locale );
+ if ( charset != null ){
+ setCharacterEncoding(charset);
+ }
+
+ }
+
+
+ // --------------------------------------------------- HttpResponse Methods
+
+
+ /**
+ * Return an array of all cookies set for this response, or
+ * a zero-length array if no cookies have been set.
+ */
+ public Cookie[] getCookies() {
+ return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));
+ }
+
+
+ /**
+ * Return the value for the specified header, or <code>null</code> if this
+ * header has not been set. If more than one value was added for this
+ * name, only the first is returned; use getHeaderValues() to retrieve all
+ * of them.
+ *
+ * @param name Header name to look up
+ */
+ public String getHeader(String name) {
+ return getHttpResponse().getMimeHeaders().getHeader(name);
+ }
+
+
+ /**
+ * Return an array of all the header names set for this response, or
+ * a zero-length array if no headers have been set.
+ */
+ public Collection<String> getHeaderNames() {
+
+ MimeHeaders headers = getHttpResponse().getMimeHeaders();
+ int n = headers.size();
+ ArrayList<String> result = new ArrayList<String>();
+ for (int i = 0; i < n; i++) {
+ result.add(headers.getName(i).toString());
+ }
+ return result;
+ }
+
+
+ /**
+ * Return an array of all the header values associated with the
+ * specified header name, or an zero-length array if there are no such
+ * header values.
+ *
+ * @param name Header name to look up
+ */
+ public String[] getHeaderValues(String name) {
+
+ Enumeration enumeration = getHttpResponse().getMimeHeaders().values(name);
+ Vector result = new Vector();
+ while (enumeration.hasMoreElements()) {
+ result.addElement(enumeration.nextElement());
+ }
+ String[] resultArray = new String[result.size()];
+ result.copyInto(resultArray);
+ return resultArray;
+
+ }
+
+
+ /**
+ * Return the error message that was set with <code>sendError()</code>
+ * for this Response.
+ */
+ public String getMessage() {
+ return getHttpResponse().getMessage();
+ }
+
+
+ /**
+ * Return the HTTP status code associated with this Response.
+ */
+ public int getStatus() {
+ return getHttpResponse().getStatus();
+ }
+
+
+ /**
+ * Reset this response, and specify the values for the HTTP status code
+ * and corresponding message.
+ *
+ * @exception IllegalStateException if this response has already been
+ * committed
+ */
+ public void reset(int status, String message) {
+ reset();
+ setStatus(status, message);
+ }
+
+
+ // -------------------------------------------- HttpServletResponse Methods
+
+
+ /**
+ * Add the specified Cookie to those that will be included with
+ * this Response.
+ *
+ * @param cookie Cookie to be added
+ */
+ public void addCookie(final Cookie cookie) {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ cookies.add(cookie);
+
+ final StringBuffer sb = new StringBuffer();
+ ServerCookie.appendCookieValue
+ (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
+ cookie.getPath(), cookie.getDomain(), cookie.getComment(),
+ cookie.getMaxAge(), cookie.getSecure(), false);
+
+ // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 )
+ // RFC2965 is not supported by browsers and the Servlet spec
+ // asks for 2109.
+ addHeader("Set-Cookie", sb.toString());
+
+ }
+
+
+ /**
+ * Add the specified date header to the specified value.
+ *
+ * @param name Name of the header to set
+ * @param value Date value to be set
+ */
+ public void addDateHeader(String name, long value) {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included) {
+ return;
+ }
+
+ if (format == null) {
+ format = new SimpleDateFormat(HTTP_RESPONSE_DATE_HEADER,
+ Locale.US);
+ format.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
+
+ addHeader(name, FastHttpDateFormat.formatDate(value, format));
+
+ }
+
+
+ /**
+ * Add the specified header to the specified value.
+ *
+ * @param name Name of the header to set
+ * @param value Value to be set
+ */
+ public void addHeader(String name, String value) {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ getHttpResponse().addHeader(name, value);
+
+ }
+
+
+ /**
+ * Add the specified integer header to the specified value.
+ *
+ * @param name Name of the header to set
+ * @param value Integer value to be set
+ */
+ public void addIntHeader(String name, int value) {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ addHeader(name, "" + value);
+
+ }
+
+
+ /**
+ * Has the specified header been set already in this response?
+ *
+ * @param name Name of the header to check
+ */
+ public boolean containsHeader(String name) {
+ // Need special handling for Content-Type and Content-Length due to
+ // special handling of these in coyoteResponse
+ char cc=name.charAt(0);
+ if(cc=='C' || cc=='c') {
+ if(name.equalsIgnoreCase("Content-Type")) {
+ // Will return null if this has not been set
+ return getContentType() != null;
+ }
+ if(name.equalsIgnoreCase("Content-Length")) {
+ // -1 means not known and is not sent to client
+ return (getHttpResponse().getContentLength() != -1);
+ }
+ }
+
+ return getHttpResponse().containsHeader(name);
+ }
+
+
+ /**
+ * Encode the session identifier associated with this response
+ * into the specified redirect URL, if necessary.
+ *
+ * @param url URL to be encoded
+ */
+ public String encodeRedirectURL(String url) {
+
+ if (isEncodeable(toAbsolute(url))) {
+ return (toEncoded(url, req.getSession().getId()));
+ } else {
+ return (url);
+ }
+
+ }
+
+
+ /**
+ * Encode the session identifier associated with this response
+ * into the specified redirect URL, if necessary.
+ *
+ * @param url URL to be encoded
+ *
+ * @deprecated As of Version 2.1 of the Java Servlet API, use
+ * <code>encodeRedirectURL()</code> instead.
+ */
+ public String encodeRedirectUrl(String url) {
+ return (encodeRedirectURL(url));
+ }
+
+
+ /**
+ * Encode the session identifier associated with this response
+ * into the specified URL, if necessary.
+ *
+ * @param url URL to be encoded
+ */
+ public String encodeURL(String url) {
+
+ String absolute = toAbsolute(url);
+ if (isEncodeable(absolute)) {
+ // W3c spec clearly said
+ if (url.equalsIgnoreCase("")){
+ url = absolute;
+ }
+ return (toEncoded(url, req.getSession().getId()));
+ } else {
+ return (url);
+ }
+
+ }
+
+
+ /**
+ * Encode the session identifier associated with this response
+ * into the specified URL, if necessary.
+ *
+ * @param url URL to be encoded
+ *
+ * @deprecated As of Version 2.1 of the Java Servlet API, use
+ * <code>encodeURL()</code> instead.
+ */
+ public String encodeUrl(String url) {
+ return (encodeURL(url));
+ }
+
+
+ /**
+ * Send an acknowledgment of a request.
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ public void sendAcknowledgement()
+ throws IOException {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ req.getConnector().acknowledge(this);
+ }
+
+
+ /**
+ * Send an error response with the specified status and a
+ * default message.
+ *
+ * @param status HTTP status code to send
+ *
+ * @exception IllegalStateException if this response has
+ * already been committed
+ * @exception IOException if an input/output error occurs
+ */
+ public void sendError(int status)
+ throws IOException {
+ sendError(status, null);
+ }
+
+
+ /**
+ * Send an error response with the specified status and message.
+ *
+ * @param status HTTP status code to send
+ * @param message Corresponding message to send
+ *
+ * @exception IllegalStateException if this response has
+ * already been committed
+ * @exception IOException if an input/output error occurs
+ */
+ public void sendError(int status, String message)
+ throws IOException {
+
+ if (isCommitted())
+ throw new IllegalStateException
+ ("isCommitted");
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ setError();
+
+ getHttpResponse().setStatus(status);
+ getHttpResponse().setMessage(message);
+
+ // Clear any data content that has been buffered
+ resetBuffer();
+
+ // Cause the response to be finished (from the application perspective)
+ String statusPage = req.getContext().findStatusPage(status);
+
+ if (statusPage != null) {
+ req.getContext().handleStatusPage(req, this, status, statusPage);
+ } else {
+ // Send a default message body.
+ // TODO: maybe other mechanism to customize default.
+ defaultStatusPage(status, message);
+ }
+ setSuspended(true);
+ }
+
+ /**
+ * Default handler for status code != 200
+ */
+ void defaultStatusPage(int status, String message)
+ throws IOException {
+ setContentType("text/html");
+ if (status > 400 && status < 600) {
+ if (getOutputBuffer().getBytesWritten() == 0) {
+ getOutputBuffer().write("<html><body><h1>Status: " +
+ status + "</h1><h1>Message: " + message +
+ "</h1></body></html>");
+ getOutputBuffer().flush();
+ }
+ }
+ }
+
+
+
+ /**
+ * Send a temporary redirect to the specified redirect location URL.
+ *
+ * @param location Location URL to redirect to
+ *
+ * @exception IllegalStateException if this response has
+ * already been committed
+ * @exception IOException if an input/output error occurs
+ */
+ public void sendRedirect(String location)
+ throws IOException {
+
+ if (isCommitted())
+ throw new IllegalStateException
+ ("isCommitted");
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ // Clear any data content that has been buffered
+ resetBuffer();
+
+ // Generate a temporary redirect to the specified location
+ try {
+ String absolute = toAbsolute(location);
+ setStatus(SC_FOUND);
+ setHeader("Location", absolute);
+ } catch (IllegalArgumentException e) {
+ setStatus(SC_NOT_FOUND);
+ }
+
+ // Cause the response to be finished (from the application perspective)
+ setSuspended(true);
+
+ }
+
+
+ /**
+ * Set the specified date header to the specified value.
+ *
+ * @param name Name of the header to set
+ * @param value Date value to be set
+ */
+ public void setDateHeader(String name, long value) {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included) {
+ return;
+ }
+
+ if (format == null) {
+ format = new SimpleDateFormat(HTTP_RESPONSE_DATE_HEADER,
+ Locale.US);
+ format.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
+
+ setHeader(name, FastHttpDateFormat.formatDate(value, format));
+
+ }
+
+
+ /**
+ * Set the specified header to the specified value.
+ *
+ * @param name Name of the header to set
+ * @param value Value to be set
+ */
+ public void setHeader(String name, String value) {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ getHttpResponse().setHeader(name, value);
+
+ }
+
+
+ /**
+ * Set the specified integer header to the specified value.
+ *
+ * @param name Name of the header to set
+ * @param value Integer value to be set
+ */
+ public void setIntHeader(String name, int value) {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ setHeader(name, "" + value);
+
+ }
+
+
+ /**
+ * Set the HTTP status to be returned with this response.
+ *
+ * @param status The new HTTP status
+ */
+ public void setStatus(int status) {
+ setStatus(status, null);
+ }
+
+
+ /**
+ * Set the HTTP status and message to be returned with this response.
+ *
+ * @param status The new HTTP status
+ * @param message The associated text message
+ *
+ * @deprecated As of Version 2.1 of the Java Servlet API, this method
+ * has been deprecated due to the ambiguous meaning of the message
+ * parameter.
+ */
+ public void setStatus(int status, String message) {
+
+ if (isCommitted())
+ return;
+
+ // Ignore any call from an included servlet
+ if (included)
+ return;
+
+ getHttpResponse().setStatus(status);
+ getHttpResponse().setMessage(message);
+
+ }
+
+
+ // ------------------------------------------------------ Protected Methods
+
+
+ /**
+ * Return <code>true</code> if the specified URL should be encoded with
+ * a session identifier. This will be true if all of the following
+ * conditions are met:
+ * <ul>
+ * <li>The request we are responding to asked for a valid session
+ * <li>The requested session ID was not received via a cookie
+ * <li>The specified URL points back to somewhere within the web
+ * application that is responding to this request
+ * </ul>
+ *
+ * @param location Absolute URL to be validated
+ */
+ protected boolean isEncodeable(final String location) {
+
+ if (location == null)
+ return (false);
+
+ // Is this an intra-document reference?
+ if (location.startsWith("#"))
+ return (false);
+
+ // Are we in a valid session that is not using cookies?
+ final ServletRequestImpl hreq = req;
+ final HttpSession session = hreq.getSession(false);
+ if (session == null)
+ return (false);
+ if (hreq.isRequestedSessionIdFromCookie())
+ return (false);
+
+ // Is this a valid absolute URL?
+ URL url = null;
+ try {
+ url = new URL(location);
+ } catch (MalformedURLException e) {
+ return (false);
+ }
+
+ // Does this URL match down to (and including) the context path?
+ if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol()))
+ return (false);
+ if (!hreq.getServerName().equalsIgnoreCase(url.getHost()))
+ return (false);
+ int serverPort = hreq.getServerPort();
+ if (serverPort == -1) {
+ if ("https".equals(hreq.getScheme()))
+ serverPort = 443;
+ else
+ serverPort = 80;
+ }
+ int urlPort = url.getPort();
+ if (urlPort == -1) {
+ if ("https".equals(url.getProtocol()))
+ urlPort = 443;
+ else
+ urlPort = 80;
+ }
+ if (serverPort != urlPort)
+ return (false);
+
+ String contextPath = req.getContext().getContextPath();
+ if (contextPath != null) {
+ String file = url.getFile();
+ if ((file == null) || !file.startsWith(contextPath))
+ return (false);
+ if( file.indexOf(";jsessionid=" + session.getId()) >= 0 )
+ return (false);
+ }
+
+ // This URL belongs to our web application, so it is encodeable
+ return (true);
+
+ }
+
+
+ /**
+ * Convert (if necessary) and return the absolute URL that represents the
+ * resource referenced by this possibly relative URL. If this URL is
+ * already absolute, return it unchanged.
+ *
+ * @param location URL to be (possibly) converted and then returned
+ *
+ * @exception IllegalArgumentException if a MalformedURLException is
+ * thrown when converting the relative URL to an absolute one
+ */
+ private String toAbsolute(String location) {
+
+ if (location == null)
+ return (location);
+
+ boolean leadingSlash = location.startsWith("/");
+
+ if (leadingSlash || !hasScheme(location)) {
+
+ redirectURLCC.recycle();
+
+ String scheme = req.getScheme();
+ String name = req.getServerName();
+ int port = req.getServerPort();
+
+ try {
+ redirectURLCC.append(scheme, 0, scheme.length());
+ redirectURLCC.append("://", 0, 3);
+ redirectURLCC.append(name, 0, name.length());
+ if ((scheme.equals("http") && port != 80)
+ || (scheme.equals("https") && port != 443)) {
+ redirectURLCC.append(':');
+ String portS = port + "";
+ redirectURLCC.append(portS, 0, portS.length());
+ }
+ if (!leadingSlash) {
+ String relativePath = req.getDecodedRequestURI();
+ int pos = relativePath.lastIndexOf('/');
+ relativePath = relativePath.substring(0, pos);
+
+ String encodedURI = null;
+ encodedURI = urlEncoder.encodeURL(relativePath);
+ redirectURLCC.append(encodedURI, 0, encodedURI.length());
+ redirectURLCC.append('/');
+ }
+ redirectURLCC.append(location, 0, location.length());
+ } catch (IOException e) {
+ IllegalArgumentException iae =
+ new IllegalArgumentException(location);
+ iae.initCause(e);
+ throw iae;
+ }
+
+ return redirectURLCC.toString();
+
+ } else {
+
+ return (location);
+
+ }
+
+ }
+
+
+ /**
+ * Determine if a URI string has a <code>scheme</code> component.
+ */
+ private boolean hasScheme(String uri) {
+ int len = uri.length();
+ for(int i=0; i < len ; i++) {
+ char c = uri.charAt(i);
+ if(c == ':') {
+ return i > 0;
+ } else if(!isSchemeChar(c)) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the character is allowed in the scheme of a URI.
+ * See RFC 2396, Section 3.1
+ */
+ private static boolean isSchemeChar(char c) {
+ return Character.isLetterOrDigit(c) ||
+ c == '+' || c == '-' || c == '.';
+ }
+
+
+ /**
+ * Return the specified URL with the specified session identifier
+ * suitably encoded.
+ *
+ * @param url URL to be encoded with the session id
+ * @param sessionId Session id to be included in the encoded URL
+ */
+ protected String toEncoded(String url, String sessionId) {
+
+ if ((url == null) || (sessionId == null))
+ return (url);
+
+ String path = url;
+ String query = "";
+ String anchor = "";
+ int question = url.indexOf('?');
+ if (question >= 0) {
+ path = url.substring(0, question);
+ query = url.substring(question);
+ }
+ int pound = path.indexOf('#');
+ if (pound >= 0) {
+ anchor = path.substring(pound);
+ path = path.substring(0, pound);
+ }
+ StringBuffer sb = new StringBuffer(path);
+ if( sb.length() > 0 ) { // jsessionid can't be first.
+ sb.append(";jsessionid=");
+ sb.append(sessionId);
+ }
+ sb.append(anchor);
+ sb.append(query);
+ return (sb.toString());
+
+ }
+
+
+ public int getBytesWritten() {
+ return outputBuffer.getBytesWritten();
+ }
+
+ public BodyWriter getOutputBuffer() {
+ return outputBuffer;
+ }
+
+ public void setWriter(BodyWriter ob) {
+ outputBuffer = ob;
+ outputStream = new ServletOutputStreamImpl(outputBuffer);
+ }
+
+ public CharSequence getResponseHeader(String name) {
+ MessageBytes v = getHttpResponse().getMimeHeaders().getValue(name);
+ return (v == null) ? null : v.toString();
+ }
+
+
+ public HttpResponse getHttpResponse() {
+ return resB;
+ }
+
+
+ public void setHttpResponse(HttpResponse resB, BodyWriter ob) {
+ this.resB = resB;
+ setWriter(ob);
+ }
+
+
+
+ @Override
+ public Collection<String> getHeaders(String name) {
+ return null;
+ }
+
+
+}
+
--- /dev/null
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.coyote.servlet;
+
+
+import java.io.IOException;
+import java.util.Locale;
+
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+
+/**
+ * Wrapper around the response object received as parameter to
+ * RequestDispatcher.include().
+ *
+ * @author Costin Manolache
+ */
+public class ServletResponseIncludeWrapper extends HttpServletResponseWrapper {
+ public ServletResponseIncludeWrapper(ServletResponse current) {
+ super((HttpServletResponse) current);
+ }
+
+ // Not overriden:
+ /*
+ public boolean containsHeader(String name)
+ public String encodeRedirectUrl(String url)
+ public String encodeRedirectURL(String url)
+ public String encodeUrl(String url)
+ public String encodeURL(String url)
+ public void flushBuffer() throws IOException
+ public int getBufferSize()
+ public String getCharacterEncoding()
+ public String getContentType()
+ public Locale getLocale()
+ public ServletOutputStream getOutputStream() throws IOException
+ public ServletResponse getResponse()
+ public PrintWriter getWriter() throws IOException
+ public boolean isCommitted()
+ public void resetBuffer()
+ public void setCharacterEncoding(String charset)
+ public void setResponse(ServletResponse response)
+ */
+
+ public void reset() {
+ if (getResponse().isCommitted())
+ getResponse().reset();
+ else
+ throw new IllegalStateException();
+ }
+
+ public void setContentLength(int len) {
+ }
+
+ public void setContentType(String type) {
+ }
+
+ public void setLocale(Locale loc) {
+ }
+
+ public void setBufferSize(int size) {
+ }
+
+ public void addCookie(Cookie cookie) {
+ }
+
+ public void addDateHeader(String name, long value) {
+ }
+
+ public void addHeader(String name, String value) {
+ }
+
+ public void addIntHeader(String name, int value) {
+ }
+
+ public void sendError(int sc) throws IOException {
+ }
+
+ public void sendError(int sc, String msg) throws IOException {
+ }
+
+ public void sendRedirect(String location) throws IOException {
+ }
+
+ public void setDateHeader(String name, long value) {
+ }
+
+ public void setHeader(String name, String value) {
+ }
+
+ public void setIntHeader(String name, int value) {
+ }
+
+ public void setStatus(int sc) {
+ }
+
+ public void setStatus(int sc, String msg) {
+ }
+}
--- /dev/null
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.coyote.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * Coyote implementation of the servlet writer.
+ *
+ * @author Remy Maucherat
+ */
+public class ServletWriterImpl
+ extends PrintWriter {
+
+
+ // -------------------------------------------------------------- Constants
+
+
+ private static final char[] LINE_SEP = { '\r', '\n' };
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ protected Writer ob;
+ protected boolean error = false;
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ public ServletWriterImpl(Writer ob) {
+ super(ob);
+ this.ob = ob;
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Prevent cloning the facade.
+ */
+ protected Object clone()
+ throws CloneNotSupportedException {
+ throw new CloneNotSupportedException();
+ }
+
+
+ // -------------------------------------------------------- Package Methods
+
+
+ /**
+ * Clear facade.
+ */
+ void clear() {
+ ob = null;
+ }
+
+
+ /**
+ * Recycle.
+ */
+ void recycle() {
+ error = false;
+ }
+
+
+ // --------------------------------------------------------- Writer Methods
+
+
+ public void flush() {
+
+ if (error)
+ return;
+
+ try {
+ ob.flush();
+ } catch (IOException e) {
+ error = true;
+ }
+
+ }
+
+
+ public void close() {
+
+ // We don't close the PrintWriter - super() is not called,
+ // so the stream can be reused. We close ob.
+ try {
+ ob.close();
+ } catch (IOException ex ) {
+ ;
+ }
+ error = false;
+
+ }
+
+
+ public boolean checkError() {
+ flush();
+ return error;
+ }
+
+
+ public void write(int c) {
+
+ if (error)
+ return;
+
+ try {
+ ob.write(c);
+ } catch (IOException e) {
+ error = true;
+ }
+
+ }
+
+
+ public void write(char buf[], int off, int len) {
+
+ if (error)
+ return;
+
+ try {
+ ob.write(buf, off, len);
+ } catch (IOException e) {
+ error = true;
+ }
+
+ }
+
+
+ public void write(char buf[]) {
+ write(buf, 0, buf.length);
+ }
+
+
+ public void write(String s, int off, int len) {
+
+ if (error)
+ return;
+
+ try {
+ ob.write(s, off, len);
+ } catch (IOException e) {
+ error = true;
+ }
+
+ }
+
+
+ public void write(String s) {
+ write(s, 0, s.length());
+ }
+
+
+ // ---------------------------------------------------- PrintWriter Methods
+
+
+ public void print(boolean b) {
+ if (b) {
+ write("true");
+ } else {
+ write("false");
+ }
+ }
+
+
+ public void print(char c) {
+ write(c);
+ }
+
+
+ public void print(int i) {
+ write(String.valueOf(i));
+ }
+
+
+ public void print(long l) {
+ write(String.valueOf(l));
+ }
+
+
+ public void print(float f) {
+ write(String.valueOf(f));
+ }
+
+
+ public void print(double d) {
+ write(String.valueOf(d));
+ }
+
+
+ public void print(char s[]) {
+ write(s);
+ }
+
+
+ public void print(String s) {
+ if (s == null) {
+ s = "null";
+ }
+ write(s);
+ }
+
+
+ public void print(Object obj) {
+ write(String.valueOf(obj));
+ }
+
+
+ public void println() {
+ write(LINE_SEP);
+ }
+
+
+ public void println(boolean b) {
+ print(b);
+ println();
+ }
+
+
+ public void println(char c) {
+ print(c);
+ println();
+ }
+
+
+ public void println(int i) {
+ print(i);
+ println();
+ }
+
+
+ public void println(long l) {
+ print(l);
+ println();
+ }
+
+
+ public void println(float f) {
+ print(f);
+ println();
+ }
+
+
+ public void println(double d) {
+ print(d);
+ println();
+ }
+
+
+ public void println(char c[]) {
+ print(c);
+ println();
+ }
+
+
+ public void println(String s) {
+ print(s);
+ println();
+ }
+
+
+ public void println(Object o) {
+ print(o);
+ println();
+ }
+
+
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.coyote.servlet;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.Filter;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tomcat.integration.ObjectManager;
+import org.apache.tomcat.integration.simple.SimpleObjectManager;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.buf.UriNormalizer;
+import org.apache.tomcat.util.http.mapper.MappingData;
+
+/**
+ * Simpler, lower footprint serlvet engine.
+ *
+ * Uses ObjectManager to integate with an embedding app
+ * - the object names it uses:
+ *
+ * Internal objects created by Tomcat and registered for management
+ * and injection:
+ * - Servlet:CONTEXT_PATH:SERVLETNAME - a ServletWrapper
+ * - ServletContext:CONTEXT_PATH
+ * - ProtocolHandler:ep-PORT - coyote ProtocolHandler
+ * - CoyoteServer:CoyoteServer-PORT
+ * - CoyoteAdapter:PATH - for the coyote used Adapter
+ * - TomcatLite - this object.
+ * - Connector - the connector object
+ *
+ * Plugins to be constructed by framework ( defaults set in initDefaults ):
+ * - UserSessionManager
+ * - UserTemplateClassMapper
+ * - ContextPreinitListener
+ * - Connector
+ * - WebappServletMapper
+ * - WebappFilterMapper
+ * - default-servlet
+ * - jspwildcard-servlet
+ * - Foo-servlet - servlet named Foo
+ *
+ *
+ * @author Costin Manolache
+ */
+public class TomcatLite implements Runnable {
+
+ private String serverDirName;
+ private File workDir;
+
+ // all contexts - hostMapper knows about hostnames and how they are mapped.
+ // this shouldn't be needed if we want to delegate ctx management
+ private ArrayList<ServletContextImpl> contexts = new ArrayList();
+
+ URLClassLoader contextParentLoader;
+
+ // Discovered or default Host/Context mapper
+ Filter hostMapper;
+
+ // Servlets to preload in each context, configurable from CLI or API
+ Map<String,String> preloadServlets = new HashMap();
+ Map<String,String> preloadMappings = new HashMap();
+
+ Map<String,String> ctxDefaultInitParam = new HashMap();
+
+ Connector connector;
+
+ ObjectManager om;
+
+ static String SERVLETS_PACKAGE = "org.apache.tomcat.servlets";
+
+
+ protected boolean daemon = false;
+
+ public TomcatLite() {
+ }
+
+ public TomcatLite(ObjectManager om) {
+ this.setObjectManager(om);
+ }
+
+ // --------------- start/stop ---------------
+
+ public static ObjectManager defaultObjectManager() {
+ SimpleObjectManager cfg = new SimpleObjectManager();
+ cfg.loadResource("org/apache/coyote/servlet/config.properties");
+ return cfg;
+ }
+ /**
+ * Return the object manager associated with this tomcat.
+ * If none set, create a minimal one with the default
+ * values.
+ */
+ public ObjectManager getObjectManager() {
+ if (om == null) {
+ om = defaultObjectManager();
+ }
+ return om;
+ }
+
+ public void setObjectManager(ObjectManager om) {
+ this.om = om;
+ }
+
+ public List/*<ServletContextImpl>*/ getWebapps() {
+ return contexts;
+ }
+
+ public URLClassLoader getContextParentLoader() {
+ if (contextParentLoader == null) {
+
+ ClassLoader parent = this.getClass().getClassLoader();
+ contextParentLoader = new URLClassLoader(new URL[] {},
+ parent);
+
+ /*if (engineRepo == null) {
+ engineRepo = new Repository();
+ engineRepo.setParentClassLoader(parent);
+ }
+
+ contextParentLoader =
+ engineRepo.getClassLoader();
+ */
+ }
+ return contextParentLoader;
+ }
+
+ public void start() throws IOException {
+ long t0 = System.currentTimeMillis();
+
+ // start all contexts
+ // init all contexts
+ Iterator i1 = contexts.iterator();
+ while (i1.hasNext()) {
+ ServletContextImpl ctx = (ServletContextImpl) i1.next();
+ try {
+ ctx.start();
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ long t1 = System.currentTimeMillis();
+ System.err.println("Engine.start() " + (t1-t0));
+ }
+
+
+ /**
+ * Add a context - used for IntrospectionUtils.
+ *
+ * ContextPath:ContextBaseDir
+ */
+ public void setContext(String c) throws ServletException {
+ String[] pathDir = c.split(":", 2);
+ addServletContext("", pathDir[1], pathDir[0]);
+ }
+
+ public void setServletContexts(List<ServletContext> c) throws ServletException {
+ for (ServletContext ctx: c) {
+ addServletContext((ServletContextImpl) ctx);
+ }
+ }
+
+ public void setPreload(String servletNameClass) {
+ String[] nv = servletNameClass.split(":");
+ preloadServlets.put(nv[0], nv[1]);
+ }
+
+ public void addPreload(String servletName, String servletClassName) {
+ preloadServlets.put(servletName, servletClassName);
+ }
+
+ public void setDefaultInitParam(String nameValue) {
+ String[] nv = nameValue.split(":");
+ ctxDefaultInitParam.put(nv[0], nv[1]);
+ }
+
+ public void addDefaultInitParam(String name, String value) {
+ ctxDefaultInitParam.put(name, value);
+ }
+
+ public void setPreloadMappings(String servletPath) {
+ String[] nv = servletPath.split(":");
+ preloadMappings.put(nv[0], nv[1]);
+ }
+
+ public void addPreloadMapping(String servletName, String path) {
+ preloadMappings.put(servletName, path);
+ }
+
+ public void stop() {
+ Iterator i1 = contexts.iterator();
+ while (i1.hasNext()) {
+ ServletContextImpl ctx = (ServletContextImpl) i1.next();
+ try {
+ ctx.destroy();
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ try {
+ stopConnector();
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ // -------------- Context add/remove --------------
+
+ public static String[] DEFAULT_WELCOME = { "index.html" };
+
+ public void addServletContext(ServletContextImpl ctx) throws ServletException {
+ ctx.setTomcat(this);
+ if (hostMapper == null) {
+ hostMapper = new WebappContextMapper();
+ }
+
+ ((WebappContextMapper) hostMapper).addHost(ctx.getHostname(), null);
+ ((WebappContextMapper) hostMapper).addContext(ctx.getHostname(),
+ ctx);
+
+ contexts.add(ctx);
+
+ getObjectManager().bind("ServletContext:" + ctx.getContextPath(),
+ ctx);
+
+ }
+
+ /**
+ * Add a context.
+ *
+ * web.xml will be read as part of init, and the initialization will be
+ * part of start or lazy.
+ *
+ * @param hostname - ""
+ * if default host, or string to be matched with Host header
+ * @param basePath = directory where the webapp is installed
+ * @param path -
+ * context path, "/" for root, "/examples", etc
+ * @return a servlet context
+ * @throws ServletException
+ */
+ public ServletContext addServletContext(String hostname,
+ String basePath,
+ String path)
+ throws ServletException
+ {
+ ServletContextImpl ctx = new ServletContextImpl();
+ ctx.setContextPath(path);
+ ctx.setBasePath(basePath);
+ addServletContext(ctx);
+ return ctx;
+ }
+
+ public void removeServletContext(ServletContext sctx)
+ throws ServletException
+ {
+ ServletContextImpl ctx = (ServletContextImpl) sctx;
+ // TODO: destroy all servlets and filters
+ // TODO: clean up any other reference to the context or its loader
+ notifyRemove(ctx);
+ }
+
+
+ /**
+ * Required for ServletContext.getContext(uri);
+ * @throws ServletException
+ * @throws IOException
+ */
+ public ServletContextImpl getContext(ServletContextImpl impl, String uri)
+ throws IOException, ServletException {
+ // Create a request - needs to be simplified
+ ServletRequestImpl req = createMessage(impl, impl.contextPath, uri);
+ hostMapper.doFilter(req, null, null);
+ return req.getContext();
+ }
+
+ public ServletResponseImpl service(ServletRequestImpl req) throws IOException, Exception {
+ ServletResponseImpl res = req.getResponse();
+ service(req, res);
+ endRequest(req, res);
+ return res;
+ }
+
+ public void service(ServletRequestImpl req, ServletResponseImpl res)
+ throws Exception, IOException {
+ // parse the session id from URI
+ req.parseSessionId();
+
+ try {
+ UriNormalizer.decodeRequest(req.getHttpRequest().decodedURI(),
+ req.getHttpRequest().requestURI(),
+ req.getHttpRequest().getURLDecoder());
+ } catch(IOException ioe) {
+ res.setStatus(400);
+ return;
+ }
+
+ MappingData mapRes = req.getMappingData();
+ try {
+ // TODO: make hostMapper configurable, implement interface,
+ // simple to set on ROOT context
+ hostMapper.doFilter(req, null, null);
+
+
+ ServletContextImpl ctx = (ServletContextImpl)mapRes.context;
+ if( ctx == null ) {
+ // TODO: 404
+ res.setStatus(404);
+ return;
+ }
+ req.setContext(ctx);
+
+ // bind class loader
+ Thread.currentThread().setContextClassLoader(ctx.getClassLoader());
+
+ WebappServletMapper mapper = ctx.getMapper();
+ mapper.map(req.getHttpRequest().decodedURI(), mapRes);
+
+ // Possible redirect
+ MessageBytes redirectPathMB = mapRes.redirectPath;
+ if (!redirectPathMB.isNull()) {
+ String redirectPath = res.urlEncoder.encodeURL(redirectPathMB.toString());
+ String query = req.getQueryString();
+ if (req.isRequestedSessionIdFromURL()) {
+ // This is not optimal, but as this is not very common, it
+ // shouldn't matter
+ redirectPath = redirectPath + ";" + ServletRequestImpl.SESSION_PARAMETER_NAME + "="
+ + req.getRequestedSessionId();
+ }
+ if (query != null) {
+ // This is not optimal, but as this is not very common, it
+ // shouldn't matter
+ redirectPath = redirectPath + "?" + query;
+ }
+ res.sendRedirect(redirectPath);
+ return;
+ }
+
+ req.parseSessionCookiesId();
+
+ ServletConfigImpl h=(ServletConfigImpl)mapRes.wrapper;
+ if (h != null) {
+ req.setWrapper((ServletConfigImpl)mapRes.wrapper);
+ serviceServlet(ctx, req, res, h, mapRes );
+ // send the response...
+
+ //res.flushBuffer();
+
+ // Recycle the wrapper request and response
+ //req.recycle();
+ //res.recycle();
+ }
+ } finally {
+ if(mapRes != null )
+ mapRes.recycle();
+ }
+ }
+
+ /** Coyote / mapper adapter. Result of the mapper.
+ *
+ * This replaces the valve chain, the path is:
+ * 1. coyote calls mapper -> result Adapter
+ * 2. service is called. Additional filters are set on the wrapper.
+ * @param mapRes
+ */
+ private void serviceServlet(ServletContextImpl ctx,
+ ServletRequestImpl req,
+ ServletResponseImpl res,
+ ServletConfigImpl servletConfig,
+ MappingData mapRes)
+ throws IOException {
+ Servlet servlet = null;
+ try {
+ if (servletConfig.isUnavailable()) {
+ handleUnavailable(res, servletConfig);
+ return;
+ }
+ try {
+ servlet = servletConfig.allocate();
+ } catch(ServletException ex) {
+ handleUnavailable(res, servletConfig);
+ }
+ WebappFilterMapper filterMap = ctx.getFilterMapper();
+ FilterChainImpl chain =
+ filterMap.createFilterChain(req, servletConfig, servlet);
+
+ try {
+ if (chain == null) {
+ if (servlet != null) {
+ servlet.service(req, res);
+ } else {
+ System.err.println("No servlet " + req.getRequestURI());
+ res.sendError(404);
+ }
+ } else {
+ chain.doFilter(req, res);
+ }
+ } catch(UnavailableException ex) {
+ servletConfig.unavailable(ex);
+ handleUnavailable(res, servletConfig);
+ return;
+ }
+
+ // servlet completed without exception. Check status
+ int status = res.getStatus();
+ if (status != 200 && !res.isCommitted()) {
+ String statusPage = ctx.findStatusPage(status);
+
+ if (statusPage != null) {
+ ctx.handleStatusPage(req, res, status, statusPage);
+ } else {
+ // Send a default message body.
+ // TODO: maybe other mechanism to customize default.
+ res.defaultStatusPage(status, res.getMessage());
+ }
+ }
+ } catch (Throwable t) {
+ ctx.handleError(req, res, t);
+ } finally {
+ if (servlet != null) {
+ servletConfig.deallocate(servlet);
+ }
+ }
+ }
+
+ private void handleUnavailable(ServletResponseImpl response,
+ ServletConfigImpl servletConfig)
+ throws IOException {
+ long available = servletConfig.getAvailable();
+ if ((available > 0L) && (available < Long.MAX_VALUE))
+ response.setDateHeader("Retry-After", available);
+ // TODO: handle via error pages !
+ response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
+ "Service unavailable");
+ }
+
+
+ // ------------ Notifications for JMX ----------------
+
+ void notifyAdd(Object o) {
+ }
+
+ void notifyRemove(Object o) {
+ }
+
+ public void setServerDir(String dir) {
+ this.serverDirName = dir;
+ }
+
+ public File getWork() {
+ if (workDir == null) {
+ if (serverDirName == null) {
+ serverDirName = "./";
+ }
+ File rootDirFile = new File(serverDirName);
+ workDir = new File(rootDirFile, "tomcat-work");
+ if (workDir.exists()) {
+ workDir.mkdirs();
+ }
+ }
+ return workDir;
+ }
+
+ /**
+ * Init
+ *
+ * @throws ServletException
+ * @throws IOException
+ */
+ public void init() throws ServletException, IOException {
+ getObjectManager().bind("TomcatLite", this);
+ if (contexts.size() == 0) {
+ setContext("/:./webapps/ROOT");
+ }
+ getConnector().setObjectManager(getObjectManager());
+ Iterator i1 = contexts.iterator();
+ while (i1.hasNext()) {
+ ServletContextImpl ctx = (ServletContextImpl) i1.next();
+ try {
+ ctx.init();
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Initialize an webapp and add it to the server.
+ * - load web.xml
+ * - call
+ *
+ * @param rootDir
+ * @param path
+ * @param deployServlet
+ */
+ public void init(String rootDir, String path)
+ throws ServletException, IOException {
+
+ long t0 = System.currentTimeMillis();
+
+ ServletContextImpl ctx =
+ (ServletContextImpl)addServletContext(null,
+ rootDir,
+ path);
+ ctx.init();
+
+ long t1 = System.currentTimeMillis();
+
+ // At this point all config is loaded. Contexts are not yet init()
+ // - this will happen on start.
+ System.err.println("Context.init() " + path + " " + (t1-t0));
+ }
+
+ /**
+ * Get an empty request/response pair ( response available
+ * as getResponse() ). Optional set input and output buffers.
+ *
+ * This can be used for a connector-less interface to tomcat lite.
+ *
+ * TODO: make it independent of coyote !
+ */
+
+ public ServletRequestImpl createMessage() {
+ ServletRequestImpl req = new ServletRequestImpl();
+ ServletResponseImpl res = req.getResponse();
+
+ getConnector().initRequest(req, res);
+
+ req.getHttpRequest().method().setString("GET");
+ req.getHttpRequest().protocol().setString("HTTP/1.1");
+
+ return req;
+ }
+
+ /**
+ * Used internally for mapping.
+ */
+ private ServletRequestImpl createMessage(ServletContextImpl deployCtx,
+ String ctxPath,
+ String reqPath) {
+ ServletRequestImpl req = createMessage();
+ req.setContextPath(ctxPath);
+ req.setContext(deployCtx);
+ req.setRequestURI(ctxPath + reqPath);
+ return req;
+ }
+
+
+ /**
+ * Set a global filter that will be used for context mapping.
+ *
+ * The filter will get a request, with requestUri and hostname set.
+ *
+ * It needs to compute the context path and set it as an attribute.
+ *
+ * Advanced features may include on-demand loading of webapps, large scale
+ * virtual hosting, etc.
+ */
+ public void setContextMapper(Filter hostMapper2) {
+ this.hostMapper = hostMapper2;
+ }
+
+ public void endRequest(ServletRequestImpl req,
+ ServletResponseImpl res) throws IOException {
+ res.outputBuffer.flush();
+ req.getConnector().finishResponse(res);
+ }
+
+ public Connector getConnector() {
+ if (connector == null) {
+ connector = (Connector) getObjectManager().get(Connector.class);
+ setConnector(connector);
+ }
+ return connector;
+ }
+
+ public void setConnector(Connector c) {
+ connector = c;
+ connector.setTomcatLite(this);
+ getObjectManager().bind("Connector", connector);
+ }
+
+
+ public void setDaemon(boolean d) {
+ getConnector();
+ if (connector != null) {
+ connector.setDaemon(d);
+ }
+ }
+
+ public void startConnector() throws IOException {
+ getConnector();
+ if (connector != null) {
+ connector.start();
+ }
+ }
+
+ public void stopConnector() throws Exception {
+ if (connector != null) {
+ connector.stop();
+ }
+ }
+
+ public void run() {
+ try {
+ execute();
+ } catch (ServletException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void execute() throws ServletException, IOException {
+ init();
+ start();
+ startConnector();
+ }
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.coyote.servlet;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.mapper.MappingData;
+
+/**
+ * This handles host and context mapping.
+ *
+ * The default implementation for tomcat lite is very limitted -
+ * no support for virtual hosts, no support for contexts deeper than
+ * 1 level. The intention is to override this with more advanced mappers.
+ *
+ * With 'ConfigurableHosts' interface it is possible for a smart
+ * mapper to load/unload virtual hosts at runtime, maybe from a
+ * database. It should be possible to use databases to store huge number
+ * of hosts or webapps.
+ *
+ */
+public class WebappContextMapper implements Filter {
+
+ ServletContext rootContext;
+ Map<String, ServletContext> contexts = new HashMap();
+
+ public WebappContextMapper() {
+ }
+
+ public void addHost(String name, String[] aliases) {
+ }
+
+ /**
+ * Add a new Context to an existing Host.
+ *
+ * @param hostName Virtual host name this context belongs to
+ * @param contextPath Context path
+ * @param context Context object
+ * @param welcomeResources Welcome files defined for this context
+ * @param resources Static resources of the context
+ */
+ public void addContext(String hostName,
+ ServletContext context)
+ throws ServletException
+ {
+ String path = context.getContextPath();
+ if (path.lastIndexOf("/") > 0) {
+ throw new ServletException("Base context mapper supports only one level");
+ }
+ if ("/".equals(path)) {
+ rootContext = context;
+ }
+ MessageBytes mb = MessageBytes.newInstance();
+ mb.setChars(path.toCharArray(), 0, path.length());
+ contexts.put(mb.toString(), context);
+ }
+
+
+ /**
+ * Remove a context from an existing host.
+ *
+ * @param hostName Virtual host name this context belongs to
+ * @param path Context path
+ */
+ public void removeContext(String hostName, String path)
+ throws ServletException {
+ if ("/".equals(path)) {
+ rootContext = null;
+ }
+ contexts.remove(path);
+ }
+
+ /**
+ * Map the specified URI.
+ */
+ private void mapContext(ServletRequestImpl req)
+ throws IOException, ServletException {
+ MessageBytes uriMB = req.getDecodedRequestURIMB();
+ MappingData mappingData = req.getMappingData();
+ uriMB.toChars();
+ CharChunk uri = uriMB.getCharChunk();
+
+
+ if (uri.length() < 2 || contexts.size() == 0) {
+ mappingData.context = rootContext;
+ if (rootContext != null) {
+ mappingData.contextPath.setString(rootContext.getContextPath());
+ }
+ return;
+ }
+
+ int nextSlash = uri.indexOf('/', 1);
+ if (nextSlash == -1) {
+ nextSlash = uri.length();
+ }
+ mappingData.contextPath.setChars(uri.getChars(), 0, nextSlash);
+ ServletContext servletContext = contexts.get(mappingData.contextPath.toString());
+
+ if (servletContext != null) {
+ mappingData.context = servletContext;
+ } else {
+ mappingData.context = rootContext;
+ if (rootContext != null) {
+ mappingData.contextPath.setString(rootContext.getContextPath());
+ }
+ }
+ }
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+ public void doFilter(ServletRequest request,
+ ServletResponse response,
+ FilterChain chain)
+ throws IOException, ServletException {
+ ServletRequestImpl req = (ServletRequestImpl)request;
+ mapContext(req);
+ }
+
+ public void destroy() {
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.coyote.servlet;
+
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.tomcat.servlets.util.RequestUtil;
+
+/**
+ * First filter after the context and servlet are mapped. It will add
+ * web.xml-defined filters.
+ *
+ * costin: This is another mapping - done in RequestDispatcher or initial
+ * mapping.
+ * Also: StandardHostValve - sets attribute for error pages,
+ * StandardWrapperValve - mapping per invocation
+ *
+ * @author Greg Murray
+ * @author Remy Maucherat
+ */
+public class WebappFilterMapper implements Filter {
+
+
+ // -------------------------------------------------------------- Constants
+
+
+ public static final int ERROR = 1;
+ public static final Integer ERROR_INTEGER = new Integer(ERROR);
+ public static final int FORWARD = 2;
+ public static final Integer FORWARD_INTEGER = new Integer(FORWARD);
+ public static final int INCLUDE = 4;
+ public static final Integer INCLUDE_INTEGER = new Integer(INCLUDE);
+ public static final int REQUEST = 8;
+ public static final Integer REQUEST_INTEGER = new Integer(REQUEST);
+
+ /**
+ * Request dispatcher state.
+ */
+ public static final String DISPATCHER_TYPE_ATTR =
+ "org.apache.catalina.core.DISPATCHER_TYPE";
+
+ /**
+ * Request dispatcher path.
+ */
+ public static final String DISPATCHER_REQUEST_PATH_ATTR =
+ "org.apache.catalina.core.DISPATCHER_REQUEST_PATH";
+
+
+ // ----------------------------------------------------------- Constructors
+ ServletContextImpl servletContext;
+
+ public WebappFilterMapper() {
+ }
+
+ public WebappFilterMapper(ServletContextImpl impl) {
+ servletContext = impl;
+ }
+
+ public void setServletContext(ServletContextImpl sc) {
+ servletContext = sc;
+ }
+
+ // --------------------------------------------------------- Public Methods
+
+ ArrayList filterMaps = new ArrayList();
+
+ public void addMapping(String filterName,
+ String url,
+ String servletName,
+ String type[], boolean isMatchAfter) {
+ FilterMap map = new FilterMap();
+ map.setURLPattern(url);
+ map.setFilterName(filterName);
+ map.setServletName(servletName);
+ if (isMatchAfter) {
+ filterMaps.add(map);
+ } else {
+ filterMaps.add(0, map);
+ }
+ }
+
+ /**
+ * Construct and return a FilterChain implementation that will wrap the
+ * execution of the specified servlet instance. If we should not execute
+ * a filter chain at all, return <code>null</code>.
+ *
+ * @param request The servlet request we are processing
+ * @param servlet The servlet instance to be wrapped
+ */
+ public FilterChainImpl createFilterChain(ServletRequest request,
+ ServletConfigImpl wrapper,
+ Servlet servlet) {
+
+ // If there is no servlet to execute, return null
+ if (servlet == null)
+ return (null);
+
+ // get the dispatcher type
+ int dispatcher = -1;
+ if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) {
+ Integer dispatcherInt =
+ (Integer) request.getAttribute(DISPATCHER_TYPE_ATTR);
+ dispatcher = dispatcherInt.intValue();
+ }
+ String requestPath = null;
+ Object attribute = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR);
+
+ if (attribute != null){
+ requestPath = attribute.toString();
+ }
+
+ HttpServletRequest hreq = null;
+ if (request instanceof HttpServletRequest)
+ hreq = (HttpServletRequest)request;
+
+ // Create and initialize a filter chain object
+ FilterChainImpl filterChain = null;
+ if ((request instanceof ServletRequestImpl)) {
+ ServletRequestImpl req = (ServletRequestImpl) request;
+ filterChain = (FilterChainImpl) req.getFilterChain();
+ filterChain.release();
+ } else {
+ // Security: Do not recycle
+ filterChain = new FilterChainImpl();
+ }
+
+ filterChain.setServlet(wrapper, servlet);
+
+ // If there are no filter mappings, we are done
+ if ((filterMaps.size() == 0))
+ return (filterChain);
+
+ // Acquire the information we will need to match filter mappings
+ String servletName = wrapper.getServletName();
+
+ int n = 0;
+
+ // TODO(costin): optimize: separate in 2 lists, one for url-mapped, one for
+ // servlet-name. Maybe even separate list for dispatcher and
+ // non-dispatcher
+
+ // TODO(costin): optimize: set the FilterConfig in the FilterMap, to
+ // avoid second hash lookup
+
+ // Add the relevant path-mapped filters to this filter chain
+ for (int i = 0; i < filterMaps.size(); i++) {
+ FilterMap filterMap = (FilterMap)filterMaps.get(i);
+ if (!matchDispatcher(filterMap ,dispatcher)) {
+ continue;
+ }
+ if (!matchFiltersURL(filterMap, requestPath))
+ continue;
+ FilterConfigImpl filterConfig =
+ servletContext.getFilter(filterMap.getFilterName());
+ if (filterConfig == null) {
+ // FIXME - log configuration problem
+ continue;
+ }
+ filterChain.addFilter(filterConfig);
+ n++;
+ }
+
+ // Add filters that match on servlet name second
+ for (int i = 0; i < filterMaps.size(); i++) {
+ FilterMap filterMap = (FilterMap)filterMaps.get(i);
+ if (!matchDispatcher(filterMap ,dispatcher)) {
+ continue;
+ }
+ if (!matchFiltersServlet(filterMap, servletName))
+ continue;
+ FilterConfigImpl filterConfig =
+ servletContext.getFilter(filterMap.getFilterName());
+ if (filterConfig == null) {
+ ; // FIXME - log configuration problem
+ continue;
+ }
+ filterChain.addFilter(filterConfig);
+ n++;
+ }
+
+ // Return the completed filter chain
+ return (filterChain);
+
+ }
+
+
+ // -------------------------------------------------------- Private Methods
+
+
+ /**
+ * Return <code>true</code> if the context-relative request path
+ * matches the requirements of the specified filter mapping;
+ * otherwise, return <code>null</code>.
+ *
+ * @param filterMap Filter mapping being checked
+ * @param requestPath Context-relative request path of this request
+ */
+ private boolean matchFiltersURL(FilterMap filterMap, String requestPath) {
+
+ if (requestPath == null)
+ return (false);
+
+ // Match on context relative request path
+ String testPath = filterMap.getURLPattern();
+ if (testPath == null)
+ return (false);
+
+ // Case 1 - Exact Match
+ if (testPath.equals(requestPath))
+ return (true);
+
+ // Case 2 - Path Match ("/.../*")
+ if (testPath.equals("/*"))
+ return (true);
+ if (testPath.endsWith("/*")) {
+ if (testPath.regionMatches(0, requestPath, 0,
+ testPath.length() - 2)) {
+ if (requestPath.length() == (testPath.length() - 2)) {
+ return (true);
+ } else if ('/' == requestPath.charAt(testPath.length() - 2)) {
+ return (true);
+ }
+ }
+ return (false);
+ }
+
+ // Case 3 - Extension Match
+ if (testPath.startsWith("*.")) {
+ int slash = requestPath.lastIndexOf('/');
+ int period = requestPath.lastIndexOf('.');
+ if ((slash >= 0) && (period > slash)
+ && (period != requestPath.length() - 1)
+ && ((requestPath.length() - period)
+ == (testPath.length() - 1))) {
+ return (testPath.regionMatches(2, requestPath, period + 1,
+ testPath.length() - 2));
+ }
+ }
+
+ // Case 4 - "Default" Match
+ return (false); // NOTE - Not relevant for selecting filters
+
+ }
+
+
+ /**
+ * Return <code>true</code> if the specified servlet name matches
+ * the requirements of the specified filter mapping; otherwise
+ * return <code>false</code>.
+ *
+ * @param filterMap Filter mapping being checked
+ * @param servletName Servlet name being checked
+ */
+ private boolean matchFiltersServlet(FilterMap filterMap,
+ String servletName) {
+
+ if (servletName == null) {
+ return (false);
+ } else {
+ if (servletName.equals(filterMap.getServletName())) {
+ return (true);
+ } else {
+ return false;
+ }
+ }
+
+ }
+
+
+ /**
+ * Convienience method which returns true if the dispatcher type
+ * matches the dispatcher types specified in the FilterMap
+ */
+ private boolean matchDispatcher(FilterMap filterMap, int dispatcher) {
+ switch (dispatcher) {
+ case FORWARD : {
+ if (filterMap.getDispatcherMapping() == FilterMap.FORWARD ||
+ filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR ||
+ filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD ||
+ filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) {
+ return true;
+ }
+ break;
+ }
+ case INCLUDE : {
+ if (filterMap.getDispatcherMapping() == FilterMap.INCLUDE ||
+ filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR ||
+ filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD ||
+ filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) {
+ return true;
+ }
+ break;
+ }
+ case REQUEST : {
+ if (filterMap.getDispatcherMapping() == FilterMap.REQUEST ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE) {
+ return true;
+ }
+ break;
+ }
+ case ERROR : {
+ if (filterMap.getDispatcherMapping() == FilterMap.ERROR ||
+ filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR ||
+ filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR ||
+ filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
+ filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE) {
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+ }
+
+
+ // -------------------- Map elements -----------------------
+
+ public static class FilterMap implements Serializable {
+
+
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * The name of this filter to be executed when this mapping matches
+ * a particular request.
+ */
+
+ public static final int ERROR = 1;
+ public static final int FORWARD = 2;
+ public static final int FORWARD_ERROR =3;
+ public static final int INCLUDE = 4;
+ public static final int INCLUDE_ERROR = 5;
+ public static final int INCLUDE_ERROR_FORWARD =6;
+ public static final int INCLUDE_FORWARD = 7;
+ public static final int REQUEST = 8;
+ public static final int REQUEST_ERROR = 9;
+ public static final int REQUEST_ERROR_FORWARD = 10;
+ public static final int REQUEST_ERROR_FORWARD_INCLUDE = 11;
+ public static final int REQUEST_ERROR_INCLUDE = 12;
+ public static final int REQUEST_FORWARD = 13;
+ public static final int REQUEST_INCLUDE = 14;
+ public static final int REQUEST_FORWARD_INCLUDE= 15;
+
+ // represents nothing having been set. This will be seen
+ // as equal to a REQUEST
+ private static final int NOT_SET = -1;
+
+ private int dispatcherMapping=NOT_SET;
+
+ private String filterName = null;
+
+ /**
+ * The URL pattern this mapping matches.
+ */
+ private String urlPattern = null;
+
+ /**
+ * The servlet name this mapping matches.
+ */
+ private String servletName = null;
+
+
+
+ public String getFilterName() {
+ return (this.filterName);
+ }
+
+ public void setFilterName(String filterName) {
+ this.filterName = filterName;
+ }
+
+
+ public String getServletName() {
+ return (this.servletName);
+ }
+
+ public void setServletName(String servletName) {
+ this.servletName = servletName;
+ }
+
+
+ public String getURLPattern() {
+ return (this.urlPattern);
+ }
+
+ public void setURLPattern(String urlPattern) {
+ this.urlPattern = RequestUtil.URLDecode(urlPattern);
+ }
+
+ /**
+ *
+ * This method will be used to set the current state of the FilterMap
+ * representing the state of when filters should be applied:
+ *
+ * ERROR
+ * FORWARD
+ * FORWARD_ERROR
+ * INCLUDE
+ * INCLUDE_ERROR
+ * INCLUDE_ERROR_FORWARD
+ * REQUEST
+ * REQUEST_ERROR
+ * REQUEST_ERROR_INCLUDE
+ * REQUEST_ERROR_FORWARD_INCLUDE
+ * REQUEST_INCLUDE
+ * REQUEST_FORWARD,
+ * REQUEST_FORWARD_INCLUDE
+ *
+ */
+ public void setDispatcher(String dispatcherString) {
+ String dispatcher = dispatcherString.toUpperCase();
+
+ if (dispatcher.equals("FORWARD")) {
+
+ // apply FORWARD to the global dispatcherMapping.
+ switch (dispatcherMapping) {
+ case NOT_SET : dispatcherMapping = FORWARD; break;
+ case ERROR : dispatcherMapping = FORWARD_ERROR; break;
+ case INCLUDE : dispatcherMapping = INCLUDE_FORWARD; break;
+ case INCLUDE_ERROR : dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
+ case REQUEST : dispatcherMapping = REQUEST_FORWARD; break;
+ case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break;
+ case REQUEST_ERROR_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
+ case REQUEST_INCLUDE : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
+ }
+ } else if (dispatcher.equals("INCLUDE")) {
+ // apply INCLUDE to the global dispatcherMapping.
+ switch (dispatcherMapping) {
+ case NOT_SET : dispatcherMapping = INCLUDE; break;
+ case ERROR : dispatcherMapping = INCLUDE_ERROR; break;
+ case FORWARD : dispatcherMapping = INCLUDE_FORWARD; break;
+ case FORWARD_ERROR : dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
+ case REQUEST : dispatcherMapping = REQUEST_INCLUDE; break;
+ case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
+ case REQUEST_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
+ case REQUEST_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
+ }
+ } else if (dispatcher.equals("REQUEST")) {
+ // apply REQUEST to the global dispatcherMapping.
+ switch (dispatcherMapping) {
+ case NOT_SET : dispatcherMapping = REQUEST; break;
+ case ERROR : dispatcherMapping = REQUEST_ERROR; break;
+ case FORWARD : dispatcherMapping = REQUEST_FORWARD; break;
+ case FORWARD_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break;
+ case INCLUDE : dispatcherMapping = REQUEST_INCLUDE; break;
+ case INCLUDE_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
+ case INCLUDE_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
+ case INCLUDE_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
+ }
+ } else if (dispatcher.equals("ERROR")) {
+ // apply ERROR to the global dispatcherMapping.
+ switch (dispatcherMapping) {
+ case NOT_SET : dispatcherMapping = ERROR; break;
+ case FORWARD : dispatcherMapping = FORWARD_ERROR; break;
+ case INCLUDE : dispatcherMapping = INCLUDE_ERROR; break;
+ case INCLUDE_FORWARD : dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
+ case REQUEST : dispatcherMapping = REQUEST_ERROR; break;
+ case REQUEST_INCLUDE : dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
+ case REQUEST_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD; break;
+ case REQUEST_FORWARD_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
+ }
+ }
+ }
+
+ public int getDispatcherMapping() {
+ // per the SRV.6.2.5 absence of any dispatcher elements is
+ // equivelant to a REQUEST value
+ if (dispatcherMapping == NOT_SET) return REQUEST;
+ else return dispatcherMapping;
+ }
+
+ }
+
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain)
+ throws IOException, ServletException {
+ }
+
+
+ public void destroy() {
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.coyote.servlet;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.tomcat.util.buf.Ascii;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.mapper.MappingData;
+
+/**
+ * Mapper, which implements the servlet API mapping rules (which are derived
+ * from the HTTP rules).
+ *
+ * Based on catalina mapper - but simplified. All host and context mappings
+ * is done in HostMapper - this is just dealing with web.xml.
+ *
+ * For corner cases ( very large number of rules, dynamic rules, etc ) you
+ * can override the mapper for a context with a class extending this.
+ *
+ * TODO: remove, use coyote-level mapper or user-space
+ */
+public class WebappServletMapper implements Filter {
+
+ /**
+ * Context associated with this wrapper, used for wrapper mapping.
+ */
+ public ContextMapElement contextMapElement = new ContextMapElement();
+
+
+ // --------------------------------------------------------- Public Methods
+ public WebappServletMapper() {
+ }
+
+ public void setServletContext(ServletContextImpl impl) {
+ contextMapElement.object = impl;
+ contextMapElement.name = impl.getContextPath();
+ }
+
+
+ /** Set context, used for wrapper mapping (request dispatcher).
+ *
+ * @param welcomeResources Welcome files defined for this context
+ * @param resources Static resources of the context
+ */
+ public void setContext(String path, String[] welcomeResources,
+ File resources) {
+ contextMapElement.name = path;
+ contextMapElement.welcomeResources = welcomeResources;
+ contextMapElement.resources = resources;
+ }
+
+
+ /**
+ * Add a wrapper to the context associated with this wrapper.
+ *
+ * @param path Wrapper mapping
+ * @param wrapper The Wrapper object
+ */
+ public void addWrapper(String path, Object wrapper) {
+ addWrapper(contextMapElement, path, wrapper);
+ }
+
+
+ public void addWrapper(String path, Object wrapper, boolean jspWildCard) {
+ addWrapper(contextMapElement, path, wrapper, jspWildCard);
+ }
+
+
+ public void addWrapper(ContextMapElement context, String path, Object wrapper) {
+ addWrapper(context, path, wrapper, false);
+ }
+
+
+ /**
+ * Adds a wrapper to the given context.
+ *
+ * @param context The context to which to add the wrapper
+ * @param path Wrapper mapping
+ * @param wrapper The Wrapper object
+ * @param jspWildCard true if the wrapper corresponds to the JspServlet
+ * and the mapping path contains a wildcard; false otherwise
+ */
+ protected void addWrapper(ContextMapElement context, String path, Object wrapper,
+ boolean jspWildCard) {
+
+ synchronized (context) {
+ WrapperMapElement newWrapper = new WrapperMapElement();
+ newWrapper.object = wrapper;
+ newWrapper.jspWildCard = jspWildCard;
+ if (path.endsWith("/*")) {
+ // Wildcard wrapper
+ newWrapper.name = path.substring(0, path.length() - 2);
+ WrapperMapElement[] oldWrappers = context.wildcardWrappers;
+ WrapperMapElement[] newWrappers =
+ new WrapperMapElement[oldWrappers.length + 1];
+ if (insertMap(oldWrappers, newWrappers, newWrapper)) {
+ context.wildcardWrappers = newWrappers;
+ int slashCount = slashCount(newWrapper.name);
+ if (slashCount > context.nesting) {
+ context.nesting = slashCount;
+ }
+ }
+ } else if (path.startsWith("*.")) {
+ // Extension wrapper
+ newWrapper.name = path.substring(2);
+ WrapperMapElement[] oldWrappers = context.extensionWrappers;
+ WrapperMapElement[] newWrappers =
+ new WrapperMapElement[oldWrappers.length + 1];
+ if (insertMap(oldWrappers, newWrappers, newWrapper)) {
+ context.extensionWrappers = newWrappers;
+ }
+ } else if (path.equals("/")) {
+ // Default wrapper
+ newWrapper.name = "";
+ context.defaultWrapper = newWrapper;
+ } else {
+ // Exact wrapper
+ newWrapper.name = path;
+ WrapperMapElement[] oldWrappers = context.exactWrappers;
+ WrapperMapElement[] newWrappers =
+ new WrapperMapElement[oldWrappers.length + 1];
+ if (insertMap(oldWrappers, newWrappers, newWrapper)) {
+ context.exactWrappers = newWrappers;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Remove a wrapper from the context associated with this wrapper.
+ *
+ * @param path Wrapper mapping
+ */
+ public void removeWrapper(String path) {
+ removeWrapper(contextMapElement, path);
+ }
+
+
+ protected void removeWrapper(ContextMapElement context, String path) {
+ synchronized (context) {
+ if (path.endsWith("/*")) {
+ // Wildcard wrapper
+ String name = path.substring(0, path.length() - 2);
+ WrapperMapElement[] oldWrappers = context.wildcardWrappers;
+ WrapperMapElement[] newWrappers =
+ new WrapperMapElement[oldWrappers.length - 1];
+ if (removeMap(oldWrappers, newWrappers, name)) {
+ // Recalculate nesting
+ context.nesting = 0;
+ for (int i = 0; i < newWrappers.length; i++) {
+ int slashCount = slashCount(newWrappers[i].name);
+ if (slashCount > context.nesting) {
+ context.nesting = slashCount;
+ }
+ }
+ context.wildcardWrappers = newWrappers;
+ }
+ } else if (path.startsWith("*.")) {
+ // Extension wrapper
+ String name = path.substring(2);
+ WrapperMapElement[] oldWrappers = context.extensionWrappers;
+ WrapperMapElement[] newWrappers =
+ new WrapperMapElement[oldWrappers.length - 1];
+ if (removeMap(oldWrappers, newWrappers, name)) {
+ context.extensionWrappers = newWrappers;
+ }
+ } else if (path.equals("/")) {
+ // Default wrapper
+ context.defaultWrapper = null;
+ } else {
+ // Exact wrapper
+ String name = path;
+ WrapperMapElement[] oldWrappers = context.exactWrappers;
+ WrapperMapElement[] newWrappers =
+ new WrapperMapElement[oldWrappers.length - 1];
+ if (removeMap(oldWrappers, newWrappers, name)) {
+ context.exactWrappers = newWrappers;
+ }
+ }
+ }
+ }
+
+ /**
+ * Map the specified URI relative to the context,
+ * mutating the given mapping data.
+ *
+ * @param uri URI
+ * @param mappingData This structure will contain the result of the mapping
+ * operation
+ */
+ public void map(MessageBytes uri, MappingData mappingData)
+ throws Exception {
+
+ uri.toChars();
+ CharChunk uricc = uri.getCharChunk();
+ //uricc.setLimit(-1);
+ internalMapWrapper(contextMapElement, uricc, mappingData);
+
+ }
+
+
+ // -------------------------------------------------------- Private Methods
+
+
+ /**
+ * Wrapper mapping.
+ */
+ private final void internalMapWrapper(ContextMapElement context,
+ CharChunk path,
+ MappingData mappingData)
+ throws Exception {
+
+ int pathOffset = path.getOffset();
+ int pathEnd = path.getEnd();
+ int servletPath = pathOffset;
+ boolean noServletPath = false;
+
+ int length = context.name.length();
+ if (length == 1) length--;
+ if (length != (pathEnd - pathOffset)) {
+ servletPath = pathOffset + length;
+ } else {
+ noServletPath = true;
+ // What is this doing ???
+ path.append('/');
+ pathOffset = path.getOffset();
+ pathEnd = path.getEnd();
+ servletPath = pathOffset+length;
+ }
+
+ path.setOffset(servletPath);
+
+ // Rule 1 -- Exact Match
+ WrapperMapElement[] exactWrappers = context.exactWrappers;
+ internalMapExactWrapper(exactWrappers, path, mappingData);
+
+ // Rule 2 -- Prefix Match
+ boolean checkJspWelcomeFiles = false;
+ WrapperMapElement[] wildcardWrappers = context.wildcardWrappers;
+ if (mappingData.wrapper == null) {
+ internalMapWildcardWrapper(wildcardWrappers, context.nesting,
+ path, mappingData);
+ if (mappingData.wrapper != null && mappingData.jspWildCard) {
+ char[] buf = path.getBuffer();
+ if (buf[pathEnd - 1] == '/') {
+ /*
+ * Path ending in '/' was mapped to JSP servlet based on
+ * wildcard match (e.g., as specified in url-pattern of a
+ * jsp-property-group.
+ * Force the context's welcome files, which are interpreted
+ * as JSP files (since they match the url-pattern), to be
+ * considered. See Bugzilla 27664.
+ */
+ mappingData.wrapper = null;
+ checkJspWelcomeFiles = true;
+ } else {
+ // See Bugzilla 27704
+ mappingData.wrapperPath.setChars(buf, path.getStart(),
+ path.getLength());
+ mappingData.pathInfo.recycle();
+ }
+ }
+ }
+
+ if(mappingData.wrapper == null && noServletPath) {
+ // The path is empty, redirect to "/"
+ mappingData.redirectPath.setChars
+ (path.getBuffer(), pathOffset, pathEnd);
+ path.setEnd(pathEnd - 1);
+ return;
+ }
+
+ // Rule 3 -- Extension Match
+ WrapperMapElement[] extensionWrappers = context.extensionWrappers;
+ if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
+ internalMapExtensionWrapper(extensionWrappers, path, mappingData);
+ }
+
+ File file = null;
+ // Rule 4 -- Welcome resources processing for servlets
+ if (mappingData.wrapper == null) {
+ boolean checkWelcomeFiles = checkJspWelcomeFiles;
+ if (!checkWelcomeFiles) {
+ char[] buf = path.getBuffer();
+ checkWelcomeFiles = (buf[pathEnd - 1] == '/');
+ }
+ if (checkWelcomeFiles) {
+ for (int i = 0; (i < context.welcomeResources.length)
+ && (mappingData.wrapper == null); i++) {
+ path.setOffset(pathOffset);
+ path.setEnd(pathEnd);
+ path.append(context.welcomeResources[i], 0,
+ context.welcomeResources[i].length());
+ path.setOffset(servletPath);
+
+ // Rule 4a -- Welcome resources processing for exact macth
+ internalMapExactWrapper(exactWrappers, path, mappingData);
+
+ // Rule 4b -- Welcome resources processing for prefix match
+ if (mappingData.wrapper == null) {
+ internalMapWildcardWrapper
+ (wildcardWrappers, context.nesting,
+ path, mappingData);
+ }
+
+ // Rule 4c -- Welcome resources processing
+ // for physical folder
+ if (mappingData.wrapper == null
+ && context.resources != null) {
+ // Default servlet: check if it's file or dir to apply
+ // welcome files rules.
+ // TODO: Save the File in attributes,
+ // to avoid duplication in DefaultServlet.
+
+ String pathStr = path.toString();
+ file = new File(context.resources, pathStr);
+ if (file.exists() && !(file.isDirectory()) ) {
+
+ internalMapExtensionWrapper(extensionWrappers,
+ path, mappingData);
+ if (mappingData.wrapper == null
+ && context.defaultWrapper != null) {
+ mappingData.wrapper =
+ context.defaultWrapper.object;
+ mappingData.requestPath.setChars
+ (path.getBuffer(), path.getStart(),
+ path.getLength());
+ mappingData.wrapperPath.setChars
+ (path.getBuffer(), path.getStart(),
+ path.getLength());
+ mappingData.requestPath.setString(pathStr);
+ mappingData.wrapperPath.setString(pathStr);
+ }
+ }
+ }
+ }
+
+ path.setOffset(servletPath);
+ path.setEnd(pathEnd);
+ }
+
+ }
+
+
+ // Rule 7 -- Default servlet
+ if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
+ if (context.defaultWrapper != null) {
+ mappingData.wrapper = context.defaultWrapper.object;
+ mappingData.requestPath.setChars
+ (path.getBuffer(), path.getStart(), path.getLength());
+ mappingData.wrapperPath.setChars
+ (path.getBuffer(), path.getStart(), path.getLength());
+ }
+ // Redirection to a folder
+ char[] buf = path.getBuffer();
+ if (context.resources != null && buf[pathEnd -1 ] != '/') {
+ String pathStr = path.toString();
+ file = new File( context.resources, pathStr);
+ if (file.exists() && file.isDirectory()) {
+ // Note: this mutates the path: do not do any processing
+ // after this (since we set the redirectPath, there
+ // shouldn't be any)
+ path.setOffset(pathOffset);
+ path.append('/');
+ mappingData.redirectPath.setChars
+ (path.getBuffer(), path.getStart(), path.getLength());
+ } else {
+ mappingData.requestPath.setString(pathStr);
+ mappingData.wrapperPath.setString(pathStr);
+ }
+ }
+ }
+
+ path.setOffset(pathOffset);
+ path.setEnd(pathEnd);
+ }
+
+
+ /**
+ * Exact mapping.
+ */
+ private final void internalMapExactWrapper
+ (WrapperMapElement[] wrappers, CharChunk path, MappingData mappingData) {
+ int pos = find(wrappers, path);
+ if ((pos != -1) && (path.equals(wrappers[pos].name))) {
+ mappingData.requestPath.setString(wrappers[pos].name);
+ mappingData.wrapperPath.setString(wrappers[pos].name);
+ mappingData.wrapper = wrappers[pos].object;
+ }
+ }
+
+
+ /**
+ * Wildcard mapping.
+ */
+ private final void internalMapWildcardWrapper
+ (WrapperMapElement[] wrappers, int nesting, CharChunk path,
+ MappingData mappingData) {
+
+ int pathEnd = path.getEnd();
+ int pathOffset = path.getOffset();
+
+ int lastSlash = -1;
+ int length = -1;
+ int pos = find(wrappers, path);
+ if (pos != -1) {
+ boolean found = false;
+ while (pos >= 0) {
+ if (path.startsWith(wrappers[pos].name)) {
+ length = wrappers[pos].name.length();
+ if (path.getLength() == length) {
+ found = true;
+ break;
+ } else if (path.startsWithIgnoreCase("/", length)) {
+ found = true;
+ break;
+ }
+ }
+ if (lastSlash == -1) {
+ lastSlash = nthSlash(path, nesting + 1);
+ } else {
+ lastSlash = lastSlash(path);
+ }
+ path.setEnd(lastSlash);
+ pos = find(wrappers, path);
+ }
+ path.setEnd(pathEnd);
+ if (found) {
+ mappingData.wrapperPath.setString(wrappers[pos].name);
+ if (path.getLength() > length) {
+ mappingData.pathInfo.setChars
+ (path.getBuffer(),
+ path.getOffset() + length,
+ path.getLength() - length);
+ }
+ mappingData.requestPath.setChars
+ (path.getBuffer(), path.getOffset(), path.getLength());
+ mappingData.wrapper = wrappers[pos].object;
+ mappingData.jspWildCard = wrappers[pos].jspWildCard;
+ }
+ }
+ }
+
+
+ /**
+ * Extension mappings.
+ */
+ private final void internalMapExtensionWrapper
+ (WrapperMapElement[] wrappers, CharChunk path, MappingData mappingData) {
+ char[] buf = path.getBuffer();
+ int pathEnd = path.getEnd();
+ int servletPath = path.getOffset();
+ int slash = -1;
+ for (int i = pathEnd - 1; i >= servletPath; i--) {
+ if (buf[i] == '/') {
+ slash = i;
+ break;
+ }
+ }
+ if (slash == -1 ) slash = 0;
+ if (slash >= 0) {
+ int period = -1;
+ for (int i = pathEnd - 1; i > slash; i--) {
+ if (buf[i] == '.') {
+ period = i;
+ break;
+ }
+ }
+ if (period >= 0) {
+ path.setOffset(period + 1);
+ path.setEnd(pathEnd);
+ int pos = find(wrappers, path);
+ if ((pos != -1)
+ && (path.equals(wrappers[pos].name))) {
+ mappingData.wrapperPath.setChars
+ (buf, servletPath, pathEnd - servletPath);
+ mappingData.requestPath.setChars
+ (buf, servletPath, pathEnd - servletPath);
+ mappingData.wrapper = wrappers[pos].object;
+ }
+ path.setOffset(servletPath);
+ path.setEnd(pathEnd);
+ }
+ }
+ }
+
+
+ /**
+ * Find a map elemnt given its name in a sorted array of map elements.
+ * This will return the index for the closest inferior or equal item in the
+ * given array.
+ */
+ public static final int find(MapElement[] map, CharChunk name) {
+ return find(map, name, name.getStart(), name.getEnd());
+ }
+
+
+ /**
+ * Find a map elemnt given its name in a sorted array of map elements.
+ * This will return the index for the closest inferior or equal item in the
+ * given array.
+ */
+ private static final int find(MapElement[] map, CharChunk name,
+ int start, int end) {
+
+ int a = 0;
+ int b = map.length - 1;
+
+ // Special cases: -1 and 0
+ if (b == -1) {
+ return -1;
+ }
+
+ if (compare(name, start, end, map[0].name) < 0 ) {
+ return -1;
+ }
+ if (b == 0) {
+ return 0;
+ }
+
+ int i = 0;
+ while (true) {
+ i = (b + a) / 2;
+ int result = compare(name, start, end, map[i].name);
+ if (result == 1) {
+ a = i;
+ } else if (result == 0) {
+ return i;
+ } else {
+ b = i;
+ }
+ if ((b - a) == 1) {
+ int result2 = compare(name, start, end, map[b].name);
+ if (result2 < 0) {
+ return a;
+ } else {
+ return b;
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Find a map elemnt given its name in a sorted array of map elements.
+ * This will return the index for the closest inferior or equal item in the
+ * given array.
+ */
+ private static final int findIgnoreCase(MapElement[] map, CharChunk name) {
+ return findIgnoreCase(map, name, name.getStart(), name.getEnd());
+ }
+
+
+ /**
+ * Find a map elemnt given its name in a sorted array of map elements.
+ * This will return the index for the closest inferior or equal item in the
+ * given array.
+ */
+ private static final int findIgnoreCase(MapElement[] map, CharChunk name,
+ int start, int end) {
+
+ int a = 0;
+ int b = map.length - 1;
+
+ // Special cases: -1 and 0
+ if (b == -1) {
+ return -1;
+ }
+ if (compareIgnoreCase(name, start, end, map[0].name) < 0 ) {
+ return -1;
+ }
+ if (b == 0) {
+ return 0;
+ }
+
+ int i = 0;
+ while (true) {
+ i = (b + a) / 2;
+ int result = compareIgnoreCase(name, start, end, map[i].name);
+ if (result == 1) {
+ a = i;
+ } else if (result == 0) {
+ return i;
+ } else {
+ b = i;
+ }
+ if ((b - a) == 1) {
+ int result2 = compareIgnoreCase(name, start, end, map[b].name);
+ if (result2 < 0) {
+ return a;
+ } else {
+ return b;
+ }
+ }
+ }
+
+ }
+
+
+ /**
+ * Find a map elemnt given its name in a sorted array of map elements.
+ * This will return the index for the closest inferior or equal item in the
+ * given array.
+ */
+ public static final int find(MapElement[] map, String name) {
+
+ int a = 0;
+ int b = map.length - 1;
+
+ // Special cases: -1 and 0
+ if (b == -1) {
+ return -1;
+ }
+
+ if (name.compareTo(map[0].name) < 0) {
+ return -1;
+ }
+ if (b == 0) {
+ return 0;
+ }
+
+ int i = 0;
+ while (true) {
+ i = (b + a) / 2;
+ int result = name.compareTo(map[i].name);
+ if (result > 0) {
+ a = i;
+ } else if (result == 0) {
+ return i;
+ } else {
+ b = i;
+ }
+ if ((b - a) == 1) {
+ int result2 = name.compareTo(map[b].name);
+ if (result2 < 0) {
+ return a;
+ } else {
+ return b;
+ }
+ }
+ }
+
+ }
+
+
+ /**
+ * Compare given char chunk with String.
+ * Return -1, 0 or +1 if inferior, equal, or superior to the String.
+ */
+ private static final int compare(CharChunk name, int start, int end,
+ String compareTo) {
+ int result = 0;
+ char[] c = name.getBuffer();
+ int len = compareTo.length();
+ if ((end - start) < len) {
+ len = end - start;
+ }
+ for (int i = 0; (i < len) && (result == 0); i++) {
+ if (c[i + start] > compareTo.charAt(i)) {
+ result = 1;
+ } else if (c[i + start] < compareTo.charAt(i)) {
+ result = -1;
+ }
+ }
+ if (result == 0) {
+ if (compareTo.length() > (end - start)) {
+ result = -1;
+ } else if (compareTo.length() < (end - start)) {
+ result = 1;
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Compare given char chunk with String ignoring case.
+ * Return -1, 0 or +1 if inferior, equal, or superior to the String.
+ */
+ private static final int compareIgnoreCase(CharChunk name, int start, int end,
+ String compareTo) {
+ int result = 0;
+ char[] c = name.getBuffer();
+ int len = compareTo.length();
+ if ((end - start) < len) {
+ len = end - start;
+ }
+ for (int i = 0; (i < len) && (result == 0); i++) {
+ if (Ascii.toLower(c[i + start]) > Ascii.toLower(compareTo.charAt(i))) {
+ result = 1;
+ } else if (Ascii.toLower(c[i + start]) < Ascii.toLower(compareTo.charAt(i))) {
+ result = -1;
+ }
+ }
+ if (result == 0) {
+ if (compareTo.length() > (end - start)) {
+ result = -1;
+ } else if (compareTo.length() < (end - start)) {
+ result = 1;
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Find the position of the last slash in the given char chunk.
+ */
+ public static final int lastSlash(CharChunk name) {
+
+ char[] c = name.getBuffer();
+ int end = name.getEnd();
+ int start = name.getStart();
+ int pos = end;
+
+ while (pos > start) {
+ if (c[--pos] == '/') {
+ break;
+ }
+ }
+
+ return (pos);
+
+ }
+
+
+ /**
+ * Find the position of the nth slash, in the given char chunk.
+ */
+ public static final int nthSlash(CharChunk name, int n) {
+
+ char[] c = name.getBuffer();
+ int end = name.getEnd();
+ int start = name.getStart();
+ int pos = start;
+ int count = 0;
+
+ while (pos < end) {
+ if ((c[pos++] == '/') && ((++count) == n)) {
+ pos--;
+ break;
+ }
+ }
+
+ return (pos);
+
+ }
+
+
+ /**
+ * Return the slash count in a given string.
+ */
+ public static final int slashCount(String name) {
+ int pos = -1;
+ int count = 0;
+ while ((pos = name.indexOf('/', pos + 1)) != -1) {
+ count++;
+ }
+ return count;
+ }
+
+
+ /**
+ * Insert into the right place in a sorted MapElement array, and prevent
+ * duplicates.
+ */
+ public static final boolean insertMap
+ (MapElement[] oldMap, MapElement[] newMap, MapElement newElement) {
+ int pos = find(oldMap, newElement.name);
+ if ((pos != -1) && (newElement.name.equals(oldMap[pos].name))) {
+ return false;
+ }
+ System.arraycopy(oldMap, 0, newMap, 0, pos + 1);
+ newMap[pos + 1] = newElement;
+ System.arraycopy
+ (oldMap, pos + 1, newMap, pos + 2, oldMap.length - pos - 1);
+ return true;
+ }
+
+
+ /**
+ * Insert into the right place in a sorted MapElement array.
+ */
+ public static final boolean removeMap
+ (MapElement[] oldMap, MapElement[] newMap, String name) {
+ int pos = find(oldMap, name);
+ if ((pos != -1) && (name.equals(oldMap[pos].name))) {
+ System.arraycopy(oldMap, 0, newMap, 0, pos);
+ System.arraycopy(oldMap, pos + 1, newMap, pos,
+ oldMap.length - pos - 1);
+ return true;
+ }
+ return false;
+ }
+
+
+ // ------------------------------------------------- MapElement Inner Class
+
+
+ protected static abstract class MapElement {
+ /** hostname or path
+ */
+ public String name = null;
+ public Object object = null;
+
+ public String toString() {
+ return "MapElement: \"" + name +"\"";
+ }
+ }
+
+
+ // ---------------------------------------------------- Context Inner Class
+
+
+ public static final class ContextMapElement
+ extends MapElement {
+
+ public String[] welcomeResources = new String[0];
+ public File resources = null;
+ public WrapperMapElement defaultWrapper = null;
+ public WrapperMapElement[] exactWrappers = new WrapperMapElement[0];
+ public WrapperMapElement[] wildcardWrappers = new WrapperMapElement[0];
+ public WrapperMapElement[] extensionWrappers = new WrapperMapElement[0];
+ public int nesting = 0;
+
+ public String toString() {
+ return "ContextMapElement {" +
+ "name: \"" + name +
+ "\"\nnesting: \"" + nesting +
+ "\"\n}";
+ }
+ }
+
+
+ // ---------------------------------------------------- Wrapper Inner Class
+
+
+ public static class WrapperMapElement
+ extends MapElement {
+ public boolean jspWildCard = false;
+ }
+
+
+ public void destroy() {
+ }
+
+
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException,
+ ServletException {
+ }
+
+
+ public void init(FilterConfig filterConfig) throws ServletException {
+ }
+
+
+}
--- /dev/null
+# Support for PropertiesSpi - the 'dummy' framework used for tomcat-lite
+# If tomcat is used with a proper framework, you need to bind and configure
+# those objects in the framework.
+
+Main.(class)=org.apache.coyote.servlet.TomcatLite
+
+Jmx.(class)=org.apache.tomcat.integration.jmx.JmxObjectManagerSpi
+
+# --- Class names for required plugin interfaces ---
+
+org.apache.coyote.servlet.WebappServletMapper.(class)=org.apache.coyote.servlet.WebappServletMapper
+org.apache.coyote.servlet.WebappFilterMapper.(class)=org.apache.coyote.servlet.WebappFilterMapper
+
+# Sessions
+org.apache.tomcat.servlets.session.UserSessionManager.(class)=org.apache.tomcat.servlets.session.SimpleSessionManager
+
+# Loader for web.xml - you can have your own custom class using a more efficient
+# or hardcoded.
+org.apache.coyote.servlet.ContextPreinitListener.(class)=org.apache.coyote.servlet.webxml.TomcatLiteWebXmlConfig
+
+# Connector class
+org.apache.coyote.servlet.Connector.(class)=org.apache.coyote.servlet.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
+
+
+++ /dev/null
-/*
- * 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<String, B2CConverter> encoders =
- new HashMap<String, B2CConverter>();
-
-
- /**
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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.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(StringBuilder 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
+++ /dev/null
-en=ISO-8859-1
-fr=ISO-8859-1
+++ /dev/null
-/*
- * 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() {
-
- StringBuilder sb = new StringBuilder("ClientAbortException: ");
- if (message != null) {
- sb.append(message);
- if (throwable != null) {
- sb.append(": ");
- }
- }
- if (throwable != null) {
- sb.append(throwable.toString());
- }
- return (sb.toString());
-
- }
-
-
-}
+++ /dev/null
-/*
- * 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 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.
- *
- * Currently we have lots of deps on coyote Request, but I plan to
- * change this and allow other HTTP implementations - like MINA, the
- * experimental async connector, etc. Most important will be
- * different support for IO - i.e. a more non-blocking mode.
- * We'll probably keep MessageBytes as wrappers for request/res
- * properties.
- *
- * This interface has no dep on coyote.
- *
- */
-public interface Connector {
-
- public void setDaemon(boolean b);
-
- public void start() throws IOException;
-
- public void stop() throws Exception;
-
- /**
- * 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);
-
- void initRequest(HttpServletRequest req, HttpServletResponse res);
-
- 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;
-}
+++ /dev/null
-/*
- * 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 javax.servlet.ServletContext;
-
-/**
- * Tomcat-lite specific interface ( could be moved to addons ).
- * This class will be called before initialization - implementations
- * can add servlets, filters, etc. In particular web.xml parsing
- * is done implementing this interface.
- *
- * On a small server you could remove web.xml support to reduce
- * footprint, and either hardcode this class or use properties.
- * Same if you already use a framework and you inject settings
- * or use framework's registry (OSGI).
- *
- * @author Costin Manolache
- */
-public interface ContextPreinitListener {
-
- public void preInit(ServletContext ctx);
-}
+++ /dev/null
-/*
- * Copyright 2009 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.lite;
-
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.Servlet;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-/**
- * Wraps the list of filters for the current request. One instance
- * associated with each RequestImpl, reused.
- *
- * Populated by the mapper ( WebappFilterMapper for example ), which
- * determines the filters for the current request.
- *
- * Not thread safe.
- */
-public final class FilterChainImpl implements FilterChain {
- private List<FilterConfigImpl> filters = new ArrayList<FilterConfigImpl>();
-
-
- /**
- * The int which is used to maintain the current position
- * in the filter chain.
- */
- private int pos = 0;
-
- /**
- * The servlet instance to be executed by this chain.
- */
- private Servlet servlet = null;
-
-
- private ServletConfigImpl wrapper;
-
-
- public FilterChainImpl() {
- super();
- }
-
-
- /**
- * Invoke the next filter in this chain, passing the specified request
- * and response. If there are no more filters in this chain, invoke
- * the <code>service()</code> method of the servlet itself.
- *
- * @param request The servlet request we are processing
- * @param response The servlet response we are creating
- *
- * @exception IOException if an input/output error occurs
- * @exception ServletException if a servlet exception occurs
- */
- public void doFilter(ServletRequest request, ServletResponse response)
- throws IOException, ServletException {
-
-
- // Call the next filter if there is one
- if (pos < filters.size()) {
- FilterConfigImpl filterConfig = filters.get(pos++);
- Filter filter = null;
- try {
- filter = filterConfig.getFilter();
- filter.doFilter(request, response, this);
- } catch (IOException e) {
- throw e;
- } catch (ServletException e) {
- throw e;
- } catch (RuntimeException e) {
- throw e;
- } catch (Throwable e) {
- e.printStackTrace();
- throw new ServletException("Throwable", e);
- }
- return;
- }
-
- // We fell off the end of the chain -- call the servlet instance
- try {
- if (servlet != null)
- servlet.service(request, response);
- } catch (IOException e) {
- throw e;
- } catch (ServletException e) {
- throw e;
- } catch (RuntimeException e) {
- throw e;
- } catch (Throwable e) {
- throw new ServletException("Throwable", e);
- }
- }
-
-
- // -------------------------------------------------------- Package Methods
-
-
-
- /**
- * Add a filter to the set of filters that will be executed in this chain.
- *
- * @param filterConfig The FilterConfig for the servlet to be executed
- */
- public void addFilter(FilterConfigImpl filterConfig) {
- filters.add(filterConfig);
- }
-
-
- /**
- * Release references to the filters and wrapper executed by this chain.
- */
- public void release() {
- filters.clear();
- pos = 0;
- servlet = null;
- }
-
-
- /**
- * Set the servlet that will be executed at the end of this chain.
- * Set by the mapper filter
- */
- public void setServlet(ServletConfigImpl wrapper, Servlet servlet) {
- this.wrapper = wrapper;
- this.servlet = servlet;
- }
-
- // ------ Getters for information ------------
-
- public int getSize() {
- return filters.size();
- }
-
- public FilterConfigImpl getFilter(int i) {
- return filters.get(i);
- }
-
- public Servlet getServlet() {
- return servlet;
- }
-
- public ServletConfigImpl getServletConfig() {
- return wrapper;
- }
-
- public int getPos() {
- return pos;
- }
-}
+++ /dev/null
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.tomcat.lite;
-
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import javax.servlet.DispatcherType;
-import javax.servlet.Filter;
-import javax.servlet.FilterConfig;
-import javax.servlet.FilterRegistration;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.FilterRegistration.Dynamic;
-
-import org.apache.tomcat.servlets.util.Enumerator;
-
-
-/**
- * A Filter is configured in web.xml by:
- * - name - used in mappings
- * - className - used to instantiate the filter
- * - init params
- * - other things not used in the servlet container ( icon, descr, etc )
- *
- * Alternatively, in API mode you can pass the actual filter.
- *
- * @see ServletConfigImpl
- */
-public final class FilterConfigImpl implements FilterConfig, FilterRegistration {
-
- DynamicFilterRegistration dynamic = new DynamicFilterRegistration();
-
- public FilterConfigImpl(ServletContextImpl context) {
- this.ctx = context;
- }
-
- boolean asyncSupported;
-
- private ServletContextImpl ctx = null;
-
- /**
- * The application Filter we are configured for.
- */
- private transient Filter filter = null;
-
- String descryption;
-
- private String filterName;
-
- private String filterClassName;
-
- Map<String, String> initParams;
-
- private Class<? extends Filter> filterClass;
-
- public void setData(String filterName, String filterClass,
- Map<String, String> params) {
- this.filterName = filterName;
- this.filterClassName = filterClass;
- this.initParams = params;
- }
-
- public void setFilter(Filter f) {
- filter = f;
- }
-
- public String getFilterName() {
- return filterName;
- }
-
- public void setFilterClass(Class<? extends Filter> filterClass2) {
- this.filterClass = filterClass2;
- }
-
-
- public String getInitParameter(String name) {
- if (initParams == null) return null;
- return initParams.get(name);
- }
-
- /**
- * Return an <code>Enumeration</code> of the names of the initialization
- * parameters for this Filter.
- */
- public Enumeration getInitParameterNames() {
- if (initParams == null)
- return (new Enumerator(new ArrayList()));
- else
- return (new Enumerator(initParams.keySet()));
- }
-
-
- /**
- * Return the ServletContext of our associated web application.
- */
- public ServletContext getServletContext() {
- return ctx;
- }
-
- /**
- * Return the application Filter we are configured for.
- */
- public Filter createFilter() throws ClassCastException, ClassNotFoundException,
- IllegalAccessException, InstantiationException, ServletException {
-
- // Return the existing filter instance, if any
- if (filter != null)
- return filter;
-
- ClassLoader classLoader = ctx.getClassLoader();
-
- ClassLoader oldCtxClassLoader =
- Thread.currentThread().getContextClassLoader();
- if (classLoader != oldCtxClassLoader) {
- Thread.currentThread().setContextClassLoader(classLoader);
- }
- try {
- if (filterClass == null) {
- filterClass = (Class<? extends Filter>) classLoader.loadClass(filterClassName);
- }
- this.filter = (Filter) filterClass.newInstance();
- } finally {
- if (classLoader != oldCtxClassLoader) {
- Thread.currentThread().setContextClassLoader(oldCtxClassLoader);
- }
- }
-
- // TODO: resource injection
-
- return filter;
- }
-
- public Filter getFilter() throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException {
- Filter filter = createFilter();
- filter.init(this);
- return (this.filter);
- }
-
-
- /**
- * Release the Filter instance associated with this FilterConfig,
- * if there is one.
- */
- public void release() {
- if (this.filter != null){
- filter.destroy();
- }
- this.filter = null;
- }
-
-
- @Override
- public void addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes,
- boolean isMatchAfter,
- String... servletNames) {
- if (ctx.startDone) {
- // Use the context method instead of the servlet API to
- // add mappings after context init.
- throw new IllegalStateException();
- }
- ArrayList<String> dispatchers = new ArrayList<String>();
- for (DispatcherType dt: dispatcherTypes) {
- dispatchers.add(dt.name());
- }
- for (String servletName: servletNames) {
- ctx.getFilterMapper().addMapping(getFilterName(),
- null, servletName, (String[]) dispatchers.toArray(), isMatchAfter);
- }
- }
-
-
- @Override
- public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes,
- boolean isMatchAfter,
- String... urlPatterns) {
- if (ctx.startDone) {
- // Use the context method instead of the servlet API to
- // add mappings after context init.
- throw new IllegalStateException();
- }
- ArrayList<String> dispatchers = new ArrayList<String>();
- for (DispatcherType dt: dispatcherTypes) {
- dispatchers.add(dt.name());
- }
- for (String url: urlPatterns) {
- ctx.getFilterMapper().addMapping(getFilterName(),
- url, null, (String[]) dispatchers.toArray(), isMatchAfter);
- }
- }
-
-
- @Override
- public boolean setInitParameter(String name, String value)
- throws IllegalArgumentException, IllegalStateException {
- return ServletContextImpl.setInitParameter(ctx, initParams,
- name, value);
- }
-
-
- @Override
- public Set<String> setInitParameters(Map<String, String> initParameters)
- throws IllegalArgumentException, IllegalStateException {
- return ServletContextImpl.setInitParameters(ctx, initParams,
- initParameters);
- }
-
- public Dynamic getDynamic() {
- return dynamic;
- }
-
- public class DynamicFilterRegistration implements Dynamic {
-
-
- @Override
- public void addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes,
- boolean isMatchAfter,
- String... servletNames) {
- FilterConfigImpl.this.addMappingForServletNames(dispatcherTypes, isMatchAfter, servletNames);
- }
-
-
- @Override
- public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes,
- boolean isMatchAfter,
- String... urlPatterns) {
- FilterConfigImpl.this.addMappingForUrlPatterns(dispatcherTypes, isMatchAfter, urlPatterns);
- }
-
-
- @Override
- public boolean setInitParameter(String name, String value)
- throws IllegalArgumentException, IllegalStateException {
- return ServletContextImpl.setInitParameter(ctx, initParams,
- name, value);
- }
-
-
- @Override
- public Set<String> setInitParameters(Map<String, String> initParameters)
- throws IllegalArgumentException, IllegalStateException {
- return ServletContextImpl.setInitParameters(ctx, initParams,
- initParameters);
- }
-
-
- @Override
- public void setAsyncSupported(boolean isAsyncSupported)
- throws IllegalStateException {
- asyncSupported = isAsyncSupported;
- }
-
-
- public void setDescription(String description)
- throws IllegalStateException {
- FilterConfigImpl.this.descryption = description;
- }
-
- @Override
- public Collection<String> getUrlPatternMappings() {
- // implement me
- return null;
- }
-
- @Override
- public Collection<String> getServletNameMappings() {
- // implement me
- return null;
- }
-
- @Override
- public Map<String, String> getInitParameters() {
- // implement me
- return null;
- }
-
- @Override
- public String getInitParameter(String name) {
- if (initParams == null) return null;
- return initParams.get(name);
- }
-
- @Override
- public String getClassName() {
- // implement me
- return null;
- }
-
- @Override
- public String getName() {
- // implement me
- return null;
- }
- }
-
- @Override
- public Collection<String> getUrlPatternMappings() {
- // implement me
- return null;
- }
-
- @Override
- public Collection<String> getServletNameMappings() {
- // implement me
- return null;
- }
-
- @Override
- public Map<String, String> getInitParameters() {
- // implement me
- return null;
- }
-
- @Override
- public String getClassName() {
- // implement me
- return null;
- }
-
- @Override
- public String getName() {
- // implement me
- return null;
- }
-
-}
+++ /dev/null
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tomcat.lite;
-
-
-import java.io.InputStream;
-import java.util.Locale;
-import java.util.Properties;
-
-
-
-/**
- * One instance per Context. Holds the
- *
- * Utility class that attempts to map from a Locale to the corresponding
- * character set to be used for interpreting input text (or generating
- * output text) when the Content-Type header does not include one. You
- * can customize the behavior of this class by modifying the mapping data
- * it loads, or by subclassing it (to change the algorithm) and then using
- * your own version for a particular web application.
- *
- * @author Craig R. McClanahan
- */
-public class Locale2Charset {
-
-
- // ---------------------------------------------------- Manifest Constants
-
-
- /**
- * Default properties resource name.
- */
- public static final String DEFAULT_RESOURCE =
- "/org/apache/tomcat/lite/CharsetMapperDefault.properties";
-
-
-
- // ---------------------------------------------------------- Constructors
-
-
- /**
- * Construct a new CharsetMapper using the default properties resource.
- */
- public Locale2Charset() {
- String name = DEFAULT_RESOURCE;
- if (defaultMap == null) { // once !
- try {
- defaultMap = new Properties();
- InputStream stream =
- this.getClass().getResourceAsStream(name);
- defaultMap.load(stream);
- stream.close();
- } catch (Throwable t) {
- throw new IllegalArgumentException(t.toString());
- }
- }
- map = defaultMap;
- }
-
-
- // ---------------------------------------------------- Instance Variables
-
-
- private static Properties defaultMap; // shared for all apps
-
- /**
- * The mapping properties that have been initialized from the specified or
- * default properties resource.
- */
- private Properties map;
-
-
- // ------------------------------------------------------- Public Methods
-
-
- /**
- * Calculate the name of a character set to be assumed, given the specified
- * Locale and the absence of a character set specified as part of the
- * content type header.
- *
- * @param locale The locale for which to calculate a character set
- */
- public String getCharset(Locale locale) {
- // Match full language_country_variant first, then language_country,
- // then language only
- String charset = map.getProperty(locale.toString());
- if (charset == null) {
- charset = map.getProperty(locale.getLanguage() + "_"
- + locale.getCountry());
- if (charset == null) {
- charset = map.getProperty(locale.getLanguage());
- }
- }
- return (charset);
- }
-
-
- /**
- * The deployment descriptor can have a
- * locale-encoding-mapping-list element which describes the
- * webapp's desired mapping from locale to charset. This method
- * gets called when processing the web.xml file for a context
- *
- * @param locale The locale for a character set
- * @param charset The charset to be associated with the locale
- */
- public void addCharsetMapping(String locale, String charset) {
- if (map == defaultMap) {
- // new copy, don't modify original
- map = new Properties(defaultMap);
- }
- map.put(locale, charset);
- }
-}
+++ /dev/null
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.tomcat.lite;
-
-
-import java.util.HashMap;
-import java.util.Map;
-
-
-/**
- * Extended implementation of <strong>HashMap</strong> that includes a
- * <code>locked</code> property. This class can be used to safely expose
- * Catalina internal parameter map objects to user classes without having
- * to clone them in order to avoid modifications. When first created, a
- * <code>ParmaeterMap</code> instance is not locked.
- *
- * @author Craig R. McClanahan
- * @version $Revision$ $Date$
- */
-
-public final class ParameterMap extends HashMap {
-
-
- // ----------------------------------------------------------- Constructors
-
-
- /**
- * Construct a new, empty map with the default initial capacity and
- * load factor.
- */
- public ParameterMap() {
-
- super();
-
- }
-
-
- /**
- * Construct a new, empty map with the specified initial capacity and
- * default load factor.
- *
- * @param initialCapacity The initial capacity of this map
- */
- public ParameterMap(int initialCapacity) {
-
- super(initialCapacity);
-
- }
-
-
- /**
- * Construct a new, empty map with the specified initial capacity and
- * load factor.
- *
- * @param initialCapacity The initial capacity of this map
- * @param loadFactor The load factor of this map
- */
- public ParameterMap(int initialCapacity, float loadFactor) {
-
- super(initialCapacity, loadFactor);
-
- }
-
-
- /**
- * Construct a new map with the same mappings as the given map.
- *
- * @param map Map whose contents are dupliated in the new map
- */
- public ParameterMap(Map map) {
-
- super(map);
-
- }
-
-
- // ------------------------------------------------------------- Properties
-
-
- /**
- * The current lock state of this parameter map.
- */
- private boolean locked = false;
-
-
- /**
- * Return the locked state of this parameter map.
- */
- public boolean isLocked() {
-
- return (this.locked);
-
- }
-
-
- /**
- * Set the locked state of this parameter map.
- *
- * @param locked The new locked state
- */
- public void setLocked(boolean locked) {
-
- this.locked = locked;
-
- }
-
-
- // --------------------------------------------------------- Public Methods
-
-
-
- /**
- * Remove all mappings from this map.
- *
- * @exception IllegalStateException if this map is currently locked
- */
- public void clear() {
-
- if (locked)
- throw new IllegalStateException
- ("parameterMap.locked");
- super.clear();
-
- }
-
-
- /**
- * Associate the specified value with the specified key in this map. If
- * the map previously contained a mapping for this key, the old value is
- * replaced.
- *
- * @param key Key with which the specified value is to be associated
- * @param value Value to be associated with the specified key
- *
- * @return The previous value associated with the specified key, or
- * <code>null</code> if there was no mapping for key
- *
- * @exception IllegalStateException if this map is currently locked
- */
- public Object put(Object key, Object value) {
-
- if (locked)
- throw new IllegalStateException
- ("parameterMap.locked");
- return (super.put(key, value));
-
- }
-
-
- /**
- * Copy all of the mappings from the specified map to this one. These
- * mappings replace any mappings that this map had for any of the keys
- * currently in the specified Map.
- *
- * @param map Mappings to be stored into this map
- *
- * @exception IllegalStateException if this map is currently locked
- */
- public void putAll(Map map) {
-
- if (locked)
- throw new IllegalStateException
- ("parameterMap.locked");
- super.putAll(map);
-
- }
-
-
- /**
- * Remove the mapping for this key from the map if present.
- *
- * @param key Key whose mapping is to be removed from the map
- *
- * @return The previous value associated with the specified key, or
- * <code>null</code> if there was no mapping for that key
- *
- * @exception IllegalStateException if this map is currently locked
- */
- public Object remove(Object key) {
-
- if (locked)
- throw new IllegalStateException
- ("parameterMap.locked");
- return (super.remove(key));
-
- }
-
-
-}
+++ /dev/null
-/*
- * 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.PrintWriter;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.Servlet;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletRequestWrapper;
-import javax.servlet.ServletResponse;
-import javax.servlet.ServletResponseWrapper;
-import javax.servlet.UnavailableException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.tomcat.util.buf.CharChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.mapper.MappingData;
-
-/**
- *
- */
-public final class RequestDispatcherImpl implements RequestDispatcher {
- /**
- * The request attribute under which the original servlet path is stored
- * on an forwarded dispatcher request.
- */
- public static final String FORWARD_SERVLET_PATH_ATTR =
- "javax.servlet.forward.servlet_path";
-
-
- /**
- * The request attribute under which the original query string is stored
- * on an forwarded dispatcher request.
- */
- public static final String FORWARD_QUERY_STRING_ATTR =
- "javax.servlet.forward.query_string";
-
- /**
- * The request attribute under which the original request URI is stored
- * on an forwarded dispatcher request.
- */
- public static final String FORWARD_REQUEST_URI_ATTR =
- "javax.servlet.forward.request_uri";
-
-
- /**
- * The request attribute under which the original context path is stored
- * on an forwarded dispatcher request.
- */
- public static final String FORWARD_CONTEXT_PATH_ATTR =
- "javax.servlet.forward.context_path";
-
-
- /**
- * The request attribute under which the original path info is stored
- * on an forwarded dispatcher request.
- */
- public static final String FORWARD_PATH_INFO_ATTR =
- "javax.servlet.forward.path_info";
-
- /**
- * The request attribute under which we store the servlet name on a
- * named dispatcher request.
- */
- public static final String NAMED_DISPATCHER_ATTR =
- "org.apache.catalina.NAMED";
-
- /**
- * The request attribute under which the request URI of the included
- * servlet is stored on an included dispatcher request.
- */
- public static final String INCLUDE_REQUEST_URI_ATTR =
- "javax.servlet.include.request_uri";
-
-
- /**
- * The request attribute under which the context path of the included
- * servlet is stored on an included dispatcher request.
- */
- public static final String INCLUDE_CONTEXT_PATH_ATTR =
- "javax.servlet.include.context_path";
-
-
- /**
- * The request attribute under which the path info of the included
- * servlet is stored on an included dispatcher request.
- */
- public static final String INCLUDE_PATH_INFO_ATTR =
- "javax.servlet.include.path_info";
-
-
- /**
- * The request attribute under which the servlet path of the included
- * servlet is stored on an included dispatcher request.
- */
- public static final String INCLUDE_SERVLET_PATH_ATTR =
- "javax.servlet.include.servlet_path";
-
-
- /**
- * The request attribute under which the query string of the included
- * servlet is stored on an included dispatcher request.
- */
- public static final String INCLUDE_QUERY_STRING_ATTR =
- "javax.servlet.include.query_string";
-
- /**
- * The request attribute under which we expose the value of the
- * <code><jsp-file></code> value associated with this servlet,
- * if any.
- */
- public static final String JSP_FILE_ATTR =
- "org.apache.catalina.jsp_file";
-
-
- // ----------------------------------------------------- Instance Variables
-
- private static Logger log = Logger.getLogger(RequestDispatcherImpl.class.getName());
-
- private ServletContextImpl ctx = null;
-
- /**
- * The servlet name for a named dispatcher.
- */
- private String name = null;
-
- // Path for a path dispatcher
- private String path;
-
- /**
- * MappingData object - per thread for buffering.
- */
- private transient ThreadLocal localMappingData = new ThreadLocal();
-
- /*
- OrigRequest(ServletRequestImpl) -> include/forward * -> this include
-
- On the path: user-defined RequestWrapper or our ServletRequestWrapper
-
- include() is called with a RequestWrapper(->...->origRequest) or origRequest
-
- Based on params, etc -> we wrap the req / response in ServletRequestWrapper,
- call filters+servlet. Inside, the req can be wrapped again in
- userReqWrapper, and other include called.
-
-
- */
-
- /**
- * The outermost request that will be passed on to the invoked servlet.
- */
- private ServletRequest outerRequest = null;
-
- /**
- * The outermost response that will be passed on to the invoked servlet.
- */
- private ServletResponse outerResponse = null;
-
- /**
- * The request wrapper we have created and installed (if any).
- */
- private ServletRequest wrapRequest = null;
-
- /**
- * The response wrapper we have created and installed (if any).
- */
- private ServletResponse wrapResponse = null;
-
- // Parameters used when constructing the dispatcvher
- /**
- * The extra path information for this RequestDispatcher.
- */
- private String pathInfo = null;
- /**
- * The query string parameters for this RequestDispatcher.
- */
- private String queryString = null;
- /**
- * The request URI for this RequestDispatcher.
- */
- private String requestURI = null;
- /**
- * The servlet path for this RequestDispatcher.
- */
- private String servletPath = null;
-
- //
- private String origServletPath = null;
-
- /**
- * The Wrapper associated with the resource that will be forwarded to
- * or included.
- */
- private ServletConfigImpl wrapper = null;
-
- private Servlet servlet;
-
- /** Named dispatcher
- */
- public RequestDispatcherImpl(ServletConfigImpl wrapper, String name) {
- this.wrapper = wrapper;
- this.name = name;
- this.ctx = (ServletContextImpl) wrapper.getServletContext();
-
- }
-
- public RequestDispatcherImpl(ServletContextImpl ctx, String path) {
- this.path = path;
- this.ctx = ctx;
- }
-
-
-
- /**
- * Forward this request and response to another resource for processing.
- * Any runtime exception, IOException, or ServletException thrown by the
- * called servlet will be propogated to the caller.
- *
- * @param request The servlet request to be forwarded
- * @param response The servlet response to be forwarded
- *
- * @exception IOException if an input/output error occurs
- * @exception ServletException if a servlet exception occurs
- */
- public void forward(ServletRequest request, ServletResponse response)
- throws ServletException, IOException
- {
- // Reset any output that has been buffered, but keep headers/cookies
- if (response.isCommitted()) {
- throw new IllegalStateException("forward(): response.isComitted()");
- }
-
- try {
- response.resetBuffer();
- } catch (IllegalStateException e) {
- throw e;
- }
-
- // Set up to handle the specified request and response
- setup(request, response, false);
-
- // Identify the HTTP-specific request and response objects (if any)
- HttpServletRequest hrequest = (HttpServletRequest) request;
-
- ServletRequestWrapperImpl wrequest =
- (ServletRequestWrapperImpl) wrapRequest();
-
-
- if (name != null) {
- wrequest.setRequestURI(hrequest.getRequestURI());
- wrequest.setContextPath(hrequest.getContextPath());
- wrequest.setServletPath(hrequest.getServletPath());
- wrequest.setPathInfo(hrequest.getPathInfo());
- wrequest.setQueryString(hrequest.getQueryString());
-
-
- } else { // path based
- mapPath();
- if (wrapper == null) {
- throw new ServletException("Forward not found " +
- path);
- }
- String contextPath = ctx.getContextPath();
- if (hrequest.getAttribute(FORWARD_REQUEST_URI_ATTR) == null) {
- wrequest.setAttribute(FORWARD_REQUEST_URI_ATTR,
- hrequest.getRequestURI());
- wrequest.setAttribute(FORWARD_CONTEXT_PATH_ATTR,
- hrequest.getContextPath());
- wrequest.setAttribute(FORWARD_SERVLET_PATH_ATTR,
- hrequest.getServletPath());
- wrequest.setAttribute(FORWARD_PATH_INFO_ATTR,
- hrequest.getPathInfo());
- wrequest.setAttribute(FORWARD_QUERY_STRING_ATTR,
- hrequest.getQueryString());
- }
-
- wrequest.setContextPath(contextPath);
- wrequest.setRequestURI(requestURI);
- wrequest.setServletPath(servletPath);
- wrequest.setPathInfo(pathInfo);
- if (queryString != null) {
- wrequest.setQueryString(queryString);
- wrequest.setQueryParams(queryString);
- }
- }
- processRequest(outerRequest, outerResponse);
-
- wrequest.recycle();
- unwrapRequest();
-
- // This is not a real close in order to support error processing
-// if ( log.isDebugEnabled() )
-// log.debug(" Disabling the response for futher output");
-
- if (response instanceof ServletResponseImpl) {
- ((ServletResponseImpl) response).flushBuffer();
- ((ServletResponseImpl) response).setSuspended(true);
- } else {
- // Servlet SRV.6.2.2. The Resquest/Response may have been wrapped
- // and may no longer be instance of RequestFacade
- if (log.isLoggable(Level.FINE)){
- log.fine( " The Response is vehiculed using a wrapper: "
- + response.getClass().getName() );
- }
-
- // Close anyway
- try {
- PrintWriter writer = response.getWriter();
- writer.close();
- } catch (IllegalStateException e) {
- try {
- ServletOutputStream stream = response.getOutputStream();
- stream.close();
- } catch (IllegalStateException f) {
- ;
- } catch (IOException f) {
- ;
- }
- } catch (IOException e) {
- ;
- }
- }
- }
-
-
-
- /**
- * Include the response from another resource in the current response.
- * Any runtime exception, IOException, or ServletException thrown by the
- * called servlet will be propogated to the caller.
- *
- * @param request The servlet request that is including this one
- * @param response The servlet response to be appended to
- *
- * @exception IOException if an input/output error occurs
- * @exception ServletException if a servlet exception occurs
- */
- public void include(ServletRequest request, ServletResponse response)
- throws ServletException, IOException
- {
-
- // Set up to handle the specified request and response
- setup(request, response, true);
-
- // Create a wrapped response to use for this request
- // this actually gets inserted somewhere in the chain - it's not
- // the last one, but first non-user response
- wrapResponse();
- ServletRequestWrapperImpl wrequest =
- (ServletRequestWrapperImpl) wrapRequest();
-
-
- // Handle an HTTP named dispatcher include
- if (name != null) {
- wrequest.setAttribute(NAMED_DISPATCHER_ATTR, name);
- if (servletPath != null) wrequest.setServletPath(servletPath);
- wrequest.setAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR,
- new Integer(WebappFilterMapper.INCLUDE));
- wrequest.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR,
- origServletPath);
- } else {
- mapPath();
- String contextPath = ctx.getContextPath();
- if (requestURI != null)
- wrequest.setAttribute(INCLUDE_REQUEST_URI_ATTR,
- requestURI);
- if (contextPath != null)
- wrequest.setAttribute(INCLUDE_CONTEXT_PATH_ATTR,
- contextPath);
- if (servletPath != null)
- wrequest.setAttribute(INCLUDE_SERVLET_PATH_ATTR,
- servletPath);
- if (pathInfo != null)
- wrequest.setAttribute(INCLUDE_PATH_INFO_ATTR,
- pathInfo);
- if (queryString != null) {
- wrequest.setAttribute(INCLUDE_QUERY_STRING_ATTR,
- queryString);
- wrequest.setQueryParams(queryString);
- }
-
- wrequest.setAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR,
- new Integer(WebappFilterMapper.INCLUDE));
- wrequest.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR,
- origServletPath);
- }
-
- invoke(outerRequest, outerResponse);
-
- wrequest.recycle();
- unwrapRequest();
- unwrapResponse();
- }
-
-
- // -------------------------------------------------------- Private Methods
-
- public void mapPath() {
- if (path == null || servletPath != null) return;
-
- // Retrieve the thread local URI, used for mapping
- // TODO: recycle RequestDispatcher stack and associated objects
- // instead of this object
-
- // Retrieve the thread local mapping data
- MappingData mappingData = (MappingData) localMappingData.get();
- if (mappingData == null) {
- mappingData = new MappingData();
- localMappingData.set(mappingData);
- }
-
- // Get query string
- int pos = path.indexOf('?');
- if (pos >= 0) {
- queryString = path.substring(pos + 1);
- } else {
- pos = path.length();
- }
-
- // Map the URI
- MessageBytes uriMB = MessageBytes.newInstance();
- CharChunk charBuffer = new CharChunk();
- //mappingData.localURIBytes;
- uriMB.recycle();
- //CharChunk uriCC = uriMB.getCharChunk();
- try {
- /*
- * Ignore any trailing path params (separated by ';') for mapping
- * purposes.
- * This is sometimes broken - path params can be on any path
- * component, not just last.
- */
- int semicolon = path.indexOf(';');
- if (pos >= 0 && semicolon > pos) {
- semicolon = -1;
- }
- if (ctx.getContextPath().length() > 1 ) {
- charBuffer.append(ctx.getContextPath());
- }
- charBuffer.append(path, 0,
- semicolon > 0 ? semicolon : pos);
-
- // Wrap the buffer
- uriMB.setChars(charBuffer.getBuffer(),
- charBuffer.getOffset(),
- charBuffer.getLength());
-
- // TODO: make charBuffer part of request or something
- ctx.getMapper().map(uriMB, mappingData);
-
- // at least default wrapper must be returned
-
- /*
- * Append any trailing path params (separated by ';') that were
- * ignored for mapping purposes, so that they're reflected in the
- * RequestDispatcher's requestURI
- */
- if (semicolon > 0) {
- // I don't think this will be used in future
- charBuffer.append(path,
- semicolon, pos - semicolon);
- }
- } catch (Exception e) {
- log.log(Level.SEVERE, "getRequestDispatcher()", e);
- }
-
- wrapper = (ServletConfigImpl) mappingData.wrapper;
- servletPath = mappingData.wrapperPath.toString();
- pathInfo = mappingData.pathInfo.toString();
-
- mappingData.recycle();
-
- }
-
-
- /**
- * Prepare the request based on the filter configuration.
- * @param request The servlet request we are processing
- * @param response The servlet response we are creating
- *
- * @exception IOException if an input/output error occurs
- * @exception ServletException if a servlet error occurs
- */
- private void processRequest(ServletRequest request,
- ServletResponse response)
- throws IOException, ServletException {
- Integer disInt =
- (Integer) request.getAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR);
- if (disInt != null) {
- if (disInt.intValue() != WebappFilterMapper.ERROR) {
- outerRequest.setAttribute
- (WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR,
- origServletPath);
- outerRequest.setAttribute
- (WebappFilterMapper.DISPATCHER_TYPE_ATTR,
- new Integer(WebappFilterMapper.FORWARD));
- }
- invoke(outerRequest, response);
- }
-
- }
-
-
-
-
- /**
- * Ask the resource represented by this RequestDispatcher to process
- * the associated request, and create (or append to) the associated
- * response.
- * <p>
- * <strong>IMPLEMENTATION NOTE</strong>: This implementation assumes
- * that no filters are applied to a forwarded or included resource,
- * because they were already done for the original request.
- *
- * @param request The servlet request we are processing
- * @param response The servlet response we are creating
- *
- * @exception IOException if an input/output error occurs
- * @exception ServletException if a servlet error occurs
- */
- private void invoke(ServletRequest request, ServletResponse response)
- throws IOException, ServletException {
-
- // Checking to see if the context classloader is the current context
- // classloader. If it's not, we're saving it, and setting the context
- // classloader to the Context classloader
- ClassLoader oldCCL = Thread.currentThread().getContextClassLoader();
- ClassLoader contextClassLoader = ctx.getClassLoader();
-
- if (oldCCL != contextClassLoader) {
- Thread.currentThread().setContextClassLoader(contextClassLoader);
- } else {
- oldCCL = null;
- }
-
- // Initialize local variables we may need
- HttpServletResponse hresponse = (HttpServletResponse) response;
- IOException ioException = null;
- ServletException servletException = null;
- RuntimeException runtimeException = null;
-
- servletException = allocateServlet(hresponse, servletException);
-
- // Get the FilterChain Here
- WebappFilterMapper factory =
- ((ServletContextImpl)wrapper.getServletContext()).getFilterMapper();
-
- FilterChainImpl filterChain = factory.createFilterChain(request,
- wrapper,
- servlet);
-
- // Call the service() method for the allocated servlet instance
- try {
- String jspFile = wrapper.getJspFile();
- if (jspFile != null)
- request.setAttribute(JSP_FILE_ATTR, jspFile);
- else
- request.removeAttribute(JSP_FILE_ATTR);
- // for includes/forwards
- if ((servlet != null) && (filterChain != null)) {
- filterChain.doFilter(request, response);
- }
- } catch (IOException e) {
- ctx.getLogger().log(Level.WARNING, "RequestDispatcherImpl error " +
- wrapper.getServletName(), e);
- ioException = e;
- } catch (UnavailableException e) {
- ctx.getLogger().log(Level.WARNING, "RequestDispatcherImpl error " +
- wrapper.getServletName(), e);
- servletException = e;
- wrapper.unavailable(e);
- } catch (ServletException e) {
- servletException = e;
- } catch (RuntimeException e) {
- ctx.getLogger().log(Level.WARNING, "RequestDispatcherImpl error " +
- wrapper.getServletName(), e);
- runtimeException = e;
- }
- request.removeAttribute(JSP_FILE_ATTR);
-
- // Release the filter chain (if any) for this request
- if (filterChain != null)
- filterChain.release();
-
- servletException = servletDealocate(servletException);
-
- // Reset the old context class loader
- if (oldCCL != null)
- Thread.currentThread().setContextClassLoader(oldCCL);
-
- // Unwrap request/response if needed
- unwrapRequest();
- unwrapResponse();
-
- // Rethrow an exception if one was thrown by the invoked servlet
- if (ioException != null)
- throw ioException;
- if (servletException != null)
- throw servletException;
- if (runtimeException != null)
- throw runtimeException;
-
- }
-
- private ServletException servletDealocate(ServletException servletException)
- {
- if (servlet != null) {
- wrapper.deallocate(servlet);
- }
- return servletException;
- }
-
- private ServletException allocateServlet(HttpServletResponse hresponse,
- ServletException servletException)
- throws IOException
- {
- boolean unavailable = false;
-
- // Check for the servlet being marked unavailable
- if (wrapper.isUnavailable()) {
- ctx.getLogger().log(Level.WARNING, "isUnavailable() " + wrapper.getServletName());
- long available = wrapper.getAvailable();
- if ((available > 0L) && (available < Long.MAX_VALUE))
- hresponse.setDateHeader("Retry-After", available);
- hresponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
- "Unavailable"); // No need to include internal info: wrapper.getServletName();
- unavailable = true;
- }
-
- // Allocate a servlet instance to process this request
- try {
- if (!unavailable) {
- servlet = wrapper.allocate();
- }
- } catch (ServletException e) {
- ctx.getLogger().log(Level.WARNING, "RequestDispatcher: allocate " +
- wrapper.toString());
- servletException = e;
- servlet = null;
- } catch (Throwable e) {
- ctx.getLogger().log(Level.WARNING, "allocate() error " + wrapper.getServletName(), e);
- servletException = new ServletException
- ("Allocate error " + wrapper.getServletName(), e);
- servlet = null;
- }
- return servletException;
- }
-
-
- /**
- * Set up to handle the specified request and response
- *
- * @param request The servlet request specified by the caller
- * @param response The servlet response specified by the caller
- * @param including Are we performing an include() as opposed to
- * a forward()?
- */
- private void setup(ServletRequest request, ServletResponse response,
- boolean including) {
-
- this.outerRequest = request;
- this.outerResponse = response;
- }
-
-
- /**
- * Unwrap the request if we have wrapped it. Not sure how it could end
- * up in the middle.
- */
- private void unwrapRequest() {
- if (wrapRequest == null)
- return;
-
- ServletRequest previous = null;
- ServletRequest current = outerRequest;
- while (current != null) {
- // If we run into the container request we are done
- if (current instanceof ServletRequestImpl)
- break;
-
- // Remove the current request if it is our wrapper
- if (current == wrapRequest) {
- ServletRequest next =
- ((ServletRequestWrapper) current).getRequest();
- if (previous == null)
- outerRequest = next;
- else
- ((ServletRequestWrapper) previous).setRequest(next);
- break;
- }
-
- // Advance to the next request in the chain
- previous = current;
- current = ((ServletRequestWrapper) current).getRequest();
- }
- }
-
-
- /**
- * Unwrap the response if we have wrapped it.
- */
- private void unwrapResponse() {
- if (wrapResponse == null)
- return;
-
- ServletResponse previous = null;
- ServletResponse current = outerResponse;
- while (current != null) {
- // If we run into the container response we are done
- if (current instanceof ServletResponseImpl)
- break;
-
- // Remove the current response if it is our wrapper
- if (current == wrapResponse) {
- ServletResponse next =
- ((ServletResponseWrapper) current).getResponse();
- if (previous == null)
- outerResponse = next;
- else
- ((ServletResponseWrapper) previous).setResponse(next);
- break;
- }
- // Advance to the next response in the chain
- previous = current;
- current = ((ServletResponseWrapper) current).getResponse();
- }
- }
-
-
- /**
- * Create and return a request wrapper that has been inserted in the
- * appropriate spot in the request chain.
- */
- private ServletRequest wrapRequest() {
- // Locate the request we should insert in front of
- ServletRequest previous = null;
- ServletRequest current = outerRequest;
- while (current != null) {
- if (!(current instanceof ServletRequestWrapper))
- break;
- if (current instanceof ServletRequestWrapperImpl)
- break;
- if (current instanceof ServletRequestImpl)
- break;
- // user-specified
- previous = current;
- current = ((ServletRequestWrapper) current).getRequest();
- }
- // now previous will be a user-specified wrapper,
- // and current one of our own wrappers ( deeper in stack )
- // ... current USER_previous USER USER
- // previous is null if the top request is ours.
-
- // Instantiate a new wrapper at this point and insert it in the chain
- ServletRequest wrapper = null;
-
- // Compute a crossContext flag
- boolean crossContext = isCrossContext();
- wrapper =
- new ServletRequestWrapperImpl((HttpServletRequest) current,
- ctx, crossContext);
-
- if (previous == null) {
- // outer becomes the wrapper, includes orig wrapper inside
- outerRequest = wrapper;
- } else {
- // outer remains user-specified sersvlet, delegating to
- // our wrapper, which delegates to real request or our wrapper.
- ((ServletRequestWrapper) previous).setRequest(wrapper);
- }
- wrapRequest = wrapper;
- return (wrapper);
- }
-
- private boolean isCrossContext() {
- boolean crossContext = false;
- if ((outerRequest instanceof ServletRequestWrapperImpl) ||
- (outerRequest instanceof ServletRequestImpl) ||
- (outerRequest instanceof HttpServletRequest)) {
- HttpServletRequest houterRequest =
- (HttpServletRequest) outerRequest;
- Object contextPath =
- houterRequest.getAttribute(INCLUDE_CONTEXT_PATH_ATTR);
- if (contextPath == null) {
- // Forward
- contextPath = houterRequest.getContextPath();
- }
- crossContext = !(ctx.getContextPath().equals(contextPath));
- }
- return crossContext;
- }
-
-
- /**
- * Create and return a response wrapper that has been inserted in the
- * appropriate spot in the response chain.
- *
- * Side effect: updates outerResponse, wrapResponse.
- * The chain is updated with a wrapper below lowest user wrapper
- */
- private ServletResponse wrapResponse() {
- // Locate the response we should insert in front of
- ServletResponse previous = null;
- ServletResponse current = outerResponse;
- while (current != null) {
- if (!(current instanceof ServletResponseWrapper))
- break;
- if (current instanceof ServletResponseImpl)
- break;
- previous = current;
- current = ((ServletResponseWrapper) current).getResponse();
- }
-
- // Instantiate a new wrapper at this point and insert it in the chain
- ServletResponse wrapper =
- new ServletResponseIncludeWrapper(current);
-
- if (previous == null) {
- // outer is ours, we can wrap on top
- outerResponse = wrapper;
- } else {
- // outer is user-specified, leave it alone.
- // we insert ourself below the lowest user-specified response
- ((ServletResponseWrapper) previous).setResponse(wrapper);
- }
- wrapResponse = wrapper;
- return (wrapper);
-
- }
-
-
-}
+++ /dev/null
-/*
- * Copyright 1999-2002,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.tomcat.lite;
-
-import java.io.PrintStream;
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.Stack;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-
-import javax.servlet.MultipartConfigElement;
-import javax.servlet.Servlet;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRegistration;
-import javax.servlet.ServletSecurityElement;
-import javax.servlet.SingleThreadModel;
-import javax.servlet.UnavailableException;
-
-import org.apache.tomcat.addons.UserTemplateClassMapper;
-import org.apache.tomcat.servlets.util.Enumerator;
-import org.apache.tomcat.util.IntrospectionUtils;
-
-/**
- * Based on Wrapper.
- *
- * Standard implementation of the <b>Wrapper</b> interface that represents
- * an individual servlet definition. No child Containers are allowed, and
- * the parent Container must be a Context.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
- */
-@SuppressWarnings("deprecation")
-public class ServletConfigImpl implements ServletConfig, ServletRegistration {
-
- ServletDynamicRegistration dynamic = new ServletDynamicRegistration();
-
- protected boolean asyncSupported;
-
- private static Logger log=
- Logger.getLogger(ServletConfigImpl.class.getName());
-
- private static final String[] DEFAULT_SERVLET_METHODS = new String[] {
- "GET", "HEAD", "POST" };
-
- // TODO: refactor all 'stm' to separate class (not implemented)
- // public static final String SINGLE_THREADED_PROXY =
- // "org.apache.tomcat.servlets.jsp.SingleThreadedProxyServlet";
-
- protected String description;
- protected Map<String, String> initParams = new HashMap<String, String>();
- protected String servletName;
- protected String servletClassName;
- protected String jspFile;
- protected int loadOnStartup = -1;
- protected String runAs;
- protected Map securityRoleRef = new HashMap(); // roleName -> [roleLink]
-
- /**
- * The date and time at which this servlet will become available (in
- * milliseconds since the epoch), or zero if the servlet is available.
- * If this value equals Long.MAX_VALUE, the unavailability of this
- * servlet is considered permanent.
- */
- private transient long available = 0L;
-
- private ServletContextImpl ctx;
-
- /**
- * The (single) initialized instance of this servlet.
- */
- private transient Servlet instance = null;
-
- /**
- * Are we unloading our servlet instance at the moment?
- */
- private transient boolean unloading = false;
-
- private Class servletClass = null;
-
- // Support for SingleThreaded
- /**
- * The count of allocations that are currently active (even if they
- * are for the same instance, as will be true on a non-STM servlet).
- */
- private transient int countAllocated = 0;
-
- private transient boolean singleThreadModel = false;
- /**
- * Stack containing the STM instances.
- */
- private transient Stack instancePool = null;
-
-
- // Statistics
- private transient long loadTime=0;
- private transient int classLoadTime=0;
-
- // ------------------------------------------------------------- Properties
- public ServletConfigImpl(ServletContextImpl ctx, String name,
- String classname) {
- this.servletName = name;
- this.servletClassName = classname;
- this.ctx = ctx;
- ctx.facade.notifyAdd(this);
- }
-
- /**
- * Return the available date/time for this servlet, in milliseconds since
- * the epoch. If this date/time is Long.MAX_VALUE, it is considered to mean
- * that unavailability is permanent and any request for this servlet will return
- * an SC_NOT_FOUND error. If this date/time is in the future, any request for
- * this servlet will return an SC_SERVICE_UNAVAILABLE error. If it is zero,
- * the servlet is currently available.
- */
- public long getAvailable() {
- return (this.available);
- }
-
-
- /**
- * Set the available date/time for this servlet, in milliseconds since the
- * epoch. If this date/time is Long.MAX_VALUE, it is considered to mean
- * that unavailability is permanent and any request for this servlet will return
- * an SC_NOT_FOUND error. If this date/time is in the future, any request for
- * this servlet will return an SC_SERVICE_UNAVAILABLE error.
- *
- * @param available The new available date/time
- */
- public void setAvailable(long available) {
-
- long oldAvailable = this.available;
- if (available > System.currentTimeMillis())
- this.available = available;
- else
- this.available = 0L;
-
- }
-
-
- /**
- * Return the number of active allocations of this servlet, even if they
- * are all for the same instance (as will be true for servlets that do
- * not implement <code>SingleThreadModel</code>.
- */
- public int getCountAllocated() {
- return (this.countAllocated);
- }
-
- /**
- * Return the jsp-file setting for this servlet.
- */
- public String getJspFile() {
- return jspFile;
- }
-
- public void setJspFile(String s) {
- this.jspFile = s;
- }
-
- /**
- * Return the load-on-startup order value (negative value means
- * load on first call).
- */
- public int getLoadOnStartup() {
- return loadOnStartup;
- }
-
- /**
- * Return the fully qualified servlet class name for this servlet.
- */
- public String getServletClass() {
- return servletClassName;
- }
-
- /**
- * Is this servlet currently unavailable?
- */
- public boolean isUnavailable() {
- if (available == 0L)
- return (false);
- else if (available <= System.currentTimeMillis()) {
- available = 0L;
- return (false);
- } else
- return (true);
-
- }
-
-
- /**
- * Gets the names of the methods supported by the underlying servlet.
- *
- * This is the same set of methods included in the Allow response header
- * in response to an OPTIONS request method processed by the underlying
- * servlet.
- *
- * @return Array of names of the methods supported by the underlying
- * servlet
- */
- public String[] getServletMethods() throws ServletException {
-
- Class servletClazz = loadServlet().getClass();
- if (!javax.servlet.http.HttpServlet.class.isAssignableFrom(
- servletClazz)) {
- return DEFAULT_SERVLET_METHODS;
- }
-
- HashSet allow = new HashSet();
- allow.add("TRACE");
- allow.add("OPTIONS");
-
- Method[] methods = getAllDeclaredMethods(servletClazz);
- for (int i=0; methods != null && i<methods.length; i++) {
- Method m = methods[i];
-
- if (m.getName().equals("doGet")) {
- allow.add("GET");
- allow.add("HEAD");
- } else if (m.getName().equals("doPost")) {
- allow.add("POST");
- } else if (m.getName().equals("doPut")) {
- allow.add("PUT");
- } else if (m.getName().equals("doDelete")) {
- allow.add("DELETE");
- }
- }
-
- String[] methodNames = new String[allow.size()];
- return (String[]) allow.toArray(methodNames);
-
- }
-
-
- // --------------------------------------------------------- Public Methods
-
-
- /**
- * Extract the root cause from a servlet exception.
- *
- * @param e The servlet exception
- */
- public static Throwable getRootCause(ServletException e) {
- Throwable rootCause = e;
- Throwable rootCauseCheck = null;
- // Extra aggressive rootCause finding
- do {
- try {
- rootCauseCheck = (Throwable)IntrospectionUtils.getProperty
- (rootCause, "rootCause");
- if (rootCauseCheck!=null)
- rootCause = rootCauseCheck;
-
- } catch (ClassCastException ex) {
- rootCauseCheck = null;
- }
- } while (rootCauseCheck != null);
- return rootCause;
- }
-
- /**
- * MUST be called before service()
- * This method should be called to get the servlet. After
- * service(), dealocate should be called. This deals with STM and
- * update use counters.
- *
- * Normally called from RequestDispatcher and TomcatLite.
- */
- public Servlet allocate() throws ServletException {
- // If we are currently unloading this servlet, throw an exception
- if (unloading)
- throw new ServletException
- ("allocate() while unloading " + getServletName());
-
- Servlet servlet = null;
- if (instance == null && !singleThreadModel) {
- // never loaded.
- synchronized (this) {
- if (instance == null && !singleThreadModel) {
- try {
- servlet = loadServlet();
- } catch (ServletException e) {
- throw e;
- } catch (Throwable e) {
- throw new ServletException("loadServlet()", e);
- }
- if (servlet != null && !singleThreadModel) {
- setServlet(servlet);
- }
- }
- }
- }
-
- // If not SingleThreadedModel, return the same instance every time
- if (instance != null) {
- countAllocated++;
- return (instance);
- }
-
- // Simpler policy for ST: unbound number of servlets ( can grow to
- // one per thread )
-
- synchronized (instancePool) {
- if (instancePool.isEmpty()) {
- try {
- if (servlet != null) {
- // this is the first invocation
- countAllocated++;
- return servlet;
- }
- countAllocated++;
- Servlet newServlet = loadServlet();
- log.fine("New STM servet " + newServlet + " " +
- countAllocated);
- return newServlet;
- } catch (ServletException e) {
- throw e;
- } catch (Throwable e) {
- throw new ServletException("allocate " + getServletName(),
- e);
- }
- }
- log.fine("Get from pool " + instancePool.size() + " " +
- countAllocated);
- Servlet s = (Servlet) instancePool.pop();
- countAllocated++;
- log.fine("After get " + instancePool.size() + " " + s +
- " " + countAllocated);
- return s;
- }
- }
-
-
- /**
- * MUST be called after service().
- */
- public void deallocate(Servlet servlet) {
- // If not SingleThreadModel, no action is required
- if (!singleThreadModel) {
- countAllocated--;
- return;
- }
-
- // Unlock and free this instance
- synchronized (instancePool) {
- countAllocated--;
- if (instancePool.contains(servlet)) {
- System.err.println("Aleady in pool " + servlet + " "
- + instancePool.size()+ " " + countAllocated);
- return;
- }
- System.err.println("return pool " + servlet + " " +
- instancePool.size() + " " + countAllocated);
- instancePool.push(servlet);
- }
- }
-
- public Servlet newInstance() throws ServletException {
- String actualClass = servletClassName;
-
- if (instance != null) {
- return instance;
- }
- if (actualClass == null) {
- // No explicit name. Try to use the framework
- if (jspFile != null) {
-
- // Named JSPs can be handled by a servlet or by the mapper.
- Servlet res = (Servlet) ctx.getObjectManager().get("filetemplate-servlet");
- if (res != null) {
- servletClass = res.getClass();
- actualClass = servletClass.getName();
- initParams.put("jsp-file", jspFile);
- return res;
- } else {
- UserTemplateClassMapper mapper =
- (UserTemplateClassMapper) ctx.getObjectManager().get(
- UserTemplateClassMapper.class);
- if (mapper != null) {
- return mapper.loadProxy(jspFile, ctx, this);
- }
- }
- }
- if (actualClass == null) {
- // Covers 'default-" and "jspwildcard-" servlets as well
- Servlet res = (Servlet) ctx.getObjectManager().get( servletName +
- "-servlet");
- if (res != null) {
- servletClass = res.getClass();
- actualClass = servletClass.getName();
- return res;
- }
- }
-
- //ctx.getObjectManager().getObject(c);
- //ctx.getObjectManager().getObject(servletName);
- }
-
-
- if (servletClass == null) {
- // set classClass
- loadClass(actualClass);
- }
-
-
- // jsp-file case. Load the JspProxyServlet instead, with the
- // right params. Note the JspProxyServlet is _not_ jasper,
- // nor 'jsp' servlet - it is just a proxy with no special
- // params. It calls the jsp servlet and jasper to generate the
- // real class.
-
- // this is quite different from catalina, where an ugly kludge was
- // used to use the same jsp servlet in 2 roles
-
- // the jsp proxy is replaced by the web.xml processor
-
- if (servletClass == null) {
- unavailable(null);
- throw new UnavailableException("ClassNotFound: " + actualClass);
- }
-
- // Instantiate and initialize an instance of the servlet class itself
- try {
- return (Servlet) servletClass.newInstance();
- } catch (ClassCastException e) {
- unavailable(null);
- throw new UnavailableException("ClassCast: (Servlet)" +
- actualClass);
- } catch (Throwable e) {
- unavailable(null);
-
- // Added extra log statement for Bugzilla 36630:
- // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630
- if(log.isLoggable(Level.FINE)) {
- log.log(Level.FINE, "newInstance() error: servlet-name: " +
- getServletName() +
- " servlet-class: " + actualClass, e);
- }
-
- // Restore the context ClassLoader
- throw new ServletException("newInstance() error " + getServletName() +
- " " + actualClass, e);
- }
- }
-
- /**
- * Load and initialize an instance of this servlet, if there is not already
- * at least one initialized instance. This can be used, for example, to
- * load servlets that are marked in the deployment descriptor to be loaded
- * at server startup time.
- */
- public synchronized Servlet loadServlet() throws ServletException {
- // Nothing to do if we already have an instance or an instance pool
- if (!singleThreadModel && (instance != null))
- return instance;
-
- long t1=System.currentTimeMillis();
-
- Servlet servlet = newInstance();
-
- classLoadTime=(int) (System.currentTimeMillis() -t1);
-
- // Call the initialization method of this servlet
- try {
- servlet.init(this);
- } catch (UnavailableException f) {
- unavailable(f);
- throw f;
- } catch (ServletException f) {
- throw f;
- } catch (Throwable f) {
- getServletContext().log("StandardWrapper.Throwable", f );
- throw new ServletException("Servlet.init()", f);
- }
-
- // Register our newly initialized instance
- singleThreadModel = servlet instanceof SingleThreadModel;
- if (singleThreadModel) {
- if (instancePool == null)
- instancePool = new Stack();
- }
- loadTime=System.currentTimeMillis() -t1;
-
- return servlet;
- }
-
-
- private void loadClass(String actualClass) throws ServletException {
- // Complain if no servlet class has been specified
- if (actualClass == null) {
- unavailable(null);
- throw new ServletException("servlet-class missing " +
- getServletName());
- }
-
- ClassLoader classLoader = ctx.getClassLoader();
- if (classLoader == null )
- classLoader = this.getClass().getClassLoader();
-
- // Load the specified servlet class from the appropriate class loader
- try {
- servletClass = classLoader.loadClass(actualClass);
- } catch (ClassNotFoundException e) {
- servletClass = null;
- }
- }
-
- /**
- * Return a String representation of this component.
- */
- public String toString() {
- StringBuilder sb = new StringBuilder();
- if (ctx != null) {
- sb.append(ctx.toString());
- sb.append(".");
- }
- sb.append("Servlet[");
- sb.append(getServletName()).append(" ");
- sb.append(servletClassName);
- if (jspFile != null) {
- sb.append(" jsp=").append(jspFile);
- }
- sb.append("]");
- return (sb.toString());
- }
-
-
- /**
- * Process an UnavailableException, marking this servlet as unavailable
- * for the specified amount of time.
- *
- * @param unavailable The exception that occurred, or <code>null</code>
- * to mark this servlet as permanently unavailable
- */
- public void unavailable(UnavailableException unavailable) {
- getServletContext().log("UnavailableException:" + getServletName());
- if (unavailable == null)
- setAvailable(Long.MAX_VALUE);
- else if (unavailable.isPermanent())
- setAvailable(Long.MAX_VALUE);
- else {
- int unavailableSeconds = unavailable.getUnavailableSeconds();
- if (unavailableSeconds <= 0)
- unavailableSeconds = 60; // Arbitrary default
- setAvailable(System.currentTimeMillis() +
- (unavailableSeconds * 1000L));
- }
-
- }
-
-
- /**
- * Unload all initialized instances of this servlet, after calling the
- * <code>destroy()</code> method for each instance. This can be used,
- * for example, prior to shutting down the entire servlet engine, or
- * prior to reloading all of the classes from the Loader associated with
- * our Loader's repository.
- *
- * @exception ServletException if an exception is thrown by the
- * destroy() method
- */
- public synchronized void unload() throws ServletException {
- setAvailable(Long.MAX_VALUE);
-
- // Nothing to do if we have never loaded the instance
- if (!singleThreadModel && (instance == null))
- return;
- unloading = true;
-
- // Loaf a while if the current instance is allocated
- // (possibly more than once if non-STM)
- if (countAllocated > 0) {
- int nRetries = 0;
- long delay = ctx.getUnloadDelay() / 20;
- while ((nRetries < 21) && (countAllocated > 0)) {
- if ((nRetries % 10) == 0) {
- log.info("Servlet.unload() timeout " +
- countAllocated);
- }
- try {
- Thread.sleep(delay);
- } catch (InterruptedException e) {
- ;
- }
- nRetries++;
- }
- }
-
- ClassLoader oldCtxClassLoader =
- Thread.currentThread().getContextClassLoader();
- if (instance != null) {
- ClassLoader classLoader = instance.getClass().getClassLoader();
-
- PrintStream out = System.out;
- // Call the servlet destroy() method
- try {
- Thread.currentThread().setContextClassLoader(classLoader);
- instance.destroy();
- } catch (Throwable t) {
- instance = null;
- //instancePool = null;
- unloading = false;
- throw new ServletException("Servlet.destroy() " +
- getServletName(), t);
- } finally {
- // restore the context ClassLoader
- Thread.currentThread().setContextClassLoader(oldCtxClassLoader);
- }
-
- // Deregister the destroyed instance
- instance = null;
- }
- if (singleThreadModel && (instancePool != null)) {
- try {
- ClassLoader classLoader = ctx.getClassLoader();
- Thread.currentThread().setContextClassLoader(classLoader);
- while (!instancePool.isEmpty()) {
- ((Servlet) instancePool.pop()).destroy();
- }
- } catch (Throwable t) {
- instancePool = null;
- unloading = false;
- throw new ServletException("Servlet.destroy() " + getServletName(), t);
- } finally {
- // restore the context ClassLoader
- Thread.currentThread().setContextClassLoader
- (oldCtxClassLoader);
- }
- instancePool = null;
- }
-
- singleThreadModel = false;
-
- unloading = false;
- }
-
-
- /**
- * Return the initialization parameter value for the specified name,
- * if any; otherwise return <code>null</code>.
- *
- * @param name Name of the initialization parameter to retrieve
- */
- public String getInitParameter(String name) {
- return initParams.get(name);
- }
-
-
- /**
- * Return the set of initialization parameter names defined for this
- * servlet. If none are defined, an empty Enumeration is returned.
- */
- public Enumeration getInitParameterNames() {
- synchronized (initParams) {
- return (new Enumerator(initParams.keySet()));
- }
- }
-
-
- /**
- * Return the servlet context with which this servlet is associated.
- */
- public ServletContext getServletContext() {
- return ctx;
- }
-
-
- /**
- * Return the name of this servlet.
- */
- public String getServletName() {
- return servletName;
- }
-
-// public long getProcessingTime() {
-// return swValve.getProcessingTime();
-// }
-//
-// public void setProcessingTime(long processingTime) {
-// swValve.setProcessingTime(processingTime);
-// }
-//
-// public long getMaxTime() {
-// return swValve.getMaxTime();
-// }
-//
-// public void setMaxTime(long maxTime) {
-// swValve.setMaxTime(maxTime);
-// }
-//
-// public long getMinTime() {
-// return swValve.getMinTime();
-// }
-//
-// public void setMinTime(long minTime) {
-// swValve.setMinTime(minTime);
-// }
-//
-// public int getRequestCount() {
-// return swValve.getRequestCount();
-// }
-//
-// public void setRequestCount(int requestCount) {
-// swValve.setRequestCount(requestCount);
-// }
-//
-// public int getErrorCount() {
-// return swValve.getErrorCount();
-// }
-//
-// public void setErrorCount(int errorCount) {
-// swValve.setErrorCount(errorCount);
-// }
-//
-// /**
-// * Increment the error count used for monitoring.
-// */
-// public void incrementErrorCount(){
-// swValve.setErrorCount(swValve.getErrorCount() + 1);
-// }
-//
-// public long getLoadTime() {
-// return loadTime;
-// }
-//
-// public void setLoadTime(long loadTime) {
-// this.loadTime = loadTime;
-// }
-//
-// public int getClassLoadTime() {
-// return classLoadTime;
-// }
-
- // -------------------------------------------------------- Package Methods
-
-
- // -------------------------------------------------------- Private Methods
-
- private Method[] getAllDeclaredMethods(Class c) {
-
- if (c.equals(javax.servlet.http.HttpServlet.class)) {
- return null;
- }
-
- Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
-
- Method[] thisMethods = c.getDeclaredMethods();
- if (thisMethods == null) {
- return parentMethods;
- }
-
- if ((parentMethods != null) && (parentMethods.length > 0)) {
- Method[] allMethods =
- new Method[parentMethods.length + thisMethods.length];
- System.arraycopy(parentMethods, 0, allMethods, 0,
- parentMethods.length);
- System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
- thisMethods.length);
-
- thisMethods = allMethods;
- }
-
- return thisMethods;
- }
-
- /** Specify the instance. Avoids the class lookup, disables unloading.
- * Use for embedded case, or to control the allocation.
- *
- * @param servlet
- */
- public void setServlet(Servlet servlet) {
- instance = servlet;
- ctx.getObjectManager().bind("Servlet:" +
- ctx.getContextPath() + ":" + getServletName(),
- this);
- }
-
- public String getSecurityRoleRef(String role) {
- return (String)securityRoleRef.get(role);
- }
-
- public void setSecurityRoleRef(Map securityRoles) {
- this.securityRoleRef = securityRoles;
- }
-
- public void setConfig(Map initParams) {
- this.initParams = initParams;
- }
-
- public void setLoadOnStartup(int loadOnStartup) {
- this.loadOnStartup = loadOnStartup;
- }
-
- @Override
- public Set<String> addMapping(String... urlPatterns) {
- if (ctx.startDone) {
- // Use the context method instead of the servlet API to
- // add mappings after context init.
- throw new IllegalStateException();
- }
- Set<String> failed = new HashSet<String>();
- for (String url: urlPatterns) {
- if (url == null) {
- throw new IllegalArgumentException();
- }
- if (ctx.contextConfig.servletMapping.get(url) != null) {
- failed.add(url);
- } else {
- ctx.contextConfig.servletMapping.put(url, getServletName());
- ctx.addMapping(url, this);
- }
- }
- return failed;
- }
-
-
- @Override
- public boolean setInitParameter(String name, String value)
- throws IllegalArgumentException, IllegalStateException {
- return ServletContextImpl.setInitParameter(ctx, initParams,
- name, value);
- }
-
-
- @Override
- public Set<String> setInitParameters(Map<String, String> initParameters)
- throws IllegalArgumentException, IllegalStateException {
- return ServletContextImpl.setInitParameters(ctx, initParams,
- initParameters);
- }
-
- public Dynamic getDynamic() {
- return dynamic;
- }
-
- class ServletDynamicRegistration implements Dynamic {
-
-
- @Override
- public void setAsyncSupported(boolean isAsyncSupported)
- throws IllegalStateException {
- asyncSupported = isAsyncSupported;
- }
-
-
- public void setDescription(String description)
- throws IllegalStateException {
- ServletConfigImpl.this.description = description;
- }
-
- @Override
- public Set<String> setServletSecurity(ServletSecurityElement constraint) {
- //implement me
- return null;
- }
-
- @Override
- public void setLoadOnStartup(int loadOnStartup) {
- //implement me - here to compile
- }
-
- @Override
- public void setMultipartConfig(MultipartConfigElement multipartConfig) {
- //implement me - here to compile
- }
-
- @Override
- public void setRunAsRole(String roleName) {
- //implement me - here to compile
- }
-
- @Override
- public String getRunAsRole() {
- //implement me - here to compile
- return null;
- }
-
- @Override
- public Collection<String> getMappings() {
- //implement me
- return null;
- }
-
- @Override
- public Set<String> addMapping(String... urlPatterns) {
- //implement me
- return null;
- }
-
- @Override
- public Map<String, String> getInitParameters() {
- // implement me
- return null;
- }
-
- @Override
- public Set<String> setInitParameters(Map<String, String> initParameters)
- throws IllegalArgumentException, IllegalStateException {
- // implement me
- return null;
- }
-
- @Override
- public String getClassName() {
- // implement me
- return null;
- }
-
- @Override
- public String getName() {
- // implement me
- return null;
- }
-
- @Override
- public String getInitParameter(String name) {
- // implement me
- return null;
- }
-
- @Override
- public boolean setInitParameter(String name, String value)
- throws IllegalArgumentException, IllegalStateException {
- // implement me
- return false;
- }
-
- }
-
- @Override
- public Collection<String> getMappings() {
- //implement me
- return null;
- }
-
- public void setServletClass(Class<? extends Servlet> servletClass2) {
- servletClass = servletClass2;
- }
-
-
- @Override
- public String getRunAsRole() {
- //implement me
- return null;
- }
-
-
- @Override
- public Map<String, String> getInitParameters() {
- // implement me
- return null;
- }
-
- @Override
- public String getClassName() {
- // implement me
- return null;
- }
-
- @Override
- public String getName() {
- // implement me
- return null;
- }
-
-}
+++ /dev/null
-/*
- * 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.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.Enumeration;
-import java.util.EventListener;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.atomic.AtomicInteger;
-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;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextAttributeEvent;
-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 javax.servlet.descriptor.JspConfigDescriptor;
-
-import org.apache.tomcat.addons.UserSessionManager;
-import org.apache.tomcat.integration.ObjectManager;
-import org.apache.tomcat.lite.webxml.ServletContextConfig;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.FilterData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.FilterMappingData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.ServletData;
-import org.apache.tomcat.servlets.util.Enumerator;
-import org.apache.tomcat.servlets.util.RequestUtil;
-import org.apache.tomcat.servlets.util.UrlUtils;
-import org.apache.tomcat.util.http.MimeMap;
-
-
-/**
- * Context - initialized from web.xml or using APIs.
- *
- * Initialization order:
- *
- * - add all listeners
- * - add all filters
- * - add all servlets
- *
- * - session parameters
- * -
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
- * @version $Revision$ $Date$
- */
-
-public class ServletContextImpl implements ServletContext {
-
- /**
- * Empty collection to serve as the basis for empty enumerations.
- */
- private transient static final ArrayList empty = new ArrayList();
-
- transient Logger log;
-
- /**
- * Base path - the directory root of the webapp
- */
- protected String basePath = null;
-
- protected String contextPath;
-
- // All config from web.xml
- protected ServletContextConfig contextConfig = new ServletContextConfig();
-
- MimeMap contentTypes = new MimeMap();
-
- /**
- * The context attributes for this context.
- */
- protected transient Map<String, Object> attributes = new HashMap<String, Object>();
-
- /**
- * List of read only attributes for this context.
- * In catalina - used to protect workdir att. We trust the app, so no need
- * for extra complexity.
- */
- //protected transient HashMap readOnlyAttributes = new HashMap();
-
- protected transient ArrayList<EventListener> lifecycleListeners = new ArrayList();
-
- protected UserSessionManager manager;
-
- HashMap<String, FilterConfigImpl> filters = new HashMap<String, FilterConfigImpl>();
-
- HashMap<String, ServletConfigImpl> servlets = new HashMap<String, ServletConfigImpl>();
-
- ArrayList<String> securityRoles = new ArrayList<String>();
-
- /** Mapper for filters.
- */
- protected WebappFilterMapper webappFilterMapper;
-
- /** Internal mapper for request dispatcher, must have all
- * context mappings.
- */
- protected WebappServletMapper mapper;
-
- transient Locale2Charset charsetMapper = new Locale2Charset();
-
- transient TomcatLite facade;
-
- ObjectManager om;
-
- private String hostname;
-
-
- boolean initDone = false;
-
- boolean startDone = false;
-
- // ------------------------------------------------- ServletContext Methods
- public ServletContextImpl() {
- }
-
- public void setTomcat(TomcatLite facade) {
- this.facade = facade;
- }
-
- /**
- * Registry/framework interface associated with the context.
- * Also available as a context attribute.
- * @return
- */
- public ObjectManager getObjectManager() {
- if (om == null) {
- om = facade.getObjectManager();
- }
- return om;
- }
-
- public void setObjectManager(ObjectManager om) {
- this.om = om;
- }
-
- public Locale2Charset getCharsetMapper() {
- return charsetMapper;
- }
-
- /**
- * Set the context path, starting with "/" - "/" for ROOT
- * @param path
- */
- public void setContextPath(String path) {
- this.contextPath = path;
- log = Logger.getLogger("webapp" + path.replace('/', '.'));
- }
-
- public void setHostname(String hostname) {
- this.hostname = hostname;
- }
-
- public String getHostname() {
- return hostname;
- }
-
- /** The directory where this app is based. May be null.
- *
- * @param basePath
- */
- public void setBasePath(String basePath) {
- this.basePath = basePath;
- }
-
- public ServletContextConfig getContextConfig() {
- return contextConfig;
- }
-
- /** The directory where this app is based.
- *
- * @param basePath
- */
- public String getBasePath() {
- return basePath;
- }
-
- public String getEncodedPath() {
- return null;
- }
-
-
- public boolean getCookies() {
- return false;
- }
-
-
- public ServletContext getServletContext() {
- return this;
- }
-
- public List<EventListener> getListeners() {
- return lifecycleListeners;
- }
-
- public void addListener(Class <? extends EventListener> listenerClass) {
- // implement me
- }
-
- public void addListener(String className) {
- // implement me
- }
-
- public <T extends EventListener> void addListener(T t) {
- lifecycleListeners.add(t);
- }
-
-
- public void removeListener(EventListener listener) {
- lifecycleListeners.remove(listener);
- }
-
-
-
- public Logger getLogger() {
- return log;
- }
-
- public long getUnloadDelay() {
- return 0;
- }
-
- public ServletConfigImpl getServletConfig(String jsp_servlet_name) {
- return (ServletConfigImpl)servlets.get(jsp_servlet_name);
- }
-
- public Map getServletConfigs() {
- return servlets;
- }
-
- /**
- * Add a servlet to the context.
- * Called from processWebAppData()
- *
- * @param servletConfig
- */
- public void addServletConfig(ServletConfigImpl servletConfig) {
- servlets.put(servletConfig.getServletName(), servletConfig);
- }
-
- public boolean getPrivileged() {
- return false;
- }
-
-
- public Map getFilters() {
- return filters;
- }
-
-
- protected boolean getCrossContext() {
- return true;
- }
-
- public void addMimeType(String ext, String type) {
- contentTypes.addContentType(ext, type);
- }
-
- public WebappServletMapper getMapper() {
- if (mapper == null) {
- Object customMapper = getObjectManager().get(WebappServletMapper.class);
- if (customMapper == null) {
- mapper = new WebappServletMapper();
- } else {
- mapper = (WebappServletMapper) customMapper;
- }
- mapper.setServletContext(this);
- }
-
- return mapper;
- }
-
- public WebappFilterMapper getFilterMapper() {
- if (webappFilterMapper == null) {
- Object customMapper = getObjectManager().get(WebappFilterMapper.class);
- if (customMapper == null) {
- webappFilterMapper = new WebappFilterMapper();
- } else {
- webappFilterMapper = (WebappFilterMapper) customMapper;
- }
- webappFilterMapper.setServletContext(this);
- }
-
- return webappFilterMapper ;
- }
-
- public FilterConfigImpl getFilter(String name) {
- return (FilterConfigImpl)filters.get(name);
- }
-
- /**
- * Return the value of the specified context attribute, if any;
- * otherwise return <code>null</code>.
- *
- * @param name Name of the context attribute to return
- */
- public Object getAttribute(String name) {
- if ("ObjectManager".equals(name)) {
- return om;
- }
- if ("context-listeners".equals(name)) {
- return lifecycleListeners;
- }
- return (attributes.get(name));
- }
-
- /**
- * Return an enumeration of the names of the context attributes
- * associated with this context.
- */
- public Enumeration getAttributeNames() {
- return new Enumerator(attributes.keySet(), true);
- }
-
-
- public void addSecurityRole(String role) {
- securityRoles.add(role);
- }
-
- public List getSecurityRoles() {
- return securityRoles;
- }
-
- /**
- * Return a <code>ServletContext</code> object that corresponds to a
- * specified URI on the server. This method allows servlets to gain
- * access to the context for various parts of the server, and as needed
- * obtain <code>RequestDispatcher</code> objects or resources from the
- * context. The given path must be absolute (beginning with a "/"),
- * and is interpreted based on our virtual host's document root.
- *
- * @param uri Absolute URI of a resource on the server
- */
- public ServletContext getContext(String uri) {
- // TODO: support real uri ( http://host/path )
- // Validate the format of the specified argument
- if ((uri == null) || (!uri.startsWith("/")))
- return (null);
-
- ServletContextImpl child = null;
- try {
- child = facade.getContext(this, uri);
- } catch (IOException e) {
- } catch (ServletException e) {
- }
-
- if (child == null)
- return (null);
-
- if (this.getCrossContext()) {
- // If crossContext is enabled, can always return the context
- return child.getServletContext();
- } else if (child == this) {
- // Can still return the current context
- return this.getServletContext();
- } else {
- // Nothing to return
- return (null);
- }
- }
-
-
- /**
- * Return the main path associated with this context.
- */
- public String getContextPath() {
- return contextPath;
- }
-
-
- /**
- * Return the value of the specified initialization parameter, or
- * <code>null</code> if this parameter does not exist.
- *
- * @param name Name of the initialization parameter to retrieve
- */
- public String getInitParameter(final String name) {
- return ((String) contextConfig.contextParam.get(name));
- }
-
-
- /**
- * Return the names of the context's initialization parameters, or an
- * empty enumeration if the context has no initialization parameters.
- */
- public Enumeration getInitParameterNames() {
- return (new Enumerator(contextConfig.contextParam.keySet()));
- }
-
- public void setContextParams(Map newParams) {
- contextConfig.contextParam = (HashMap) newParams;
- }
-
- /**
- * Return the major version of the Java Servlet API that we implement.
- */
- public int getMajorVersion() {
- return 2;
- }
-
-
- /**
- * Return the minor version of the Java Servlet API that we implement.
- */
- public int getMinorVersion() {
- return 4;
- }
-
-
- /**
- * Return the MIME type of the specified file, or <code>null</code> if
- * the MIME type cannot be determined.
- *
- * @param file Filename for which to identify a MIME type
- */
- public String getMimeType(String file) {
- return contentTypes.getMimeType(file);
- }
-
- /**
- * Return the real path for a given virtual path, if possible; otherwise
- * return <code>null</code>.
- *
- * @param path The path to the desired resource
- */
- public String getRealPath(String path) {
- if (path == null) {
- return null;
- }
-
- File file = new File(basePath, path);
- return (file.getAbsolutePath());
- }
-
- /**
- * Return a <code>RequestDispatcher</code> object that acts as a
- * wrapper for the named servlet.
- *
- * @param name Name of the servlet for which a dispatcher is requested
- */
- public RequestDispatcher getNamedDispatcher(String name) {
- if (name == null) return null;
- ServletConfigImpl wrapper =
- (ServletConfigImpl) this.getServletConfig(name);
- if (wrapper == null) return null;
-
- return new RequestDispatcherImpl(wrapper, name);
- }
-
-
- /**
- * Return a <code>RequestDispatcher</code> instance that acts as a
- * wrapper for the resource at the given path. The path must begin
- * with a "/" and is interpreted as relative to the current context root.
- *
- * @param path The path to the desired resource.
- */
- public RequestDispatcher getRequestDispatcher(String path) {
- if (path == null) return null;
-
- if (!path.startsWith("/"))
- throw new IllegalArgumentException(path);
-
- path = UrlUtils.normalize(path);
- if (path == null) return (null);
-
-
- return new RequestDispatcherImpl(this, path);
- }
-
- public RequestDispatcher getRequestDispatcher(String path,
- int type,
- String dispatcherPath) {
- RequestDispatcher dispatcher = getRequestDispatcher(path);
- //((RequestDispatcherImpl)dispatcher);
- return dispatcher;
- }
-
- ThreadLocal requestDispatcherStack = new ThreadLocal();
-
- protected ClassLoader classLoader;
-
-// protected RequestDispatcherImpl getRequestDispatcher() {
-// ArrayList/*<RequestDispatcherImpl>*/ list =
-// (ArrayList)requestDispatcherStack.get();
-// if (list == null) {
-// list = new ArrayList();
-// requestDispatcherStack.set(list);
-// }
-//
-//
-// return null;
-// }
-
- public void resetDispatcherStack() {
-
- }
-
- /**
- * Return the URL to the resource that is mapped to a specified path.
- * The path must begin with a "/" and is interpreted as relative to the
- * current context root.
- *
- * @param path The path to the desired resource
- *
- * @exception MalformedURLException if the path is not given
- * in the correct form
- */
- public URL getResource(String path)
- throws MalformedURLException {
-
- if (path == null || !path.startsWith("/")) {
- throw new MalformedURLException("getResource() " + path);
- }
-
- path = UrlUtils.normalize(path);
- if (path == null)
- return (null);
-
- String libPath = "/WEB-INF/lib/";
- if ((path.startsWith(libPath)) && (path.endsWith(".jar"))) {
- File jarFile = null;
- jarFile = new File(basePath, path);
- if (jarFile.exists()) {
- return jarFile.toURL();
- } else {
- return null;
- }
- } else {
- File resFile = new File(basePath + path);
- if (resFile.exists()) {
- return resFile.toURL();
- }
- }
-
- return (null);
-
- }
-
- /**
- * Return the requested resource as an <code>InputStream</code>. The
- * path must be specified according to the rules described under
- * <code>getResource</code>. If no such resource can be identified,
- * return <code>null</code>.
- *
- * @param path The path to the desired resource.
- */
- public InputStream getResourceAsStream(String path) {
-
- path = UrlUtils.normalize(path);
- if (path == null)
- return (null);
-
- File resFile = new File(basePath + path);
- if (!resFile.exists())
- return null;
-
- try {
- return new FileInputStream(resFile);
- } catch (FileNotFoundException e) {
- return null;
- }
-
- }
-
-
- /**
- * Return a Set containing the resource paths of resources member of the
- * specified collection. Each path will be a String starting with
- * a "/" character. The returned set is immutable.
- *
- * @param path Collection path
- */
- public Set getResourcePaths(String path) {
-
- // Validate the path argument
- if (path == null) {
- return null;
- }
- if (!path.startsWith("/")) {
- throw new IllegalArgumentException("getResourcePaths() " + path);
- }
-
- path = UrlUtils.normalize(path);
- if (path == null)
- return (null);
-
- File f = new File(basePath + path);
- File[] files = f.listFiles();
- if (files == null) return null;
- if (!path.endsWith("/")) {
- path = path + "/";
- }
-
- HashSet result = new HashSet();
- for (int i=0; i < files.length; i++) {
- if (files[i].isDirectory() ) {
- result.add(path + files[i].getName() + "/");
- } else {
- result.add(path + files[i].getName());
- }
- }
- return result;
- }
-
-
-
- /**
- * Return the name and version of the servlet container.
- */
- public String getServerInfo() {
- return "Apache Tomcat Lite";
- }
-
- /**
- * @deprecated As of Java Servlet API 2.1, with no direct replacement.
- */
- public Servlet getServlet(String name) {
- return (null);
- }
-
-
- /**
- * Return the display name of this web application.
- */
- public String getServletContextName() {
- return contextConfig.displayName;
- }
-
-
- /**
- * @deprecated As of Java Servlet API 2.1, with no direct replacement.
- */
- public Enumeration getServletNames() {
- return (new Enumerator(empty));
- }
-
-
- /**
- * @deprecated As of Java Servlet API 2.1, with no direct replacement.
- */
- public Enumeration getServlets() {
- return (new Enumerator(empty));
- }
-
-
- /**
- * Writes the specified message to a servlet log file.
- *
- * @param message Message to be written
- */
- public void log(String message) {
- this.getLogger().info(message);
- }
-
-
- /**
- * Writes the specified exception and message to a servlet log file.
- *
- * @param exception Exception to be reported
- * @param message Message to be written
- *
- * @deprecated As of Java Servlet API 2.1, use
- * <code>log(String, Throwable)</code> instead
- */
- public void log(Exception exception, String message) {
- this.getLogger().log(Level.INFO, message, exception);
- }
-
-
- /**
- * Writes the specified message and exception to a servlet log file.
- *
- * @param message Message to be written
- * @param throwable Exception to be reported
- */
- public void log(String message, Throwable throwable) {
- this.getLogger().log(Level.INFO, message, throwable);
- }
-
- /**
- * Remove the context attribute with the specified name, if any.
- *
- * @param name Name of the context attribute to be removed
- */
- public void removeAttribute(String name) {
-
- Object value = null;
- boolean found = false;
-
- // Remove the specified attribute
- // Check for read only attribute
- found = attributes.containsKey(name);
- if (found) {
- value = attributes.get(name);
- attributes.remove(name);
- } else {
- return;
- }
-
- // Notify interested application event listeners
- List listeners = this.getListeners();
- if (listeners.size() == 0)
- return;
- ServletContextAttributeEvent event = null;
- for (int i = 0; i < listeners.size(); i++) {
- if (!(listeners.get(i) instanceof ServletContextAttributeListener))
- continue;
- ServletContextAttributeListener listener =
- (ServletContextAttributeListener) listeners.get(i);
- try {
- if (event == null) {
- event = new ServletContextAttributeEvent(this.getServletContext(),
- name, value);
-
- }
- listener.attributeRemoved(event);
- } catch (Throwable t) {
- // FIXME - should we do anything besides log these?
- log("ServletContextAttributeListener", t);
- }
- }
- }
-
-
- /**
- * Bind the specified value with the specified context attribute name,
- * replacing any existing value for that name.
- *
- * @param name Attribute name to be bound
- * @param value New attribute value to be bound
- */
- public void setAttribute(String name, Object value) {
- // Name cannot be null
- if (name == null)
- throw new IllegalArgumentException
- ("name == null");
-
- // Null value is the same as removeAttribute()
- if (value == null) {
- removeAttribute(name);
- return;
- }
-
- Object oldValue = null;
- boolean replaced = false;
-
- // Add or replace the specified attribute
- synchronized (attributes) {
- // Check for read only attribute
- oldValue = attributes.get(name);
- if (oldValue != null)
- replaced = true;
- attributes.put(name, value);
- }
-
- // Notify interested application event listeners
- List listeners = this.getListeners();
- if (listeners.size() == 0)
- return;
- ServletContextAttributeEvent event = null;
- for (int i = 0; i < listeners.size(); i++) {
- if (!(listeners.get(i) instanceof ServletContextAttributeListener))
- continue;
- ServletContextAttributeListener listener =
- (ServletContextAttributeListener) listeners.get(i);
- try {
- if (event == null) {
- if (replaced)
- event =
- new ServletContextAttributeEvent(this.getServletContext(),
- name, oldValue);
- else
- event =
- new ServletContextAttributeEvent(this.getServletContext(),
- name, value);
-
- }
- if (replaced) {
- listener.attributeReplaced(event);
- } else {
- listener.attributeAdded(event);
- }
- } catch (Throwable t) {
- // FIXME - should we do anything besides log these?
- log("ServletContextAttributeListener error", t);
- }
- }
-
- }
-
- /**
- * Clear all application-created attributes.
- */
- void clearAttributes() {
- // Create list of attributes to be removed
- ArrayList list = new ArrayList();
- synchronized (attributes) {
- Iterator iter = attributes.keySet().iterator();
- while (iter.hasNext()) {
- list.add(iter.next());
- }
- }
-
- // Remove application originated attributes
- // (read only attributes will be left in place)
- Iterator keys = list.iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- removeAttribute(key);
- }
- }
-
- public void initFilters() throws ServletException {
- Iterator fI = getFilters().values().iterator();
- while (fI.hasNext()) {
- FilterConfigImpl fc = (FilterConfigImpl)fI.next();
- try {
- fc.getFilter(); // will triger init()
- } catch (Throwable e) {
- log.log(Level.WARNING, getContextPath() + " Filter.init() " +
- fc.getFilterName(), e);
- }
-
- }
- }
-
- public void initServlets() throws ServletException {
- Iterator fI = getServletConfigs().values().iterator();
- Map/*<Integer, List<ServletConfigImpl>>*/ onStartup =
- new TreeMap/*<Integer, List<ServletConfigImpl>>*/();
- while (fI.hasNext()) {
- ServletConfigImpl fc = (ServletConfigImpl)fI.next();
- if (fc.getLoadOnStartup() > 0 ) {
- Integer i = new Integer(fc.getLoadOnStartup());
- List/*<ServletConfigImpl>*/ old = (List)onStartup.get(i);
- if (old == null) {
- old = new ArrayList/*<ServletConfigImpl>*/();
- onStartup.put(i, old);
- }
- old.add(fc);
- }
- }
- Iterator keys = onStartup.keySet().iterator();
- while (keys.hasNext()) {
- Integer key = (Integer)keys.next();
- List/*<ServletConfigImpl>*/ servlets = (List)onStartup.get(key);
- Iterator servletsI = servlets.iterator();
- while (servletsI.hasNext()) {
- ServletConfigImpl fc = (ServletConfigImpl) servletsI.next();
- try {
- fc.loadServlet();
- } catch (Throwable e) {
- log.log(Level.WARNING, "Error initializing " + fc.getServletName(), e);
- }
- }
- }
- }
-
- public void initListeners() throws ServletException {
- Iterator fI = contextConfig.listenerClass.iterator();
- while (fI.hasNext()) {
- String listenerClass = (String)fI.next();
- try {
- Object l =
- getClassLoader().loadClass(listenerClass).newInstance();
- lifecycleListeners.add((EventListener) l);
- } catch (Throwable e) {
- log.log(Level.WARNING, "Error initializing listener " + listenerClass, e);
- }
- }
- }
-
- public ClassLoader getClassLoader() {
- return classLoader;
- }
-
- public void addMapping(String path, String name) {
- ServletConfigImpl wrapper = getServletConfig(name);
- addMapping(path, wrapper);
- }
-
- public void addMapping(String path, ServletConfig wrapper) {
- getMapper().addWrapper(getMapper().contextMapElement, path, wrapper);
- }
-
-
-
- public void setWelcomeFiles(String[] name) {
- getMapper().contextMapElement.welcomeResources = name;
- }
-
- public String[] getWelcomeFiles() {
- return getMapper().contextMapElement.welcomeResources;
- }
-
- public void setSessionTimeout(int to) {
- getManager().setSessionTimeout(to);
- }
-
- /**
- * Initialize the context from the parsed config.
- *
- * Note that WebAppData is serializable.
- */
- public void processWebAppData(ServletContextConfig d) throws ServletException {
- this.contextConfig = d;
-
- for (String k: d.mimeMapping.keySet()) {
- addMimeType(k, d.mimeMapping.get(k));
- }
-
- String[] wFiles = (String[])d.welcomeFileList.toArray(new String[0]);
- if (wFiles.length == 0) {
- wFiles = new String[] {"index.html" };
- }
- if (basePath != null) {
- getMapper().contextMapElement.resources = new File(getBasePath());
- }
- setWelcomeFiles(wFiles);
-
- Iterator i2 = d.filters.values().iterator();
- while (i2.hasNext()) {
- FilterData fd = (FilterData)i2.next();
- addFilter(fd.filterName, fd.filterClass, fd.initParams);
- }
-
- Iterator i3 = d.servlets.values().iterator();
- while (i3.hasNext()) {
- ServletData sd = (ServletData) i3.next();
- // jsp-file
- if (sd.servletClass == null) {
- if (sd.jspFile == null) {
- log.log(Level.WARNING, "Missing servlet class for " + sd.servletName);
- continue;
- }
- }
-
- ServletConfigImpl sw =
- new ServletConfigImpl(this, sd.servletName, sd.servletClass);
- sw.setConfig(sd.initParams);
- sw.setJspFile(sd.jspFile);
- sw.setLoadOnStartup(sd.loadOnStartup);
- //sw.setRunAs(sd.runAs);
- sw.setSecurityRoleRef(sd.securityRoleRef);
-
- addServletConfig(sw);
- }
-
- for (String k: d.servletMapping.keySet()) {
- addMapping(k, d.servletMapping.get(k));
- }
-
- Iterator i5 = d.filterMappings.iterator();
- while (i5.hasNext()) {
- FilterMappingData k = (FilterMappingData) i5.next();
- String[] disp = new String[k.dispatcher.size()];
- if (k.urlPattern != null) {
- addFilterMapping(k.urlPattern,
- k.filterName,
- (String[])k.dispatcher.toArray(disp));
- }
- if (k.servletName != null) {
- addFilterServletMapping(k.servletName,
- k.filterName,
- (String[])k.dispatcher.toArray(disp));
- }
- }
-
- for (String n: d.localeEncodingMapping.keySet()) {
- getCharsetMapper().addCharsetMapping(n,
- d.localeEncodingMapping.get(n));
- }
- }
-
- public void addServlet(String servletName, String servletClass,
- String jspFile, Map params) {
- ServletConfigImpl sc = new ServletConfigImpl(this, servletName,
- servletClass);
- sc.setJspFile(jspFile);
- sc.setConfig(params);
- addServletConfig(sc);
- }
-
- @Override
- public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
- ServletConfigImpl sc = new ServletConfigImpl(this, servletName, null);
- sc.setServlet(servlet);
- addServletConfig(sc);
- return sc.getDynamic();
- }
-
- public void addServletSec(String serlvetName, String runAs, Map roles) {
- // TODO
- }
-
-
-
- public void addFilterMapping(String path, String filterName,
- String[] dispatcher) {
- getFilterMapper().addMapping(filterName,
- path, null, dispatcher, true);
-
- }
-
- public void addFilterServletMapping(String servlet,
- String filterName,
- String[] dispatcher) {
- getFilterMapper().addMapping(filterName,
- null, servlet,
- dispatcher, true);
- }
-
- /**
- * Called from TomcatLite.init(), required before start.
- *
- * Will initialize defaults and load web.xml unless webAppData is
- * already set and recent. No other processing is done except reading
- * the config - you can add or alter it before start() is called.
- *
- * @throws ServletException
- */
- public void init() throws ServletException {
- if (initDone) {
- return;
- }
- initDone = true;
- // Load global init params from the facade
- initEngineDefaults();
-
- initTempDir();
-
-
- // Merge in web.xml - or other config source ( programmatic, etc )
- ContextPreinitListener cfg =
- (ContextPreinitListener) getObjectManager().get(
- ContextPreinitListener.class);
- if (cfg != null) {
- cfg.preInit(this);
- }
-
- processWebAppData(contextConfig);
-
- // if not defined yet:
- addDefaultServlets();
- }
-
-
- protected void initTempDir() throws ServletException {
- // We need a base path - at least for temp files, req. by spec
- if (basePath == null) {
- basePath = ("/".equals(contextPath)) ?
- facade.getWork().getAbsolutePath() + "/ROOT" :
- facade.getWork().getAbsolutePath() + contextPath;
- }
-
- File f = new File(basePath + "/WEB-INF/tmp");
- f.mkdirs();
- setAttribute("javax.servlet.context.tempdir", f);
- }
-
- /**
- * Static file handler ( default )
- * *.jsp support
- *
- */
- protected void addDefaultServlets() throws ServletException {
- if (servlets.get("default") == null) {
- ServletConfigImpl fileS = new ServletConfigImpl(this,
- "default", null);
- addServletConfig(fileS);
- addMapping("/", fileS);
- }
-
- // *.jsp support
- if (servlets.get("jspwildcard") == null) {
- ServletConfigImpl fileS = new ServletConfigImpl(this,
- "jspwildcard", null);
- addServletConfig(fileS);
- addMapping("*.jsp", fileS);
- }
- }
-
- protected void initEngineDefaults() throws ServletException {
-
- // TODO: make this customizable, avoid loading it on startup
- // Set the class name as default in the addon support
- for (String sname: facade.ctxDefaultInitParam.keySet()) {
- String path = facade.ctxDefaultInitParam.get(sname);
- contextConfig.contextParam.put(sname, path);
- }
-
- for (String sname: facade.preloadServlets.keySet()) {
- String sclass = facade.preloadServlets.get(sname);
- ServletConfigImpl fileS = new ServletConfigImpl(this, sname, sclass);
- addServletConfig(fileS);
- }
-
- for (String sname: facade.preloadMappings.keySet()) {
- String path = facade.preloadMappings.get(sname);
- ServletConfigImpl servletConfig = getServletConfig(sname);
- addMapping(path, servletConfig);
- }
- }
-
-
- public ArrayList getClasspath(File directory, File classesDir) {
- ArrayList res = new ArrayList();
- if (classesDir.isDirectory() && classesDir.exists() &&
- classesDir.canRead()) {
- try {
- URL url = classesDir.toURL();
- res.add(url);
- } catch (MalformedURLException e) {
- }
- }
- if (!directory.isDirectory() || !directory.exists()
- || !directory.canRead()) {
- return res;
- }
-
- File[] jars = directory.listFiles(new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return name.endsWith(".jar");
- }
- });
-
- for (int j = 0; j < jars.length; j++) {
- try {
- URL url = jars[j].toURL();
- res.add(url);
- } catch (MalformedURLException e) {
- }
- }
- return res;
- }
-
-
- public void start() throws ServletException {
- if (startDone) {
- return;
- }
- String base = getBasePath();
-
- ArrayList urls = getClasspath(new File(base + "/WEB-INF/lib"),
- new File(base + "/WEB-INF/classes"));
- URL[] urlsA = new URL[urls.size()];
- urls.toArray(urlsA);
-
- URLClassLoader parentLoader =
- getEngine().getContextParentLoader();
-
- // create a class loader.
- // TODO: reimplement special 'deploy' dirs
-
- /*
- Repository ctxRepo = new Repository();
- ctxRepo.setParentClassLoader(parentLoader);
- ctxRepo.addURL(urlsA);
- repository = ctxRepo;
- */
-
- classLoader = new URLClassLoader(urlsA, parentLoader);
-
- // JMX should know about us ( TODO: is it too early ? )
- facade.notifyAdd(this);
-
- initListeners();
-
- List listeners = this.getListeners();
- ServletContextEvent event = null;
- for (int i = 0; i < listeners.size(); i++) {
- if (!(listeners.get(i) instanceof ServletContextListener))
- continue;
- ServletContextListener listener =
- (ServletContextListener) listeners.get(i);
- if (event == null) {
- event = new ServletContextEvent(this);
- }
- try {
- // May add servlets/filters
- listener.contextInitialized(event);
- } catch (Throwable t) {
- log.log(Level.WARNING, "Context.init() contextInitialized() error:", t);
- }
- }
-
-
- initFilters();
- initServlets();
-
- startDone = true;
- }
-
- public UserSessionManager getManager() {
- if (manager == null) {
- manager = (UserSessionManager) getObjectManager().get(
- UserSessionManager.class);
- manager.setContext(this);
- if (contextConfig.sessionTimeout > 0 ) {
- manager.setSessionTimeout(contextConfig.sessionTimeout);
- }
- }
- return manager;
- }
-
-
- // TODO: configurable ? init-params
- public String getSessionCookieName() {
- return "JSESSIONID";
- }
-
-
-
- public void destroy() throws ServletException {
- // destroy filters
- Iterator fI = filters.values().iterator();
- while(fI.hasNext()) {
- FilterConfigImpl fc = (FilterConfigImpl) fI.next();
- try {
- fc.getFilter().destroy();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- // destroy servlets
- fI = servlets.values().iterator();
- while(fI.hasNext()) {
- ServletConfigImpl fc = (ServletConfigImpl) fI.next();
- try {
- fc.unload();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- public TomcatLite getEngine() {
- return facade;
- }
-
- public String findStatusPage(int status) {
- if (contextConfig.errorPageCode.size() == 0) {
- return null;
- }
- if (status == 200) {
- return null;
- }
-
- return (String) contextConfig.errorPageCode.get(Integer.toString(status));
- }
-
- public void handleStatusPage(ServletRequestImpl req,
- ServletResponseImpl res,
- int status,
- String statusPage) {
- String message = RequestUtil.filter(res.getMessage());
- if (message == null)
- message = "";
- setErrorAttributes(req, status, message);
- dispatchError(req, res, statusPage);
- }
-
- protected void setErrorAttributes(ServletRequestImpl req,
- int status,
- String message) {
- req.setAttribute("javax.servlet.error.status_code",
- new Integer(status));
- if (req.getWrapper() != null) {
- req.setAttribute("javax.servlet.error.servlet_name",
- req.getWrapper().servletName);
- }
- req.setAttribute("javax.servlet.error.request_uri",
- req.getRequestURI());
- req.setAttribute("javax.servlet.error.message",
- message);
-
- }
-
- public void handleError(ServletRequestImpl req,
- ServletResponseImpl res,
- Throwable t) {
- Throwable realError = t;
- if (realError instanceof ServletException) {
- realError = ((ServletException) realError).getRootCause();
- if (realError == null) {
- realError = t;
- }
- }
- //if (realError instanceof ClientAbortException ) {
-
- String errorPage = findErrorPage(t);
- if ((errorPage == null) && (realError != t)) {
- errorPage = findErrorPage(realError);
- }
-
- if (errorPage != null) {
- setErrorAttributes(req, 500, t.getMessage());
- req.setAttribute("javax.servlet.error.exception", realError);
- req.setAttribute("javax.servlet.error.exception_type",
- realError.getClass());
- dispatchError(req, res, errorPage);
- } else {
- log("Unhandled error", t);
- if (t instanceof ServletException &&
- ((ServletException)t).getRootCause() != null) {
- log("RootCause:", ((ServletException)t).getRootCause());
- }
- if (res.getStatus() < 500) {
- res.setStatus(500);
- }
- }
- }
-
- protected void dispatchError(ServletRequestImpl req,
- ServletResponseImpl res,
- String errorPage) {
- RequestDispatcher rd =
- getRequestDispatcher(errorPage);
- try {
- // will clean up the buffer
- rd.forward(req, res);
- return; // handled
- } catch (ServletException e) {
- // TODO
- } catch (IOException e) {
- // TODO
- }
- }
-
- protected String findErrorPage(Throwable exception) {
- if (contextConfig.errorPageException.size() == 0) {
- return null;
- }
- if (exception == null)
- return (null);
- Class clazz = exception.getClass();
- String name = clazz.getName();
- while (!Object.class.equals(clazz)) {
- String page = (String)contextConfig.errorPageException.get(name);
- if (page != null)
- return (page);
- clazz = clazz.getSuperclass();
- if (clazz == null)
- break;
- name = clazz.getName();
- }
- return (null);
-
- }
-
-
- @Override
- public EnumSet<SessionTrackingMode> getDefaultSessionTrackingModes() {
- return null;
- }
-
-
- @Override
- public EnumSet<SessionTrackingMode> getEffectiveSessionTrackingModes() {
- return null;
- }
-
-
- @Override
- public SessionCookieConfig getSessionCookieConfig() {
- return null;
- }
-
-
- @Override
- public void setSessionTrackingModes(EnumSet<SessionTrackingMode> sessionTrackingModes) {
- }
-
-
- public void addFilter(String filterName, String filterClass,
- Map params) {
- FilterConfigImpl fc = new FilterConfigImpl(this);
- fc.setData(filterName, filterClass, params);
- filters.put(filterName, fc);
- }
-
-
- @Override
- public Dynamic addFilter(String filterName, String className) {
- FilterConfigImpl fc = new FilterConfigImpl(this);
- fc.setData(filterName, className, new HashMap());
- filters.put(filterName, fc);
- return fc.getDynamic();
- }
-
-
- @Override
- public Dynamic addFilter(String filterName, Filter filter) {
- FilterConfigImpl fc = new FilterConfigImpl(this);
- fc.setData(filterName, null, new HashMap());
- fc.setFilter(filter);
- filters.put(filterName, fc);
- return fc.getDynamic();
- }
-
-
- @Override
- public Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {
- FilterConfigImpl fc = new FilterConfigImpl(this);
- fc.setData(filterName, null, new HashMap());
- fc.setFilterClass(filterClass);
- filters.put(filterName, fc);
- return fc.getDynamic();
- }
-
-
- @Override
- public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName,
- String className) {
- ServletConfigImpl sc = new ServletConfigImpl(this, servletName, className);
- addServletConfig(sc);
- return sc.getDynamic();
- }
-
-
- @Override
- public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName,
- Class<? extends Servlet> servletClass) {
- ServletConfigImpl sc = new ServletConfigImpl(this, servletName, servletClass.getName());
- sc.setServletClass(servletClass);
- addServletConfig(sc);
- return sc.getDynamic();
- }
-
- // That's tricky - this filter will have no name. We need to generate one
- // because our code relies on names.
- AtomicInteger autoName = new AtomicInteger();
-
-
- @Override
- public <T extends Filter> T createFilter(Class<T> c) throws ServletException {
- FilterConfigImpl fc = new FilterConfigImpl(this);
- String filterName = "_tomcat_auto_filter_" + autoName.incrementAndGet();
- fc.setData(filterName, null, new HashMap());
- fc.setFilterClass(c);
- filters.put(filterName, fc);
-
- try {
- return (T) fc.createFilter();
- } catch (ClassCastException e) {
- throw new ServletException(e);
- } catch (ClassNotFoundException e) {
- throw new ServletException(e);
- } catch (IllegalAccessException e) {
- throw new ServletException(e);
- } catch (InstantiationException e) {
- throw new ServletException(e);
- }
- }
-
-
- @Override
- public <T extends Servlet> T createServlet(Class<T> c) throws ServletException {
- String filterName = "_tomcat_auto_servlet_" + autoName.incrementAndGet();
- ServletConfigImpl fc = new ServletConfigImpl(this, filterName, null);
- fc.setServletClass(c);
- servlets.put(filterName, fc);
-
- try {
- return (T) fc.newInstance();
- } catch (ClassCastException e) {
- throw new ServletException(e);
- }
- }
-
-
- public FilterRegistration findFilterRegistration(String filterName) {
- return filters.get(filterName);
- }
-
-
- public ServletRegistration findServletRegistration(String servletName) {
- return servlets.get(servletName);
- }
-
-
- @Override
- public boolean setInitParameter(String name, String value) {
- HashMap<String, String> params = contextConfig.contextParam;
- return setInitParameter(this, params, name, value);
- }
-
-
- static Set<String> setInitParameters(ServletContextImpl ctx,
- Map<String, String> params,
- Map<String, String> initParameters)
- throws IllegalArgumentException, IllegalStateException {
- if (ctx.startDone) {
- throw new IllegalStateException();
- }
- Set<String> result = new HashSet<String>();
- for (String name: initParameters.keySet()) {
- String value = initParameters.get(name);
- if (name == null || value == null) {
- throw new IllegalArgumentException();
- }
- if (!setInitParameter(ctx, params, name, value)) {
- result.add(name);
- }
- }
- return result;
- }
-
- /**
- * true if the context initialization parameter with the given name and value was set successfully on this ServletContext, and false if it was not set because this ServletContext already contains a context initialization parameter with a matching name
- * Throws:
- * java.lang.IllegalStateException - if this ServletContext has already been initialized
- */
- static boolean setInitParameter(ServletContextImpl ctx, Map<String, String> params,
- String name, String value) {
- if (name == null || value == null) {
- throw new IllegalArgumentException();
- }
- if (ctx.startDone) {
- throw new IllegalStateException();
- }
- String oldValue = params.get(name);
- if (oldValue != null) {
- return false;
- } else {
- params.put(name, value);
- return true;
- }
- }
-
- public JspConfigDescriptor getJspConfigDescriptor() {
- // fix me - just here to compile
- return null;
- }
-
-
-
- public void declareRoles(String... roleNames) {
- // implement me
- }
-
- public <T extends EventListener> T createListener(Class<T> c) throws ServletException {
- // implement me
- return null;
- }
-
- public Collection<String> getMappings() {
- // implement me
- return null;
- }
-
- public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
- // implement me
- return null;
- }
-
- public FilterRegistration getFilterRegistration(String filterName) {
- // implement me
- return null;
- }
-
- public Map<String, ? extends ServletRegistration> getServletRegistrations() {
- // implement me
- return null;
- }
-
- public ServletRegistration getServletRegistration(String servletName) {
- // implement me
- return null;
- }
-
- public int getEffectiveMinorVersion() {
- // implement me
- return -1;
- }
-
- public int getEffectiveMajorVersion() {
- // implement me
- return -1;
- }
-
-}
-
+++ /dev/null
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.tomcat.lite;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.servlet.ServletInputStream;
-
-
-/**
- * Wrapper around MessageReader
- *
- * @author Remy Maucherat
- * @author Jean-Francois Arcand
- * @author Costin Manolache
- */
-public class ServletInputStreamImpl extends ServletInputStream {
-
-
- // ----------------------------------------------------- Instance Variables
-
-
- protected InputStream ib;
-
-
- // ----------------------------------------------------------- Constructors
-
-
- public ServletInputStreamImpl(InputStream ib) {
- this.ib = ib;
- }
-
- // --------------------------------------------- ServletInputStream Methods
-
- public long skip(long n)
- throws IOException {
- return ib.skip(n);
- }
-
- public void mark(int readAheadLimit)
- {
- //try {
- ib.mark(readAheadLimit);
-// } catch (IOException e) {
-// e.printStackTrace();
-// }
- }
-
-
- public void reset()
- throws IOException {
- ib.reset();
- }
-
-
-
- public int read()
- throws IOException {
- return ib.read();
- }
-
- public int available() throws IOException {
- return ib.available();
- }
-
- public int read(final byte[] b) throws IOException {
- return ib.read(b, 0, b.length);
- }
-
-
- public int read(final byte[] b, final int off, final int len)
- throws IOException {
-
- return ib.read(b, off, len);
- }
-
-
- public int readLine(byte[] b, int off, int len) throws IOException {
- return super.readLine(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 {
- ib.close();
- }
-
-}
+++ /dev/null
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.tomcat.lite;
-
-import java.io.IOException;
-
-import javax.servlet.ServletOutputStream;
-
-
-/**
- * Coyote implementation of the servlet output stream.
- *
- * @author Costin Manolache
- * @author Remy Maucherat
- */
-public class ServletOutputStreamImpl
- extends ServletOutputStream {
-
-
- // ----------------------------------------------------- Instance Variables
-
-
- protected BodyWriter ob;
-
-
- // ----------------------------------------------------------- Constructors
-
-
- public ServletOutputStreamImpl(BodyWriter ob) {
- this.ob = ob;
- }
-
-
- // --------------------------------------------------------- Public Methods
-
-
- /**
- * Prevent cloning the facade.
- */
- protected Object clone()
- throws CloneNotSupportedException {
- throw new CloneNotSupportedException();
- }
-
-
- // -------------------------------------------------------- Package Methods
-
-
- /**
- * Clear facade.
- */
- void clear() {
- ob = null;
- }
-
-
- // --------------------------------------------------- OutputStream Methods
-
-
- public void write(int i)
- throws IOException {
- ob.writeByte(i);
- }
-
-
- public void write(byte[] b)
- throws IOException {
- write(b, 0, b.length);
- }
-
-
- public void write(byte[] b, int off, int len)
- throws IOException {
- ob.write(b, off, len);
- }
-
-
- /**
- * Will send the buffer to the client.
- */
- public void flush()
- throws IOException {
- ob.flush();
- }
-
-
- public void close()
- throws IOException {
- ob.close();
- }
-
-
- // -------------------------------------------- ServletOutputStream Methods
-
-
- public void print(String s)
- throws IOException {
- ob.write(s);
- }
-
-
-}
-
+++ /dev/null
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.tomcat.lite;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.Reader;
-
-
-
-/**
- * Coyote implementation of the buffred reader.
- *
- * @author Remy Maucherat
- */
-public class ServletReaderImpl
- extends BufferedReader {
-
-
- // -------------------------------------------------------------- Constants
-
-
- private static final char[] LINE_SEP = { '\r', '\n' };
- private static final int MAX_LINE_LENGTH = 4096;
-
-
- // ----------------------------------------------------- Instance Variables
-
-
- protected Reader ib;
-
-
- protected char[] lineBuffer = null;
-
-
- // ----------------------------------------------------------- Constructors
-
-
- public ServletReaderImpl(Reader ib) {
- super(ib, 1);
- this.ib = ib;
- }
-
- public void close()
- throws IOException {
- ib.close();
- }
-
-
- public int read()
- throws IOException {
- return ib.read();
- }
-
-
- public int read(char[] cbuf)
- throws IOException {
- return ib.read(cbuf, 0, cbuf.length);
- }
-
-
- public int read(char[] cbuf, int off, int len)
- throws IOException {
- return ib.read(cbuf, off, len);
- }
-
-
- public long skip(long n)
- throws IOException {
- return ib.skip(n);
- }
-
-
- public boolean ready()
- throws IOException {
- return ib.ready();
- }
-
-
- public boolean markSupported() {
- return true;
- }
-
-
- public void mark(int readAheadLimit)
- throws IOException {
- ib.mark(readAheadLimit);
- }
-
-
- public void reset()
- throws IOException {
- ib.reset();
- }
-
-
- // TODO: move the readLine functionality to base coyote IO
- public String readLine()
- throws IOException {
-
- if (lineBuffer == null) {
- lineBuffer = new char[MAX_LINE_LENGTH];
- }
-
- String result = null;
-
- int pos = 0;
- int end = -1;
- int skip = -1;
- StringBuilder aggregator = null;
- while (end < 0) {
- mark(MAX_LINE_LENGTH);
- while ((pos < MAX_LINE_LENGTH) && (end < 0)) {
- int nRead = read(lineBuffer, pos, MAX_LINE_LENGTH - pos);
- if (nRead < 0) {
- if (pos == 0) {
- return null;
- }
- end = pos;
- skip = pos;
- }
- for (int i = pos; (i < (pos + nRead)) && (end < 0); i++) {
- if (lineBuffer[i] == LINE_SEP[0]) {
- end = i;
- skip = i + 1;
- char nextchar;
- if (i == (pos + nRead - 1)) {
- nextchar = (char) read();
- } else {
- nextchar = lineBuffer[i+1];
- }
- if (nextchar == LINE_SEP[1]) {
- skip++;
- }
- } else if (lineBuffer[i] == LINE_SEP[1]) {
- end = i;
- skip = i + 1;
- }
- }
- if (nRead > 0) {
- pos += nRead;
- }
- }
- if (end < 0) {
- if (aggregator == null) {
- aggregator = new StringBuilder();
- }
- aggregator.append(lineBuffer);
- pos = 0;
- } else {
- reset();
- skip(skip);
- }
- }
-
- if (aggregator == null) {
- result = new String(lineBuffer, 0, end);
- } else {
- aggregator.append(lineBuffer, 0, end);
- result = aggregator.toString();
- }
-
- return result;
-
- }
-}
+++ /dev/null
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tomcat.lite;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.security.Principal;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-import java.util.TreeMap;
-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;
-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.tomcat.addons.UserSessionManager;
-import org.apache.tomcat.servlets.util.Enumerator;
-import org.apache.tomcat.servlets.util.LocaleParser;
-import org.apache.tomcat.servlets.util.RequestUtil;
-import org.apache.tomcat.util.buf.B2CConverter;
-import org.apache.tomcat.util.buf.ByteChunk;
-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
- */
-public class ServletRequestImpl implements HttpServletRequest {
-
- /**
- * The request attribute under which we store the array of X509Certificate
- * objects representing the certificate chain presented by our client,
- * if any.
- */
- public static final String CERTIFICATES_ATTR =
- "javax.servlet.request.X509Certificate";
-
- /**
- * The request attribute under which we store the name of the cipher suite
- * being used on an SSL connection (as an object of type
- * java.lang.String).
- */
- public static final String CIPHER_SUITE_ATTR =
- "javax.servlet.request.cipher_suite";
-
- /**
- * Request dispatcher state.
- */
- public static final String DISPATCHER_TYPE_ATTR =
- "org.apache.catalina.core.DISPATCHER_TYPE";
-
- /**
- * Request dispatcher path.
- */
- public static final String DISPATCHER_REQUEST_PATH_ATTR =
- "org.apache.catalina.core.DISPATCHER_REQUEST_PATH";
-
- /**
- * The servlet context attribute under which we store the class path
- * for our application class loader (as an object of type String),
- * delimited with the appropriate path delimiter for this platform.
- */
- public static final String CLASS_PATH_ATTR =
- "org.apache.catalina.jsp_classpath";
-
-
- /**
- * The request attribute under which we forward a Java exception
- * (as an object of type Throwable) to an error page.
- */
- public static final String EXCEPTION_ATTR =
- "javax.servlet.error.exception";
-
-
- /**
- * The request attribute under which we forward the request URI
- * (as an object of type String) of the page on which an error occurred.
- */
- public static final String EXCEPTION_PAGE_ATTR =
- "javax.servlet.error.request_uri";
-
-
- /**
- * The request attribute under which we forward a Java exception type
- * (as an object of type Class) to an error page.
- */
- public static final String EXCEPTION_TYPE_ATTR =
- "javax.servlet.error.exception_type";
-
-
- /**
- * The request attribute under which we forward an HTTP status message
- * (as an object of type STring) to an error page.
- */
- public static final String ERROR_MESSAGE_ATTR =
- "javax.servlet.error.message";
-
-
- /**
- * The request attribute under which we expose the value of the
- * <code><jsp-file></code> value associated with this servlet,
- * if any.
- */
- public static final String JSP_FILE_ATTR =
- "org.apache.catalina.jsp_file";
-
-
- /**
- * The request attribute under which we store the key size being used for
- * this SSL connection (as an object of type java.lang.Integer).
- */
- public static final String KEY_SIZE_ATTR =
- "javax.servlet.request.key_size";
-
- /**
- * The request attribute under which we store the session id being used
- * for this SSL connection (as an object of type java.lang.String).
- */
- public static final String SSL_SESSION_ID_ATTR =
- "javax.servlet.request.ssl_session";
-
- /**
- * The request attribute under which we forward a servlet name to
- * an error page.
- */
- public static final String SERVLET_NAME_ATTR =
- "javax.servlet.error.servlet_name";
-
-
- /**
- * The name of the cookie used to pass the session identifier back
- * and forth with the client.
- */
- public static final String SESSION_COOKIE_NAME = "JSESSIONID";
-
-
- /**
- * The name of the path parameter used to pass the session identifier
- * back and forth with the client.
- */
- public static final String SESSION_PARAMETER_NAME = "jsessionid";
-
-
- /**
- * The request attribute under which we forward an HTTP status code
- * (as an object of type Integer) to an error page.
- */
- public static final String STATUS_CODE_ATTR =
- "javax.servlet.error.status_code";
-
-
- /**
- * The subject under which the AccessControlContext is running.
- */
- public static final String SUBJECT_ATTR =
- "javax.security.auth.subject";
-
-
- /**
- * The servlet context attribute under which we store a temporary
- * working directory (as an object of type File) for use by servlets
- * within this web application.
- */
- public static final String WORK_DIR_ATTR =
- "javax.servlet.context.tempdir";
-
- protected static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
-
-
- /**
- * The default Locale if none are specified.
- */
- protected static Locale defaultLocale = Locale.getDefault();
-
- // ApplicationFilterFactory. What's the use ???
- private static Integer REQUEST_INTEGER = new Integer(8);
-
- /**
- * The match string for identifying a session ID parameter.
- */
- private static final String match = ";" + SESSION_PARAMETER_NAME + "=";
-
- /**
- * The set of cookies associated with this Request.
- */
- protected Cookie[] cookies = null;
-
-
- /**
- * The set of SimpleDateFormat formats to use in getDateHeader().
- *
- * Notice that because SimpleDateFormat is not thread-safe, we can't
- * declare formats[] as a static variable.
- */
- protected SimpleDateFormat formats[] = null;
-
-
- /**
- * The attributes associated with this Request, keyed by attribute name.
- */
- protected HashMap attributes = new HashMap();
-
-
- /**
- * List of read only attributes for this Request.
- */
- //private HashMap readOnlyAttributes = new HashMap();
-
-
- /**
- * The preferred Locales assocaited with this Request.
- */
- protected ArrayList locales = new ArrayList();
-
-
- /**
- * Authentication type.
- */
- protected String authType = null;
-
- /**
- * User principal.
- */
- protected Principal userPrincipal = null;
-
-
- /**
- * The Subject associated with the current AccessControllerContext
- */
- protected transient Subject subject = null;
-
-
- /**
- * The current dispatcher type.
- */
- protected Object dispatcherType = null;
-
-
- /**
- * The associated input buffer.
- */
- protected BodyReader inputBuffer;
-
- Connector connector;
-
- /**
- * ServletInputStream.
- */
- protected ServletInputStreamImpl inputStream;
-
-
- /**
- * Reader.
- */
- protected BufferedReader reader;
-
-
- /**
- * Using stream flag.
- */
- protected boolean usingInputStream = false;
-
-
- /**
- * Using writer flag.
- */
- protected boolean usingReader = false;
-
-
- /**
- * Session parsed flag.
- */
- protected boolean sessionParsed = false;
-
-
- /**
- * Request parameters parsed flag.
- */
- protected boolean parametersParsed = false;
-
-
- /**
- * Cookies parsed flag.
- */
- protected boolean cookiesParsed = false;
-
-
- /**
- * Secure flag.
- */
- protected boolean secure = false;
-
-
- /**
- * Hash map used in the getParametersMap method.
- */
- protected ParameterMap parameterMap = new ParameterMap();
-
-
- /**
- * The currently active session for this request.
- */
- protected HttpSession session = null;
-
-
- /**
- * The current request dispatcher path.
- */
- protected Object requestDispatcherPath = null;
-
-
- /**
- * Was the requested session ID received in a cookie?
- */
- protected boolean requestedSessionCookie = false;
-
-
- /**
- * The requested session ID (if any) for this request.
- */
- protected String requestedSessionId = null;
-
-
- /**
- * Was the requested session ID received in a URL?
- */
- protected boolean requestedSessionURL = false;
-
-
- /**
- * Parse locales.
- */
- protected boolean localesParsed = false;
-
-
- /**
- * Associated context.
- */
- protected ServletContextImpl context = null;
-
-
-
- // --------------------------------------------------------- Public Methods
-
- /**
- * Filter chain associated with the request.
- */
- protected FilterChainImpl filterChain = new FilterChainImpl();
-
- /**
- * Mapping data.
- */
- protected MappingData mappingData = new MappingData();
-
-
- // -------------------------------------------------------- Request Methods
-
- /**
- * The response with which this request is associated.
- */
- protected ServletResponseImpl response = new ServletResponseImpl();
-
- /**
- * URI byte to char converter (not recycled).
- */
- // protected B2CConverter URIConverter = null;
-
- /**
- * Associated wrapper.
- */
- protected ServletConfigImpl wrapper = null;
-
- /**
- * Post data buffer.
- */
- public final static int CACHED_POST_LEN = 8192;
-
- public byte[] postData = null;
-
-
- private HttpRequest httpRequest;
-
- /** New IO/buffer model
- */
- //protected Http11Connection con;
-
-
- public ServletRequestImpl() {
- response.setRequest(this);
- }
-
-
-// /**
-// * Return the Host within which this Request is being processed.
-// */
-// public Host getHost() {
-// if (getContext() == null)
-// return null;
-// return (Host) getContext().getParent();
-// //return ((Host) mappingData.host);
-// }
-//
-//
-// /**
-// * Set the Host within which this Request is being processed. This
-// * must be called as soon as the appropriate Host is identified, and
-// * before the Request is passed to a context.
-// *
-// * @param host The newly associated Host
-// */
-// public void setHost(Host host) {
-// mappingData.host = host;
-// }
-
- /**
- * Add a Cookie to the set of Cookies associated with this Request.
- *
- * @param cookie The new cookie
- */
- public void addCookie(Cookie cookie) {
-
- if (!cookiesParsed)
- parseCookies();
-
- int size = 0;
- if (cookies != null) {
- size = cookies.length;
- }
-
- Cookie[] newCookies = new Cookie[size + 1];
- for (int i = 0; i < size; i++) {
- newCookies[i] = cookies[i];
- }
- newCookies[size] = cookie;
-
- cookies = newCookies;
-
- }
-
- /**
- * Add a Header to the set of Headers associated with this Request.
- *
- * @param name The new header name
- * @param value The new header value
- */
- public void addHeader(String name, String value) {
- // 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
- * first added Locale will be the first one returned by getLocales().
- *
- * @param locale The new preferred Locale
- */
- public void addLocale(Locale locale) {
- locales.add(locale);
- }
-
-
- /**
- * Add a parameter name and corresponding set of values to this Request.
- * (This is used when restoring the original request on a form based
- * login).
- *
- * @param name Name of this request parameter
- * @param values Corresponding values for this request parameter
- */
- public void addParameter(String name, String values[]) {
- httpRequest.getParameters().addParameterValues(name, values);
- }
-
- /**
- * Clear the collection of Cookies associated with this Request.
- */
- public void clearCookies() {
- cookiesParsed = true;
- cookies = null;
- }
-
- /**
- * Clear the collection of Headers associated with this Request.
- */
- public void clearHeaders() {
- // Not used
- }
-
- /**
- * Clear the collection of Locales associated with this Request.
- */
- public void clearLocales() {
- locales.clear();
- }
-
- /**
- * Clear the collection of parameters associated with this Request.
- */
- public void clearParameters() {
- // Not used
- }
-
-
- /**
- * Create and return a ServletInputStream to read the content
- * associated with this Request.
- *
- * @exception IOException if an input/output error occurs
- */
- public ServletInputStream createInputStream()
- throws IOException {
- return inputStream;
- }
-
- /**
- * Perform whatever actions are required to flush and close the input
- * stream or reader, in a single operation.
- *
- * @exception IOException if an input/output error occurs
- */
- public void finishRequest() throws IOException {
- // The reader and input stream don't need to be closed
- }
-
-
- /**
- * Return the specified request attribute if it exists; otherwise, return
- * <code>null</code>.
- *
- * @param name Name of the request attribute to return
- */
- public Object getAttribute(String name) {
-
- if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
- return (dispatcherType == null)
- ? REQUEST_INTEGER
- : dispatcherType;
- } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
- return (requestDispatcherPath == null)
- ? getRequestPathMB().toString()
- : requestDispatcherPath.toString();
- }
-
- Object attr=attributes.get(name);
-
- if(attr!=null)
- return(attr);
-
-// attr = reqB.getAttribute(name);
-// if(attr != null)
-// return attr;
-// if( isSSLAttribute(name) ) {
-// reqB.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE,
-// reqB);
-// attr = reqB.getAttribute(ServletRequestImpl.CERTIFICATES_ATTR);
-// if( attr != null) {
-// attributes.put(ServletRequestImpl.CERTIFICATES_ATTR, attr);
-// }
-// attr = reqB.getAttribute(ServletRequestImpl.CIPHER_SUITE_ATTR);
-// if(attr != null) {
-// attributes.put(ServletRequestImpl.CIPHER_SUITE_ATTR, attr);
-// }
-// attr = reqB.getAttribute(ServletRequestImpl.KEY_SIZE_ATTR);
-// if(attr != null) {
-// attributes.put(ServletRequestImpl.KEY_SIZE_ATTR, attr);
-// }
-// attr = reqB.getAttribute(ServletRequestImpl.SSL_SESSION_ID_ATTR);
-// if(attr != null) {
-// attributes.put(ServletRequestImpl.SSL_SESSION_ID_ATTR, attr);
-// }
-// attr = attributes.get(name);
-// }
- return attr;
- }
-
- /**
- * Return the names of all request attributes for this Request, or an
- * empty <code>Enumeration</code> if there are none.
- */
- public Enumeration getAttributeNames() {
- if (isSecure()) {
- getAttribute(ServletRequestImpl.CERTIFICATES_ATTR);
- }
- return new Enumerator(attributes.keySet(), true);
- }
-
-
- /**
- * Return the authentication type used for this Request.
- */
- public String getAuthType() {
- return (authType);
- }
-
-
- // ------------------------------------------------- Request Public Methods
-
-
- /**
- * Return the character encoding for this Request.
- */
- public String getCharacterEncoding() {
- return (httpRequest.getCharacterEncoding());
- }
-
-
- /**
- * Return the content length for this Request.
- */
- public int getContentLength() {
- return (httpRequest.getContentLength());
- }
-
-
-// /**
-// * Return the object bound with the specified name to the internal notes
-// * for this request, or <code>null</code> if no such binding exists.
-// *
-// * @param name Name of the note to be returned
-// */
-// public Object getNote(String name) {
-// return (notes.get(name));
-// }
-//
-//
-// /**
-// * Return an Iterator containing the String names of all notes bindings
-// * that exist for this request.
-// */
-// public Iterator getNoteNames() {
-// return (notes.keySet().iterator());
-// }
-//
-//
-// /**
-// * Remove any object bound to the specified name in the internal notes
-// * for this request.
-// *
-// * @param name Name of the note to be removed
-// */
-// public void removeNote(String name) {
-// notes.remove(name);
-// }
-//
-//
-// /**
-// * Bind an object to a specified name in the internal notes associated
-// * with this request, replacing any existing binding for this name.
-// *
-// * @param name Name to which the object should be bound
-// * @param value Object to be bound to the specified name
-// */
-// public void setNote(String name, Object value) {
-// notes.put(name, value);
-// }
-//
-
- /**
- * Return the content type for this Request.
- */
- public String getContentType() {
- return (httpRequest.getContentType());
- }
-
-
- /**
- * Return the Context within which this Request is being processed.
- */
- public ServletContextImpl getContext() {
- return (this.context);
- }
-
-
- /**
- * Return the portion of the request URI used to select the Context
- * of the Request.
- */
- public String getContextPath() {
- return (mappingData.contextPath.toString());
- }
-
-
- /**
- * Get the context path.
- *
- * @return the context path
- */
- public MessageBytes getContextPathMB() {
- return (mappingData.contextPath);
- }
-
-
- /**
- * Return the set of Cookies received with this Request.
- */
- public Cookie[] getCookies() {
-
- if (!cookiesParsed)
- parseCookies();
-
- return cookies;
-
- }
-
-
- /**
- * Return the value of the specified date header, if any; otherwise
- * return -1.
- *
- * @param name Name of the requested date header
- *
- * @exception IllegalArgumentException if the specified header value
- * cannot be converted to a date
- */
- public long getDateHeader(String name) {
-
- String value = getHeader(name);
- if (value == null)
- return (-1L);
- if (formats == null) {
- formats = new SimpleDateFormat[] {
- new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
- new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
- new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
- };
- formats[0].setTimeZone(GMT_ZONE);
- formats[1].setTimeZone(GMT_ZONE);
- formats[2].setTimeZone(GMT_ZONE);
- }
-
- // Attempt to convert the date header in a variety of formats
- long result = FastHttpDateFormat.parseDate(value, formats);
- if (result != (-1L)) {
- return result;
- }
- throw new IllegalArgumentException(value);
-
- }
-
-
- /**
- * Get the decoded request URI.
- *
- * @return the URL decoded request URI
- */
- public String getDecodedRequestURI() {
- return (httpRequest.decodedURI().toString());
- }
-
-
- /**
- * Get the decoded request URI.
- *
- * @return the URL decoded request URI
- */
- public MessageBytes getDecodedRequestURIMB() {
- return (httpRequest.decodedURI());
- }
-
-
- /**
- * Get filter chain associated with the request.
- */
- public FilterChainImpl getFilterChain() {
- return (this.filterChain);
- }
-
-
- // ------------------------------------------------- ServletRequest Methods
-
- /**
- * Return the first value of the specified header, if any; otherwise,
- * return <code>null</code>
- *
- * @param name Name of the requested header
- */
- public String getHeader(String name) {
- return httpRequest.getHeader(name);
- }
-
- /**
- * Return the names of all headers received with this request.
- */
- public Enumeration getHeaderNames() {
- return httpRequest.getMimeHeaders().names();
- }
-
-
- /**
- * Return all of the values of the specified header, if any; otherwise,
- * return an empty enumeration.
- *
- * @param name Name of the requested header
- */
- public Enumeration getHeaders(String name) {
- return httpRequest.getMimeHeaders().values(name);
- }
-
- /**
- * Return the servlet input stream for this Request. The default
- * implementation returns a servlet input stream created by
- * <code>createInputStream()</code>.
- *
- * @exception IllegalStateException if <code>getReader()</code> has
- * already been called for this request
- * @exception IOException if an input/output error occurs
- */
- public ServletInputStream getInputStream() throws IOException {
-
- if (usingReader)
- throw new IllegalStateException
- ("usingReader");
-
- usingInputStream = true;
- return inputStream;
-
- }
-
-
- /**
- * Return the value of the specified header as an integer, or -1 if there
- * is no such header for this request.
- *
- * @param name Name of the requested header
- *
- * @exception IllegalArgumentException if the specified header value
- * cannot be converted to an integer
- */
- public int getIntHeader(String name) {
-
- String value = getHeader(name);
- if (value == null) {
- return (-1);
- } else {
- return (Integer.parseInt(value));
- }
-
- }
-
-
- /**
- * Returns the Internet Protocol (IP) address of the interface on
- * which the request was received.
- */
- public String getLocalAddr(){
- return httpRequest.localAddr().toString();
- }
-
-
- /**
- * Return the preferred Locale that the client will accept content in,
- * based on the value for the first <code>Accept-Language</code> header
- * that was encountered. If the request did not specify a preferred
- * language, the server's default Locale is returned.
- */
- public Locale getLocale() {
-
- if (!localesParsed)
- parseLocales();
-
- if (locales.size() > 0) {
- return ((Locale) locales.get(0));
- } else {
- return (defaultLocale);
- }
-
- }
-
-
- /**
- * Return the set of preferred Locales that the client will accept
- * content in, based on the values for any <code>Accept-Language</code>
- * headers that were encountered. If the request did not specify a
- * preferred language, the server's default Locale is returned.
- */
- public Enumeration getLocales() {
-
- if (!localesParsed)
- parseLocales();
-
- if (locales.size() > 0)
- return (new Enumerator(locales));
- ArrayList results = new ArrayList();
- results.add(defaultLocale);
- return (new Enumerator(results));
-
- }
-
-
- /**
- * Returns the host name of the Internet Protocol (IP) interface on
- * which the request was received.
- */
- public String getLocalName(){
- return httpRequest.localName().toString();
- }
-
-
- /**
- * Returns the Internet Protocol (IP) port number of the interface
- * on which the request was received.
- */
- public int getLocalPort(){
- return httpRequest.getLocalPort();
- }
-
-
- /**
- * Return mapping data.
- */
- public MappingData getMappingData() {
- return (mappingData);
- }
-
-
-
- /**
- * Return the HTTP request method used in this Request.
- */
- public String getMethod() {
- return httpRequest.method().toString();
- }
-
-
- /**
- * Return the value of the specified request parameter, if any; otherwise,
- * return <code>null</code>. If there is more than one value defined,
- * return only the first one.
- *
- * @param name Name of the desired request parameter
- */
- public String getParameter(String name) {
-
- if (!parametersParsed)
- parseParameters();
-
- return httpRequest.getParameters().getParameter(name);
-
- }
-
-
- /**
- * Returns a <code>Map</code> of the parameters of this request.
- * Request parameters are extra information sent with the request.
- * For HTTP servlets, parameters are contained in the query string
- * or posted form data.
- *
- * @return A <code>Map</code> containing parameter names as keys
- * and parameter values as map values.
- */
- public Map getParameterMap() {
-
- if (parameterMap.isLocked())
- return parameterMap;
-
- Enumeration enumeration = getParameterNames();
- while (enumeration.hasMoreElements()) {
- String name = enumeration.nextElement().toString();
- String[] values = getParameterValues(name);
- parameterMap.put(name, values);
- }
-
- parameterMap.setLocked(true);
-
- return parameterMap;
-
- }
-
-
- /**
- * Return the names of all defined request parameters for this request.
- */
- public Enumeration getParameterNames() {
-
- if (!parametersParsed)
- parseParameters();
-
- return httpRequest.getParameters().getParameterNames();
-
- }
-
-
- /**
- * Return the defined values for the specified request parameter, if any;
- * otherwise, return <code>null</code>.
- *
- * @param name Name of the desired request parameter
- */
- public String[] getParameterValues(String name) {
-
- if (!parametersParsed)
- parseParameters();
-
- return httpRequest.getParameters().getParameterValues(name);
-
- }
-
-
- /**
- * Return the path information associated with this Request.
- */
- public String getPathInfo() {
- return (mappingData.pathInfo.toString());
- }
-
-
- /**
- * Get the path info.
- *
- * @return the path info
- */
- public MessageBytes getPathInfoMB() {
- return (mappingData.pathInfo);
- }
-
-
- /**
- * Return the extra path information for this request, translated
- * to a real path.
- */
- public String getPathTranslated() {
-
- if (context == null)
- return (null);
-
- if (getPathInfo() == null) {
- return (null);
- } else {
- return (context.getServletContext().getRealPath(getPathInfo()));
- }
-
- }
-
- /**
- * Return the principal that has been authenticated for this Request.
- */
- public Principal getPrincipal() {
- return (userPrincipal);
- }
-
- /**
- * Return the protocol and version used to make this Request.
- */
- public String getProtocol() {
- return httpRequest.protocol().toString();
- }
-
- /**
- * Return the query string associated with this request.
- */
- public String getQueryString() {
- String queryString = httpRequest.queryString().toString();
- if (queryString == null || queryString.equals("")) {
- return (null);
- } else {
- return queryString;
- }
- }
-
-
- /**
- * Read the Reader wrapping the input stream for this Request. The
- * default implementation wraps a <code>BufferedReader</code> around the
- * servlet input stream returned by <code>createInputStream()</code>.
- *
- * @exception IllegalStateException if <code>getInputStream()</code>
- * has already been called for this request
- * @exception IOException if an input/output error occurs
- */
- public BufferedReader getReader() throws IOException {
-
- if (usingInputStream)
- throw new IllegalStateException
- ("usingInputStream");
-
- usingReader = true;
- //inputBuffer.setConverter();// getB2C());
- return reader;
-
- }
-
- /**
- * Cached list of encoders.
- */
- protected HashMap encoders = new HashMap();
-
- public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1";
-
- /**
- * Converter for the encoding associated with the request.
- * If encoding is changed - a different encoder will be returned.
- *
- * Encoders are cached ( per request ) - at least 8K per charset
- */
- public B2CConverter getB2C() throws IOException {
- String enc = getCharacterEncoding();
- if (enc == null) {
- enc = DEFAULT_CHARACTER_ENCODING;
- }
- B2CConverter conv =
- (B2CConverter) encoders.get(enc);
- if (conv == null) {
- conv = new B2CConverter(enc);
- encoders.put(enc, conv);
- }
- return conv;
- }
-
- /**
- * Return the real path of the specified virtual path.
- *
- * @param path Path to be translated
- *
- * @deprecated As of version 2.1 of the Java Servlet API, use
- * <code>ServletContext.getRealPath()</code>.
- */
- public String getRealPath(String path) {
-
- if (context == null)
- return (null);
- ServletContext servletContext = context; // .getServletContext();
- if (servletContext == null)
- return (null);
- else {
- try {
- return (servletContext.getRealPath(path));
- } catch (IllegalArgumentException e) {
- return (null);
- }
- }
-
- }
-
-
- /**
- * Return the remote IP address making this Request.
- */
- public String getRemoteAddr() {
- if (httpRequest.remoteAddr().isNull()) {
- httpRequest.remoteAddr().setString(connector.getRemoteAddr(this));
- }
- return httpRequest.remoteAddr().toString();
- }
-
-
- /**
- * Return the remote host name making this Request.
- */
- public String getRemoteHost() {
- if (httpRequest.remoteHost().isNull()) {
- httpRequest.remoteHost().setString(connector.getRemoteHost(this));
- }
- return httpRequest.remoteHost().toString();
- }
-
-
- /**
- * Returns the Internet Protocol (IP) source port of the client
- * or last proxy that sent the request.
- */
- public int getRemotePort(){
- return httpRequest.getRemotePort();
- }
-
-
- /**
- * Return the name of the remote user that has been authenticated
- * for this Request.
- */
- public String getRemoteUser() {
-
- if (userPrincipal != null) {
- return (userPrincipal.getName());
- } else {
- return (null);
- }
-
- }
-
-
- /**
- * Return the <code>ServletRequest</code> for which this object
- * is the facade. This method must be implemented by a subclass.
- */
- public HttpServletRequest getRequest() {
- return this;
- }
-
- public HttpRequest getHttpRequest() {
- return httpRequest;
- }
-
- 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
- * path, which may be interpreted as relative to the current request path.
- *
- * @param path Path of the resource to be wrapped
- */
- public RequestDispatcher getRequestDispatcher(String path) {
-
- if (context == null)
- return (null);
-
- // If the path is already context-relative, just pass it through
- if (path == null)
- return (null);
- else if (path.startsWith("/"))
- return (context.getRequestDispatcher(path));
-
- // Convert a request-relative path to a context-relative one
- String servletPath = (String) getAttribute(RequestDispatcherImpl.INCLUDE_SERVLET_PATH_ATTR);
- if (servletPath == null)
- servletPath = getServletPath();
-
- // Add the path info, if there is any
- String pathInfo = getPathInfo();
- String requestPath = null;
-
- if (pathInfo == null) {
- requestPath = servletPath;
- } else {
- requestPath = servletPath + pathInfo;
- }
-
- int pos = requestPath.lastIndexOf('/');
- String relative = null;
- if (pos >= 0) {
- relative = RequestUtil.normalize
- (requestPath.substring(0, pos + 1) + path);
- } else {
- relative = RequestUtil.normalize(requestPath + path);
- }
-
- return (context.getRequestDispatcher(relative));
-
- }
-
-
- /**
- * Return the session identifier included in this request, if any.
- */
- public String getRequestedSessionId() {
- return (requestedSessionId);
- }
-
-
- // ---------------------------------------------------- HttpRequest Methods
-
-
- /**
- * Get the request path.
- *
- * @return the request path
- */
- public MessageBytes getRequestPathMB() {
- return (mappingData.requestPath);
- }
-
-
- /**
- * Return the request URI for this request.
- */
- public String getRequestURI() {
- return httpRequest.requestURI().toString();
- }
-
- /**
- */
- public void setRequestURI(String uri) {
- httpRequest.decodedURI().setString(uri);
- try {
- UriNormalizer.decodeRequest(httpRequest.decodedURI(),
- httpRequest.requestURI(), httpRequest.getURLDecoder());
- } catch(IOException ioe) {
- ioe.printStackTrace();
- return;
- }
- }
-
-
-
- /**
- * Reconstructs the URL the client used to make the request.
- * The returned URL contains a protocol, server name, port
- * number, and server path, but it does not include query
- * string parameters.
- * <p>
- * Because this method returns a <code>StringBuffer</code>,
- * not a <code>String</code>, you can modify the URL easily,
- * for example, to append query parameters.
- * <p>
- * This method is useful for creating redirect messages and
- * for reporting errors.
- *
- * @return A <code>StringBuffer</code> object containing the
- * reconstructed URL
- */
- public StringBuffer getRequestURL() {
-
- StringBuffer url = new StringBuffer();
- String scheme = getScheme();
- int port = getServerPort();
- if (port < 0)
- port = 80; // Work around java.net.URL bug
-
- url.append(scheme);
- url.append("://");
- url.append(getServerName());
- if ((scheme.equals("http") && (port != 80))
- || (scheme.equals("https") && (port != 443))) {
- url.append(':');
- url.append(port);
- }
- url.append(getRequestURI());
-
- return (url);
-
- }
-
-
- /**
- * Return the Response with which this Request is associated.
- */
- public ServletResponseImpl getResponse() {
- return (this.response);
- }
-
-
- /**
- * Return the scheme used to make this Request.
- */
- public String getScheme() {
- String scheme = httpRequest.scheme().toString();
- if (scheme == null) {
- scheme = (isSecure() ? "https" : "http");
- }
- return scheme;
- }
-
-
- /**
- * Return the server name responding to this Request.
- */
- public String getServerName() {
- return (httpRequest.serverName().toString());
- }
-
-
- /**
- * Return the server port responding to this Request.
- */
- public int getServerPort() {
- return (httpRequest.getServerPort());
- }
-
-
- /**
- * Return the portion of the request URI used to select the servlet
- * that will process this request.
- */
- public String getServletPath() {
- return (mappingData.wrapperPath.toString());
- }
-
-
- /**
- * Get the servlet path.
- *
- * @return the servlet path
- */
- public MessageBytes getServletPathMB() {
- return (mappingData.wrapperPath);
- }
-
-
-
- /**
- * Return the input stream associated with this Request.
- */
- public InputStream getStream() {
- return inputStream;
- }
-
-
- /**
- * Return the principal that has been authenticated for this Request.
- */
- public Principal getUserPrincipal() {
- return userPrincipal;
- }
-
-
- /**
- * Return the Wrapper within which this Request is being processed.
- */
- public ServletConfigImpl getWrapper() {
- return (this.wrapper);
- }
-
-
- /**
- * Return <code>true</code> if the session identifier included in this
- * request came from a cookie.
- */
- public boolean isRequestedSessionIdFromCookie() {
-
- if (requestedSessionId != null)
- return (requestedSessionCookie);
- else
- return (false);
-
- }
-
-
- /**
- * Return <code>true</code> if the session identifier included in this
- * request came from the request URI.
- *
- * @deprecated As of Version 2.1 of the Java Servlet API, use
- * <code>isRequestedSessionIdFromURL()</code> instead.
- */
- public boolean isRequestedSessionIdFromUrl() {
- return (isRequestedSessionIdFromURL());
- }
-
-
- /**
- * Return <code>true</code> if the session identifier included in this
- * request came from the request URI.
- */
- public boolean isRequestedSessionIdFromURL() {
-
- if (requestedSessionId != null)
- return (requestedSessionURL);
- else
- return (false);
-
- }
-
-
- /**
- * Return <code>true</code> if the session identifier included in this
- * request identifies a valid session.
- */
- public boolean isRequestedSessionIdValid() {
-
- if (requestedSessionId == null)
- return (false);
- if (context == null)
- return (false);
- UserSessionManager manager = context.getManager();
- if (manager == null)
- return (false);
- HttpSession session = null;
- try {
- session = manager.findSession(requestedSessionId);
- } catch (IOException e) {
- session = null;
- }
- if ((session != null) && manager.isValid(session))
- return (true);
- else
- return (false);
-
- }
-
- /**
- * Was this request received on a secure connection?
- */
- public boolean isSecure() {
- return (secure);
- }
-
-
- /**
- * Return <code>true</code> if the authenticated user principal
- * possesses the specified role name.
- *
- * @param role Role name to be validated
- */
- public boolean isUserInRole(String role) {
- // Have we got an authenticated principal at all?
- Principal userPrincipal = getPrincipal();
- if (userPrincipal == null)
- return (false);
-
- // Identify the Realm we will use for checking role assignmenets
- if (context == null)
- return (false);
-
- // Check for a role alias defined in a <security-role-ref> element
- if (wrapper != null) {
- String realRole = wrapper.getSecurityRoleRef(role);
- if (realRole != null) {
- role = realRole;
- }
- }
-
- if (role.equals(userPrincipal.getName())) {
- return true;
- }
-
- // TODO: check !!!!
- // Check for a role defined directly as a <security-role>
- return false;
- }
-
- /**
- * Release all object references, and initialize instance variables, in
- * preparation for reuse of this object.
- */
- public void recycle() {
-
- wrapper = null;
-
- dispatcherType = null;
- requestDispatcherPath = null;
-
- authType = null;
- inputBuffer.recycle();
- usingInputStream = false;
- usingReader = false;
- userPrincipal = null;
- subject = null;
- sessionParsed = false;
- parametersParsed = false;
- cookiesParsed = false;
- locales.clear();
- localesParsed = false;
- secure = false;
-
- attributes.clear();
- //notes.clear();
- cookies = null;
-
- if (session != null) {
- context.getManager().endAccess(session);
- }
- context = null;
- session = null;
- requestedSessionCookie = false;
- requestedSessionId = null;
- requestedSessionURL = false;
-
- parameterMap.setLocked(false);
- parameterMap.clear();
-
- mappingData.recycle();
- httpRequest.recycle();
- }
-
-
- /**
- * Remove the specified request attribute if it exists.
- *
- * @param name Name of the request attribute to remove
- */
- public void removeAttribute(String name) {
- Object value = null;
- boolean found = false;
-
- // Remove the specified attribute
- // Check for read only attribute
- // requests are per thread so synchronization unnecessary
-// if (readOnlyAttributes.containsKey(name)) {
-// return;
-// }
- found = attributes.containsKey(name);
- if (found) {
- value = attributes.get(name);
- attributes.remove(name);
- } else {
- return;
- }
-
- // Notify interested application event listeners
- List listeners = context.getListeners();
- if (listeners.size() == 0)
- return;
- ServletRequestAttributeEvent event = null;
- for (int i = 0; i < listeners.size(); i++) {
- if (!(listeners.get(i) instanceof ServletRequestAttributeListener))
- continue;
- ServletRequestAttributeListener listener =
- (ServletRequestAttributeListener) listeners.get(i);
- try {
- if (event == null) {
- event =
- new ServletRequestAttributeEvent(context.getServletContext(),
- getRequest(), name, value);
- }
- listener.attributeRemoved(event);
- } catch (Throwable t) {
- context.getLogger().log(Level.WARNING, "ServletRequestAttributeListner.attributeRemoved()", t);
- // Error valve will pick this execption up and display it to user
- attributes.put( ServletRequestImpl.EXCEPTION_ATTR, t );
- }
- }
- }
-
-
- /**
- * Set the specified request attribute to the specified value.
- *
- * @param name Name of the request attribute to set
- * @param value The associated value
- */
- public void setAttribute(String name, Object value) {
-
- // Name cannot be null
- if (name == null)
- throw new IllegalArgumentException
- ("setAttribute() name == null");
-
- // Null value is the same as removeAttribute()
- if (value == null) {
- removeAttribute(name);
- return;
- }
-
- if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
- dispatcherType = value;
- return;
- } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
- requestDispatcherPath = value;
- return;
- }
-
- Object oldValue = null;
- boolean replaced = false;
-
- // Add or replace the specified attribute
- // Check for read only attribute
- // requests are per thread so synchronization unnecessary
-// if (readOnlyAttributes.containsKey(name)) {
-// return;
-// }
-
- oldValue = attributes.put(name, value);
- if (oldValue != null) {
- replaced = true;
- }
-
- // Pass special attributes to the native layer
-// if (name.startsWith("org.apache.tomcat.")) {
-// reqB.setAttribute(name, value);
-// }
-//
- // Notify interested application event listeners
- List listeners = context.getListeners();
- if (listeners.size() == 0)
- return;
- ServletRequestAttributeEvent event = null;
-
- for (int i = 0; i < listeners.size(); i++) {
- if (!(listeners.get(i) instanceof ServletRequestAttributeListener))
- continue;
- ServletRequestAttributeListener listener =
- (ServletRequestAttributeListener) listeners.get(i);
- try {
- if (event == null) {
- if (replaced)
- event =
- new ServletRequestAttributeEvent(context.getServletContext(),
- getRequest(), name, oldValue);
- else
- event =
- new ServletRequestAttributeEvent(context.getServletContext(),
- getRequest(), name, value);
- }
- if (replaced) {
- listener.attributeReplaced(event);
- } else {
- listener.attributeAdded(event);
- }
- } catch (Throwable t) {
- context.getLogger().log(Level.WARNING, "ServletRequestAttributeListener error", t);
- // Error valve will pick this execption up and display it to user
- attributes.put( ServletRequestImpl.EXCEPTION_ATTR, t );
- }
- }
- }
-
-
- // --------------------------------------------- HttpServletRequest Methods
-
-
- /**
- * Set the authentication type used for this request, if any; otherwise
- * set the type to <code>null</code>. Typical values are "BASIC",
- * "DIGEST", or "SSL".
- *
- * @param type The authentication type used
- */
- public void setAuthType(String type) {
- this.authType = type;
- }
-
-
- /**
- * Overrides the name of the character encoding used in the body of
- * this request. This method must be called prior to reading request
- * parameters or reading input using <code>getReader()</code>.
- *
- * @param enc The character encoding to be used
- *
- * @exception UnsupportedEncodingException if the specified encoding
- * is not supported
- *
- * @since Servlet 2.3
- */
- public void setCharacterEncoding(String enc)
- throws UnsupportedEncodingException {
-
- // Ensure that the specified encoding is valid
- byte buffer[] = new byte[1];
- buffer[0] = (byte) 'a';
- String dummy = new String(buffer, enc);
-
- // Save the validated encoding
- httpRequest.setCharacterEncoding(enc);
-
- }
-
-
-// public void setConnection(Http11Connection con) {
-// this.con = con;
-// //reqB.messageWriter.setConnection(con);
-// //inputBuffer.setRequest(req);
-// }
-
-
- /**
- * Set the content length associated with this Request.
- *
- * @param length The new content length
- */
- public void setContentLength(int length) {
- // Not used
- }
-
-
- /**
- * Set the content type (and optionally the character encoding)
- * associated with this Request. For example,
- * <code>text/html; charset=ISO-8859-4</code>.
- *
- * @param type The new content type
- */
- public void setContentType(String type) {
- // Not used
- }
-
-
- /**
- * Set the Context within which this Request is being processed. This
- * must be called as soon as the appropriate Context is identified, because
- * it identifies the value to be returned by <code>getContextPath()</code>,
- * and thus enables parsing of the request URI.
- *
- * @param context The newly associated Context
- */
- public void setContext(ServletContextImpl context) {
- this.context = context;
- }
-
-
- /**
- * Set the context path for this Request. This will normally be called
- * when the associated Context is mapping the Request to a particular
- * Wrapper.
- *
- * @param path The context path
- */
- public void setContextPath(String path) {
-
- if (path == null) {
- mappingData.contextPath.setString("");
- } else {
- mappingData.contextPath.setString(path);
- }
-
- }
-
-
- /**
- * Set the set of cookies recieved with this Request.
- */
- public void setCookies(Cookie[] cookies) {
-
- this.cookies = cookies;
-
- }
-
-
- /**
- * Set the decoded request URI.
- *
- * @param uri The decoded request URI
- */
- public void setDecodedRequestURI(String uri) {
- // Not used
- }
-
-
- /**
- * Set the HTTP request method used for this Request.
- *
- * @param method The request method
- */
- public void setMethod(String method) {
- httpRequest.method().setString(method);
- }
-
-
- /**
- * Set the path information for this Request. This will normally be called
- * when the associated Context is mapping the Request to a particular
- * Wrapper.
- *
- * @param path The path information
- */
- public void setPathInfo(String path) {
- mappingData.pathInfo.setString(path);
- }
-
-
- /**
- * Set the protocol name and version associated with this Request.
- *
- * @param protocol Protocol name and version
- */
- public void setProtocol(String protocol) {
- // Not used
- }
-
-
- /**
- * Set the query string for this Request. This will normally be called
- * by the HTTP Connector, when it parses the request headers.
- *
- * @param query The query string
- */
- public void setQueryString(String query) {
- // Not used
- }
-
-
- /**
- * Set the IP address of the remote client associated with this Request.
- *
- * @param remoteAddr The remote IP address
- */
- public void setRemoteAddr(String remoteAddr) {
- // Not used
- }
-
-
- /**
- * Set the fully qualified name of the remote client associated with this
- * Request.
- *
- * @param remoteHost The remote host name
- */
- public void setRemoteHost(String remoteHost) {
- // Not used
- }
-
-
- /**
- * Set a flag indicating whether or not the requested session ID for this
- * request came in through a cookie. This is normally called by the
- * HTTP Connector, when it parses the request headers.
- *
- * @param flag The new flag
- */
- public void setRequestedSessionCookie(boolean flag) {
-
- this.requestedSessionCookie = flag;
-
- }
-
-
- /**
- * Set the requested session ID for this request. This is normally called
- * by the HTTP Connector, when it parses the request headers.
- *
- * @param id The new session id
- */
- public void setRequestedSessionId(String id) {
-
- this.requestedSessionId = id;
-
- }
-
-
- /**
- * Set a flag indicating whether or not the requested session ID for this
- * request came in through a URL. This is normally called by the
- * HTTP Connector, when it parses the request headers.
- *
- * @param flag The new flag
- */
- public void setRequestedSessionURL(boolean flag) {
-
- this.requestedSessionURL = flag;
-
- }
-
-
- /**
- * Set the name of the scheme associated with this request. Typical values
- * are <code>http</code>, <code>https</code>, and <code>ftp</code>.
- *
- * @param scheme The scheme
- */
- public void setScheme(String scheme) {
- // Not used
- }
-
-
- /**
- * Set the value to be returned by <code>isSecure()</code>
- * for this Request.
- *
- * @param secure The new isSecure value
- */
- public void setSecure(boolean secure) {
- this.secure = secure;
- }
-
-
- /**
- * Set the name of the server (virtual host) to process this request.
- *
- * @param name The server name
- */
- public void setServerName(String name) {
- httpRequest.serverName().setString(name);
- }
-
-
- /**
- * Set the port number of the server to process this request.
- *
- * @param port The server port
- */
- public void setServerPort(int port) {
- httpRequest.setServerPort(port);
- }
-
-
- /**
- * Set the servlet path for this Request. This will normally be called
- * when the associated Context is mapping the Request to a particular
- * Wrapper.
- *
- * @param path The servlet path
- */
- public void setServletPath(String path) {
- if (path != null)
- mappingData.wrapperPath.setString(path);
- }
-
-
- /**
- * Set the input stream associated with this Request.
- *
- * @param stream The new input stream
- */
- public void setStream(InputStream stream) {
- // Ignore
- }
-
-
- /**
- * Set the Principal who has been authenticated for this Request. This
- * value is also used to calculate the value to be returned by the
- * <code>getRemoteUser()</code> method.
- *
- * @param principal The user Principal
- */
- public void setUserPrincipal(Principal principal) {
-
- if (System.getSecurityManager() != null){
- HttpSession session = getSession(false);
- if ( (subject != null) &&
- (!subject.getPrincipals().contains(principal)) ){
- subject.getPrincipals().add(principal);
- } else if (session != null &&
- session.getAttribute(ServletRequestImpl.SUBJECT_ATTR) == null) {
- subject = new Subject();
- subject.getPrincipals().add(principal);
- }
- if (session != null){
- session.setAttribute(ServletRequestImpl.SUBJECT_ATTR, subject);
- }
- }
-
- this.userPrincipal = principal;
- }
-
-
- /**
- * Set the Wrapper within which this Request is being processed. This
- * must be called as soon as the appropriate Wrapper is identified, and
- * before the Request is ultimately passed to an application servlet.
- * @param wrapper The newly associated Wrapper
- */
- public void setWrapper(ServletConfigImpl wrapper) {
- this.wrapper = wrapper;
- }
-
-
- public String toString() {
- return httpRequest.requestURI().toString();
- }
-
-
- /**
- * Configures the given JSESSIONID cookie.
- *
- * @param cookie The JSESSIONID cookie to be configured
- */
- protected void configureSessionCookie(Cookie cookie) {
- cookie.setMaxAge(-1);
- String contextPath = null;
- if (//!connector.getEmptySessionPath() &&
- (getContext() != null)) {
- contextPath = getContext().getEncodedPath();
- }
- if ((contextPath != null) && (contextPath.length() > 0)) {
- cookie.setPath(contextPath);
- } else {
- cookie.setPath("/");
- }
- if (isSecure()) {
- cookie.setSecure(true);
- }
- }
-
-
- /**
- * Return the session associated with this Request, creating one
- * if necessary.
- */
- public HttpSession getSession() {
- return getSession(true);
- }
-
-
- public HttpSession getSession(boolean create) {
-
- // There cannot be a session if no context has been assigned yet
- if (context == null)
- return (null);
-
-
- // Return the requested session if it exists and is valid
- UserSessionManager manager = null;
- if (context != null)
- manager = context.getManager();
- if (manager == null)
- return (null); // Sessions are not supported
-
- // Return the current session if it exists and is valid
- if ((session != null) && !manager.isValid(session))
- session = null;
- if (session != null)
- return (session);
-
-
- if (requestedSessionId != null) {
- try {
- session = manager.findSession(requestedSessionId);
- } catch (IOException e) {
- session = null;
- }
- if ((session != null) && !manager.isValid(session))
- session = null;
- if (session != null) {
- manager.access(session);
- return (session);
- }
- }
-
- // Create a new session if requested and the response is not committed
- if (!create)
- return (null);
- if ((context != null) && (response != null) &&
- context.getCookies() &&
- getResponse().isCommitted()) {
- throw new IllegalStateException
- ("isCommited()");
- }
-
- // Attempt to reuse session id if one was submitted in a cookie
- // Do not reuse the session id if it is from a URL, to prevent possible
- // phishing attacks
- if (// connector.getEmptySessionPath() &&
- isRequestedSessionIdFromCookie()) {
- session = manager.createSession(getRequestedSessionId());
- } else {
- session = manager.createSession(null);
- }
-
- // Creating a new session cookie based on that session
- if ((session != null) && (getContext() != null)
- && getContext().getCookies()) {
- Cookie cookie = new Cookie(ServletRequestImpl.SESSION_COOKIE_NAME,
- session.getId());
- configureSessionCookie(cookie);
- response.addCookie(cookie);
- }
-
- if (session != null) {
- manager.access(session);
- return (session);
- } else {
- return (null);
- }
-
- }
-
-
- /**
- * Return the URI converter.
- */
-// protected B2CConverter getURIConverter() {
-// return URIConverter;
-// }
-//
-
- // ------------------------------------------------------ Protected Methods
-
-
- /**
- * Parse cookies.
- */
- protected void parseCookies() {
-
- cookiesParsed = true;
-
- Cookies serverCookies = httpRequest.getCookies();
- int count = serverCookies.getCookieCount();
- if (count <= 0)
- return;
-
- cookies = new Cookie[count];
-
- int idx=0;
- for (int i = 0; i < count; i++) {
- ServerCookie scookie = serverCookies.getCookie(i);
- try {
- Cookie cookie = new Cookie(scookie.getName().toString(),
- scookie.getValue().toString());
- cookie.setPath(scookie.getPath().toString());
- cookie.setVersion(scookie.getVersion());
- String domain = scookie.getDomain().toString();
- if (domain != null) {
- cookie.setDomain(scookie.getDomain().toString());
- }
- cookies[idx++] = cookie;
- } catch(IllegalArgumentException e) {
- // Ignore bad cookie
- }
- }
- if( idx < count ) {
- Cookie [] ncookies = new Cookie[idx];
- System.arraycopy(cookies, 0, ncookies, 0, idx);
- cookies = ncookies;
- }
-
- }
-
- /**
- * Parse request locales.
- */
- protected void parseLocales() {
-
- localesParsed = true;
-
- Enumeration values = getHeaders("accept-language");
-
- while (values.hasMoreElements()) {
- String value = values.nextElement().toString();
- parseLocalesHeader(value);
- }
-
- }
-
- /**
- * Parse accept-language header value.
- */
- protected void parseLocalesHeader(String value) {
-
- TreeMap locales = new LocaleParser().parseLocale(value);
- // Process the quality values in highest->lowest order (due to
- // negating the Double value when creating the key)
- Iterator keys = locales.keySet().iterator();
- while (keys.hasNext()) {
- Double key = (Double) keys.next();
- ArrayList list = (ArrayList) locales.get(key);
- Iterator values = list.iterator();
- while (values.hasNext()) {
- Locale locale = (Locale) values.next();
- addLocale(locale);
- }
- }
-
- }
-
- /**
- * Parse request parameters.
- */
- protected void parseParameters() {
-
- parametersParsed = true;
-
- Parameters parameters = httpRequest.getParameters();
-
- // getCharacterEncoding() may have been overridden to search for
- // hidden form field containing request encoding
- String enc = getCharacterEncoding();
-
-// boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
- if (enc != null) {
- parameters.setEncoding(enc);
-// if (useBodyEncodingForURI) {
-// parameters.setQueryStringEncoding(enc);
-// }
- } else {
- parameters.setEncoding(DEFAULT_CHARACTER_ENCODING);
-// if (useBodyEncodingForURI) {
-// parameters.setQueryStringEncoding
-// (DEFAULT_CHARACTER_ENCODING);
-// }
- }
-
- parameters.handleQueryParameters();
-
- if (usingInputStream || usingReader)
- return;
-
- if (!getMethod().equalsIgnoreCase("POST"))
- return;
-
- String contentType = getContentType();
- if (contentType == null)
- contentType = "";
- int semicolon = contentType.indexOf(';');
- if (semicolon >= 0) {
- contentType = contentType.substring(0, semicolon).trim();
- } else {
- contentType = contentType.trim();
- }
- if (!("application/x-www-form-urlencoded".equals(contentType)))
- return;
-
- int len = getContentLength();
-
- if (len > 0) {
-// int maxPostSize = connector.getMaxPostSize();
-// if ((maxPostSize > 0) && (len > maxPostSize)) {
-// context.getLogger().info
-// (sm.getString("reqB.postTooLarge"));
-// throw new IllegalStateException("Post too large");
-// }
- try {
- byte[] formData = null;
- if (len < CACHED_POST_LEN) {
- if (postData == null)
- postData = new byte[CACHED_POST_LEN];
- formData = postData;
- } else {
- formData = new byte[len];
- }
- int actualLen = readPostBody(formData, len);
- if (actualLen == len) {
- parameters.processParameters(formData, 0, len);
- }
- } catch (Throwable t) {
- ; // Ignore
- }
- }
-
- }
-
-
- /**
- * Parse session id in URL. Done in request for performance.
- * TODO: should be done in manager
- */
- protected void parseSessionCookiesId() {
- String sessionCookieName = context.getSessionCookieName();
-
- // Parse session id from cookies
- Cookies serverCookies = httpRequest.getCookies();
- int count = serverCookies.getCookieCount();
- if (count <= 0)
- return;
-
- for (int i = 0; i < count; i++) {
- ServerCookie scookie = serverCookies.getCookie(i);
- if (scookie.getName().equals(sessionCookieName)) {
- // Override anything requested in the URL
- if (!isRequestedSessionIdFromCookie()) {
- // Accept only the first session id cookie
- //scookie.getValue().convertToAscii();
-
- setRequestedSessionId
- (scookie.getValue().toString());
- setRequestedSessionCookie(true);
- setRequestedSessionURL(false);
- } else {
- if (!isRequestedSessionIdValid()) {
- // Replace the session id until one is valid
- //scookie.getValue().convertToAscii();
- setRequestedSessionId
- (scookie.getValue().toString());
- }
- }
- }
- }
- }
-
- /**
- * Parse session id in URL.
- */
- protected void parseSessionId() {
- ServletRequestImpl request = this;
- ByteChunk uriBC = httpRequest.requestURI().getByteChunk();
- int semicolon = uriBC.indexOf(match, 0, match.length(), 0);
-
- if (semicolon > 0) {
-
- // Parse session ID, and extract it from the decoded request URI
- int start = uriBC.getStart();
- int end = uriBC.getEnd();
-
- int sessionIdStart = semicolon + match.length();
- int semicolon2 = uriBC.indexOf(';', sessionIdStart);
- if (semicolon2 >= 0) {
- request.setRequestedSessionId
- (new String(uriBC.getBuffer(), start + sessionIdStart,
- semicolon2 - sessionIdStart));
- // Extract session ID from request URI
- byte[] buf = uriBC.getBuffer();
- for (int i = 0; i < end - start - semicolon2; i++) {
- buf[start + semicolon + i]
- = buf[start + i + semicolon2];
- }
- uriBC.setBytes(buf, start, end - start - semicolon2 + semicolon);
- } else {
- request.setRequestedSessionId
- (new String(uriBC.getBuffer(), start + sessionIdStart,
- (end - start) - sessionIdStart));
- uriBC.setEnd(start + semicolon);
- }
- request.setRequestedSessionURL(true);
-
- } else {
- request.setRequestedSessionId(null);
- request.setRequestedSessionURL(false);
- }
-
- }
-
-
- /**
- * Read post body in an array.
- */
- protected int readPostBody(byte body[], int len)
- throws IOException {
-
- int offset = 0;
- do {
- int inputLen = getStream().read(body, offset, len - offset);
- if (inputLen <= 0) {
- return offset;
- }
- offset += inputLen;
- } while ((len - offset) > 0);
- return len;
-
- }
-
-
- /**
- * Test if a given name is one of the special Servlet-spec SSL attributes.
- */
- static boolean isSSLAttribute(String name) {
- return ServletRequestImpl.CERTIFICATES_ATTR.equals(name) ||
- ServletRequestImpl.CIPHER_SUITE_ATTR.equals(name) ||
- ServletRequestImpl.KEY_SIZE_ATTR.equals(name) ||
- ServletRequestImpl.SSL_SESSION_ID_ATTR.equals(name);
- }
-
-
- public void addAsyncListener(AsyncListener listener) {
- }
-
-
-
- public void addAsyncListener(AsyncListener listener,
- ServletRequest servletRequest,
- ServletResponse servletResponse) {
- }
-
-
-
- @Override
- public AsyncContext getAsyncContext() {
- return null;
- }
-
-
-
- @Override
- public ServletContext getServletContext() {
- return null;
- }
-
-
-
- @Override
- public boolean isAsyncStarted() {
- return false;
- }
-
-
-
- @Override
- public boolean isAsyncSupported() {
- return false;
- }
-
-
- public void setAsyncTimeout(long timeout) {
- }
-
-
-
- @Override
- public AsyncContext startAsync() throws IllegalStateException {
- return null;
- }
-
-
- @Override
- public AsyncContext startAsync(ServletRequest servletRequest,
- ServletResponse servletResponse)
- throws IllegalStateException {
- return null;
- }
-
-
-
- @Override
- public boolean authenticate(HttpServletResponse response)
- throws IOException, ServletException {
- return false;
- }
-
-
-
- @Override
- public Part getPart(String name) {
- return null;
- }
-
-
-
- @Override
- public void login(String username, String password) throws ServletException {
- }
-
-
-
- @Override
- public void logout() throws ServletException {
- }
-
-
-
- public long getAsyncTimeout() {
- return 0;
- }
-
-
-
- @Override
- public DispatcherType getDispatcherType() {
- return null;
- }
-
-
- @Override
- public Collection<Part> getParts() throws IOException, ServletException {
- return null;
- }
-
-
-}
+++ /dev/null
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.tomcat.lite;
-
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
-import javax.servlet.http.HttpSession;
-
-import org.apache.tomcat.addons.UserSessionManager;
-import org.apache.tomcat.servlets.util.Enumerator;
-import org.apache.tomcat.servlets.util.RequestUtil;
-
-
-/**
- * Wrapper around a <code>javax.servlet.http.HttpServletRequest</code>
- * that transforms an application request object (which might be the original
- * one passed to a servlet, or might be based on the 2.3
- * <code>javax.servlet.http.HttpServletRequestWrapper</code> class)
- * back into an internal <code>org.apache.catalina.HttpRequest</code>.
- * <p>
- * <strong>WARNING</strong>: Due to Java's lack of support for multiple
- * inheritance, all of the logic in <code>ApplicationRequest</code> is
- * duplicated in <code>ApplicationHttpRequest</code>. Make sure that you
- * keep these two classes in synchronization when making changes!
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
- */
-public class ServletRequestWrapperImpl extends HttpServletRequestWrapper {
-
-
- // ------------------------------------------------------- Static Variables
-
-
- /**
- * The set of attribute names that are special for request dispatchers.
- */
- protected static final String specials[] =
- { RequestDispatcherImpl.INCLUDE_REQUEST_URI_ATTR,
- RequestDispatcherImpl.INCLUDE_CONTEXT_PATH_ATTR,
- RequestDispatcherImpl.INCLUDE_SERVLET_PATH_ATTR,
- RequestDispatcherImpl.INCLUDE_PATH_INFO_ATTR,
- RequestDispatcherImpl.INCLUDE_QUERY_STRING_ATTR,
- RequestDispatcherImpl.FORWARD_REQUEST_URI_ATTR,
- RequestDispatcherImpl.FORWARD_CONTEXT_PATH_ATTR,
- RequestDispatcherImpl.FORWARD_SERVLET_PATH_ATTR,
- RequestDispatcherImpl.FORWARD_PATH_INFO_ATTR,
- RequestDispatcherImpl.FORWARD_QUERY_STRING_ATTR };
-
-
- // ----------------------------------------------------------- Constructors
-
-
- /**
- * Construct a new wrapped request around the specified servlet request.
- *
- * @param request The servlet request being wrapped
- */
- public ServletRequestWrapperImpl(HttpServletRequest request,
- ServletContextImpl context,
- boolean crossContext) {
-
- super(request);
- this.context = context;
- this.crossContext = crossContext;
- setRequest(request);
-
- }
-
-
- // ----------------------------------------------------- Instance Variables
-
-
- /**
- * The context for this request.
- */
- protected ServletContextImpl context = null;
-
-
- /**
- * The context path for this request.
- */
- protected String contextPath = null;
-
-
- /**
- * If this request is cross context, since this changes session accesss
- * behavior.
- */
- protected boolean crossContext = false;
-
-
- /**
- * The current dispatcher type.
- */
- protected Object dispatcherType = null;
-
-
- /**
- * Descriptive information about this implementation.
- */
- protected static final String info =
- "org.apache.catalina.core.ApplicationHttpRequest/1.0";
-
-
- /**
- * The request parameters for this request. This is initialized from the
- * wrapped request, but updates are allowed.
- */
- protected Map parameters = null;
-
-
- /**
- * Have the parameters for this request already been parsed?
- */
- private boolean parsedParams = false;
-
-
- /**
- * The path information for this request.
- */
- protected String pathInfo = null;
-
-
- /**
- * The query parameters for the current request.
- */
- private String queryParamString = null;
-
-
- /**
- * The query string for this request.
- */
- protected String queryString = null;
-
-
- /**
- * The current request dispatcher path.
- */
- protected Object requestDispatcherPath = null;
-
-
- /**
- * The request URI for this request.
- */
- protected String requestURI = null;
-
-
- /**
- * The servlet path for this request.
- */
- protected String servletPath = null;
-
-
- /**
- * The currently active session for this request.
- */
- protected HttpSession session = null;
-
-
- /**
- * Special attributes.
- */
- protected Object[] specialAttributes = new Object[specials.length];
-
-
- // ------------------------------------------------- ServletRequest Methods
-
-
- /**
- * Override the <code>getAttribute()</code> method of the wrapped request.
- *
- * @param name Name of the attribute to retrieve
- */
- public Object getAttribute(String name) {
-
- if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
- return dispatcherType;
- } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
- if ( requestDispatcherPath != null ){
- return requestDispatcherPath.toString();
- } else {
- return null;
- }
- }
-
- int pos = getSpecial(name);
- if (pos == -1) {
- return getRequest().getAttribute(name);
- } else {
- if ((specialAttributes[pos] == null)
- && (specialAttributes[5] == null) && (pos >= 5)) {
- // If it's a forward special attribute, and null, it means this
- // is an include, so we check the wrapped request since
- // the request could have been forwarded before the include
- return getRequest().getAttribute(name);
- } else {
- return specialAttributes[pos];
- }
- }
-
- }
-
-
- /**
- * Override the <code>getAttributeNames()</code> method of the wrapped
- * request.
- */
- public Enumeration getAttributeNames() {
- return (new AttributeNamesEnumerator());
- }
-
-
- /**
- * Override the <code>removeAttribute()</code> method of the
- * wrapped request.
- *
- * @param name Name of the attribute to remove
- */
- public void removeAttribute(String name) {
-
- if (!removeSpecial(name))
- getRequest().removeAttribute(name);
-
- }
-
-
- /**
- * Override the <code>setAttribute()</code> method of the
- * wrapped request.
- *
- * @param name Name of the attribute to set
- * @param value Value of the attribute to set
- */
- public void setAttribute(String name, Object value) {
-
- if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
- dispatcherType = value;
- return;
- } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
- requestDispatcherPath = value;
- return;
- }
-
- if (!setSpecial(name, value)) {
- getRequest().setAttribute(name, value);
- }
-
- }
-
-
- /**
- * Return a RequestDispatcher that wraps the resource at the specified
- * path, which may be interpreted as relative to the current request path.
- *
- * @param path Path of the resource to be wrapped
- */
- public RequestDispatcher getRequestDispatcher(String path) {
-
- if (context == null)
- return (null);
-
- // If the path is already context-relative, just pass it through
- if (path == null)
- return (null);
- else if (path.startsWith("/"))
- return (context.getServletContext().getRequestDispatcher(path));
-
- // Convert a request-relative path to a context-relative one
- String servletPath =
- (String) getAttribute(RequestDispatcherImpl.INCLUDE_SERVLET_PATH_ATTR);
- if (servletPath == null)
- servletPath = getServletPath();
-
- // Add the path info, if there is any
- String pathInfo = getPathInfo();
- String requestPath = null;
-
- if (pathInfo == null) {
- requestPath = servletPath;
- } else {
- requestPath = servletPath + pathInfo;
- }
-
- int pos = requestPath.lastIndexOf('/');
- String relative = null;
- if (pos >= 0) {
- relative = RequestUtil.normalize
- (requestPath.substring(0, pos + 1) + path);
- } else {
- relative = RequestUtil.normalize(requestPath + path);
- }
-
- return (context.getServletContext().getRequestDispatcher(relative));
-
- }
-
-
- // --------------------------------------------- HttpServletRequest Methods
-
-
- /**
- * Override the <code>getContextPath()</code> method of the wrapped
- * request.
- */
- public String getContextPath() {
-
- return (this.contextPath);
-
- }
-
-
- /**
- * Override the <code>getParameter()</code> method of the wrapped request.
- *
- * @param name Name of the requested parameter
- */
- public String getParameter(String name) {
-
- parseParameters();
-
- Object value = parameters.get(name);
- if (value == null)
- return (null);
- else if (value instanceof String[])
- return (((String[]) value)[0]);
- else if (value instanceof String)
- return ((String) value);
- else
- return (value.toString());
-
- }
-
-
- /**
- * Override the <code>getParameterMap()</code> method of the
- * wrapped request.
- */
- public Map getParameterMap() {
-
- parseParameters();
- return (parameters);
-
- }
-
-
- /**
- * Override the <code>getParameterNames()</code> method of the
- * wrapped request.
- */
- public Enumeration getParameterNames() {
-
- parseParameters();
- return (new Enumerator(parameters.keySet()));
-
- }
-
-
- /**
- * Override the <code>getParameterValues()</code> method of the
- * wrapped request.
- *
- * @param name Name of the requested parameter
- */
- public String[] getParameterValues(String name) {
-
- parseParameters();
- Object value = parameters.get(name);
- if (value == null)
- return ((String[]) null);
- else if (value instanceof String[])
- return ((String[]) value);
- else if (value instanceof String) {
- String values[] = new String[1];
- values[0] = (String) value;
- return (values);
- } else {
- String values[] = new String[1];
- values[0] = value.toString();
- return (values);
- }
-
- }
-
-
- /**
- * Override the <code>getPathInfo()</code> method of the wrapped request.
- */
- public String getPathInfo() {
-
- return (this.pathInfo);
-
- }
-
-
- /**
- * Override the <code>getQueryString()</code> method of the wrapped
- * request.
- */
- public String getQueryString() {
-
- return (this.queryString);
-
- }
-
-
- /**
- * Override the <code>getRequestURI()</code> method of the wrapped
- * request.
- */
- public String getRequestURI() {
-
- return (this.requestURI);
-
- }
-
-
- /**
- * Override the <code>getRequestURL()</code> method of the wrapped
- * request.
- */
- public StringBuffer getRequestURL() {
-
- StringBuffer url = new StringBuffer();
- String scheme = getScheme();
- int port = getServerPort();
- if (port < 0)
- port = 80; // Work around java.net.URL bug
-
- url.append(scheme);
- url.append("://");
- url.append(getServerName());
- if ((scheme.equals("http") && (port != 80))
- || (scheme.equals("https") && (port != 443))) {
- url.append(':');
- url.append(port);
- }
- url.append(getRequestURI());
-
- return (url);
-
- }
-
-
- /**
- * Override the <code>getServletPath()</code> method of the wrapped
- * request.
- */
- public String getServletPath() {
-
- return (this.servletPath);
-
- }
-
-
- /**
- * Return the session associated with this Request, creating one
- * if necessary.
- */
- public HttpSession getSession() {
- return (getSession(true));
- }
-
-
- /**
- * Return the session associated with this Request, creating one
- * if necessary and requested.
- *
- * @param create Create a new session if one does not exist
- */
- public HttpSession getSession(boolean create) {
-
- if (crossContext) {
-
- // There cannot be a session if no context has been assigned yet
- if (context == null)
- return (null);
- UserSessionManager manager = context.getManager();
- // Return the current session if it exists and is valid
- if (session != null && manager.isValid(session)) {
- return session;
- }
-
- HttpSession other = super.getSession(false);
- if (create && (other == null)) {
- // First create a session in the first context: the problem is
- // that the top level request is the only one which can
- // create the cookie safely
- other = super.getSession(true);
- }
- if (other != null) {
- HttpSession localSession = null;
- try {
- localSession =
- manager.findSession(other.getId());
- } catch (IOException e) {
- // Ignore
- }
- if (localSession == null && create) {
- localSession =
- context.getManager().createSession(other.getId());
- }
- if (localSession != null) {
- context.getManager().access(localSession);
- session = localSession;
- return session;
- }
- }
- return null;
-
- } else {
- return super.getSession(create);
- }
-
- }
-
-
- /**
- * Returns true if the request specifies a JSESSIONID that is valid within
- * the context of this ApplicationHttpRequest, false otherwise.
- *
- * @return true if the request specifies a JSESSIONID that is valid within
- * the context of this ApplicationHttpRequest, false otherwise.
- */
- public boolean isRequestedSessionIdValid() {
-
- if (crossContext) {
-
- String requestedSessionId = getRequestedSessionId();
- if (requestedSessionId == null)
- return (false);
- if (context == null)
- return (false);
- UserSessionManager manager = context.getManager();
- if (manager == null)
- return (false);
- HttpSession session = null;
- try {
- session = manager.findSession(requestedSessionId);
- } catch (IOException e) {
- session = null;
- }
- if ((session != null) && manager.isValid(session)) {
- return (true);
- } else {
- return (false);
- }
-
- } else {
- return super.isRequestedSessionIdValid();
- }
- }
-
-
- // -------------------------------------------------------- Package Methods
-
-
- /**
- * Recycle this request
- */
- public void recycle() {
- if (session != null) {
- context.getManager().endAccess(session);
- }
- }
-
-
- /**
- * Return descriptive information about this implementation.
- */
- public String getInfo() {
-
- return (info);
-
- }
-
-
- /**
- * Perform a shallow copy of the specified Map, and return the result.
- *
- * @param orig Origin Map to be copied
- */
- Map copyMap(Map orig) {
-
- if (orig == null)
- return (new HashMap());
- HashMap dest = new HashMap();
- Iterator keys = orig.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- dest.put(key, orig.get(key));
- }
- return (dest);
-
- }
-
-
- /**
- * Set the context path for this request.
- *
- * @param contextPath The new context path
- */
- void setContextPath(String contextPath) {
-
- this.contextPath = contextPath;
-
- }
-
-
- /**
- * Set the path information for this request.
- *
- * @param pathInfo The new path info
- */
- void setPathInfo(String pathInfo) {
-
- this.pathInfo = pathInfo;
-
- }
-
-
- /**
- * Set the query string for this request.
- *
- * @param queryString The new query string
- */
- void setQueryString(String queryString) {
-
- this.queryString = queryString;
-
- }
-
-
- /**
- * Set the request that we are wrapping.
- *
- * @param request The new wrapped request
- */
- void setRequest(HttpServletRequest request) {
-
- super.setRequest(request);
-
- // Initialize the attributes for this request
- dispatcherType = request.getAttribute(ServletRequestImpl.DISPATCHER_TYPE_ATTR);
- requestDispatcherPath =
- request.getAttribute(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR);
-
- // Initialize the path elements for this request
- contextPath = request.getContextPath();
- pathInfo = request.getPathInfo();
- queryString = request.getQueryString();
- requestURI = request.getRequestURI();
- servletPath = request.getServletPath();
-
- }
-
-
- /**
- * Set the request URI for this request.
- *
- * @param requestURI The new request URI
- */
- void setRequestURI(String requestURI) {
-
- this.requestURI = requestURI;
-
- }
-
-
- /**
- * Set the servlet path for this request.
- *
- * @param servletPath The new servlet path
- */
- void setServletPath(String servletPath) {
-
- this.servletPath = servletPath;
-
- }
-
-
- /**
- * Parses the parameters of this request.
- *
- * If parameters are present in both the query string and the request
- * content, they are merged.
- */
- void parseParameters() {
-
- if (parsedParams) {
- return;
- }
-
- parameters = new HashMap();
- parameters = copyMap(getRequest().getParameterMap());
- mergeParameters();
- parsedParams = true;
- }
-
-
- /**
- * Save query parameters for this request.
- *
- * @param queryString The query string containing parameters for this
- * request
- */
- void setQueryParams(String queryString) {
- this.queryParamString = queryString;
- }
-
-
- // ------------------------------------------------------ Protected Methods
-
-
- /**
- * Is this attribute name one of the special ones that is added only for
- * included servlets?
- *
- * @param name Attribute name to be tested
- */
- protected boolean isSpecial(String name) {
-
- for (int i = 0; i < specials.length; i++) {
- if (specials[i].equals(name))
- return (true);
- }
- return (false);
-
- }
-
-
- /**
- * Get a special attribute.
- *
- * @return the special attribute pos, or -1 if it is not a special
- * attribute
- */
- protected int getSpecial(String name) {
- for (int i = 0; i < specials.length; i++) {
- if (specials[i].equals(name)) {
- return (i);
- }
- }
- return (-1);
- }
-
-
- /**
- * Set a special attribute.
- *
- * @return true if the attribute was a special attribute, false otherwise
- */
- protected boolean setSpecial(String name, Object value) {
- for (int i = 0; i < specials.length; i++) {
- if (specials[i].equals(name)) {
- specialAttributes[i] = value;
- return (true);
- }
- }
- return (false);
- }
-
-
- /**
- * Remove a special attribute.
- *
- * @return true if the attribute was a special attribute, false otherwise
- */
- protected boolean removeSpecial(String name) {
- for (int i = 0; i < specials.length; i++) {
- if (specials[i].equals(name)) {
- specialAttributes[i] = null;
- return (true);
- }
- }
- return (false);
- }
-
-
- /**
- * Merge the two sets of parameter values into a single String array.
- *
- * @param values1 First set of values
- * @param values2 Second set of values
- */
- protected String[] mergeValues(Object values1, Object values2) {
-
- ArrayList results = new ArrayList();
-
- if (values1 == null)
- ;
- else if (values1 instanceof String)
- results.add(values1);
- else if (values1 instanceof String[]) {
- String values[] = (String[]) values1;
- for (int i = 0; i < values.length; i++)
- results.add(values[i]);
- } else
- results.add(values1.toString());
-
- if (values2 == null)
- ;
- else if (values2 instanceof String)
- results.add(values2);
- else if (values2 instanceof String[]) {
- String values[] = (String[]) values2;
- for (int i = 0; i < values.length; i++)
- results.add(values[i]);
- } else
- results.add(values2.toString());
-
- String values[] = new String[results.size()];
- return ((String[]) results.toArray(values));
-
- }
-
-
- // ------------------------------------------------------ Private Methods
-
-
- /**
- * Merge the parameters from the saved query parameter string (if any), and
- * the parameters already present on this request (if any), such that the
- * parameter values from the query string show up first if there are
- * duplicate parameter names.
- */
- private void mergeParameters() {
-
- if ((queryParamString == null) || (queryParamString.length() < 1))
- return;
-
- HashMap queryParameters = new HashMap();
- String encoding = getCharacterEncoding();
- if (encoding == null)
- encoding = "ISO-8859-1";
- try {
- RequestUtil.parseParameters
- (queryParameters, queryParamString, encoding);
- } catch (Exception e) {
- ;
- }
- Iterator keys = parameters.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- Object value = queryParameters.get(key);
- if (value == null) {
- queryParameters.put(key, parameters.get(key));
- continue;
- }
- queryParameters.put
- (key, mergeValues(value, parameters.get(key)));
- }
- parameters = queryParameters;
-
- }
-
-
- // ----------------------------------- AttributeNamesEnumerator Inner Class
-
-
- /**
- * Utility class used to expose the special attributes as being available
- * as request attributes.
- */
- protected class AttributeNamesEnumerator implements Enumeration {
-
- protected int pos = -1;
- protected int last = -1;
- protected Enumeration parentEnumeration = null;
- protected String next = null;
-
- public AttributeNamesEnumerator() {
- parentEnumeration = getRequest().getAttributeNames();
- for (int i = 0; i < specialAttributes.length; i++) {
- if (getAttribute(specials[i]) != null) {
- last = i;
- }
- }
- }
-
- public boolean hasMoreElements() {
- return ((pos != last) || (next != null)
- || ((next = findNext()) != null));
- }
-
- public Object nextElement() {
- if (pos != last) {
- for (int i = pos + 1; i <= last; i++) {
- if (getAttribute(specials[i]) != null) {
- pos = i;
- return (specials[i]);
- }
- }
- }
- String result = next;
- if (next != null) {
- next = findNext();
- } else {
- throw new NoSuchElementException();
- }
- return result;
- }
-
- protected String findNext() {
- String result = null;
- while ((result == null) && (parentEnumeration.hasMoreElements())) {
- String current = (String) parentEnumeration.nextElement();
- if (!isSpecial(current)) {
- result = current;
- }
- }
- return result;
- }
-
- }
-
-
-}
+++ /dev/null
-/*
- * 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.OutputStream;
-import java.io.PrintWriter;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.Locale;
-import java.util.TimeZone;
-import java.util.Vector;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-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;
-
-/**
- * Wrapper object for the Coyote response.
- *
- * @author Remy Maucherat
- * @author Craig R. McClanahan
- * @version $Revision$ $Date$
- */
-
-public class ServletResponseImpl
- implements HttpServletResponse {
-
- /**
- * Format for http response header date field
- * From DateTool
- */
- public static final String HTTP_RESPONSE_DATE_HEADER =
- "EEE, dd MMM yyyy HH:mm:ss zzz";
-
- // ----------------------------------------------------------- Constructors
-
-
- ServletResponseImpl() {
- urlEncoder.addSafeCharacter('/');
- }
-
-
- /**
- * The date format we will use for creating date headers.
- */
- protected SimpleDateFormat format = null;
-
-
- /**
- * The associated output buffer.
- */
- protected BodyWriter outputBuffer;
-
-
- /**
- * The associated output stream.
- */
- protected ServletOutputStreamImpl outputStream;
-
-
- /**
- * The associated writer.
- */
- protected PrintWriter writer;
-
-
- /**
- * The application commit flag.
- */
- protected boolean appCommitted = false;
-
-
- /**
- * The included flag.
- */
- protected boolean included = false;
-
-
- /**
- * The characterEncoding flag
- */
- private boolean isCharacterEncodingSet = false;
-
- /**
- * The error flag.
- */
- protected boolean error = false;
-
-
- /**
- * The set of Cookies associated with this Response.
- */
- protected ArrayList cookies = new ArrayList();
-
-
- /**
- * Using output stream flag.
- */
- protected boolean usingOutputStream = false;
-
-
- /**
- * Using writer flag.
- */
- protected boolean usingWriter = false;
-
-
- /**
- * The request with which this response is associated.
- */
- protected ServletRequestImpl req = null;
-
- /**
- * URL encoder.
- */
- protected UEncoder urlEncoder = new UEncoder();
-
-
- /**
- * Recyclable buffer to hold the redirect URL.
- */
- 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
-
-
- /**
- * Release all object references, and initialize instance variables, in
- * preparation for reuse of this object.
- */
- public void recycle() {
-
- usingOutputStream = false;
- usingWriter = false;
- appCommitted = false;
- commited = false;
- included = false;
- error = false;
- isCharacterEncodingSet = false;
-
- cookies.clear();
-
- outputBuffer.recycle();
-
- resB.recycle();
- }
-
-
- // ------------------------------------------------------- Response Methods
-
-
- /**
- * Return the number of bytes actually written to the output stream.
- */
- public int getContentCount() {
- return outputBuffer.getBytesWritten() + outputBuffer.getCharsWritten();
- }
-
-
- /**
- * Set the application commit flag.
- *
- * @param appCommitted The new application committed flag value
- */
- public void setAppCommitted(boolean appCommitted) {
- this.appCommitted = appCommitted;
- }
-
-
- /**
- * Application commit flag accessor.
- */
- public boolean isAppCommitted() {
- return (this.appCommitted || isCommitted() || isSuspended()
- || ((getHttpResponse().getContentLength() > 0)
- && (getContentCount() >= getHttpResponse().getContentLength())));
- }
-
-
- /**
- * Return the "processing inside an include" flag.
- */
- public boolean getIncluded() {
- return included;
- }
-
-
- /**
- * Set the "processing inside an include" flag.
- *
- * @param included <code>true</code> if we are currently inside a
- * RequestDispatcher.include(), else <code>false</code>
- */
- public void setIncluded(boolean included) {
- this.included = included;
- }
-
-
- /**
- * Return the Request with which this Response is associated.
- */
- public ServletRequestImpl getRequest() {
- return (this.req);
- }
-
- /**
- * Set the Request with which this Response is associated.
- *
- * @param request The new associated request
- */
- public void setRequest(ServletRequestImpl request) {
- this.req = (ServletRequestImpl) request;
- }
-
-
- /**
- * Return the output stream associated with this Response.
- */
- public OutputStream getStream() {
- return outputStream;
- }
-
-
- /**
- * Set the output stream associated with this Response.
- *
- * @param stream The new output stream
- */
- public void setStream(OutputStream stream) {
- // This method is evil
- }
-
-
- /**
- * Set the suspended flag.
- *
- * @param suspended The new suspended flag value
- */
- public void setSuspended(boolean suspended) throws IOException {
- //coyoteResponse.setCommitted(true);
- flushBuffer();
- outputBuffer.setSuspended(suspended);
- }
-
-
- /**
- * Suspended flag accessor.
- */
- public boolean isSuspended() {
- return outputBuffer.isSuspended();
- }
-
-
- /**
- * Set the error flag.
- */
- public void setError() {
- error = true;
- }
-
-
- /**
- * Error flag accessor.
- */
- public boolean isError() {
- return error;
- }
-
-
- /**
- * Create and return a ServletOutputStream to write the content
- * associated with this Response.
- *
- * @exception IOException if an input/output error occurs
- */
- public ServletOutputStream createOutputStream()
- throws IOException {
- // Probably useless
- return outputStream;
- }
-
- /**
- * Return the content type that was set or calculated for this response,
- * or <code>null</code> if no content type was set.
- */
- public String getContentType() {
- String ret = contentType;
-
- if (ret != null
- && characterEncoding != null
- && charsetSet) {
- ret = ret + ";charset=" + characterEncoding;
- }
-
- return ret;
- }
-
-
- /**
- * Return a PrintWriter that can be used to render error messages,
- * regardless of whether a stream or writer has already been acquired.
- *
- * @return Writer which can be used for error reports. If the response is
- * not an error report returned using sendError or triggered by an
- * unexpected exception thrown during the servlet processing
- * (and only in that case), null will be returned if the response stream
- * has already been used.
- *
- * @exception IOException if an input/output error occurs
- */
- public PrintWriter getReporter() throws IOException {
- if (outputBuffer.isNew()) {
- outputBuffer.checkConverter();
- if (writer == null) {
- writer = new ServletWriterImpl(outputBuffer);
- }
- return writer;
- } else {
- return null;
- }
- }
-
-
- // ------------------------------------------------ ServletResponse Methods
-
-
- /**
- * Flush the buffer and commit this response.
- *
- * @exception IOException if an input/output error occurs
- */
- public void flushBuffer()
- throws IOException {
- outputBuffer.flush();
- }
-
-
- /**
- * Return the actual buffer size used for this Response.
- */
- public int getBufferSize() {
- return outputBuffer.getBufferSize();
- }
-
-
- /**
- * Return the character encoding used for this Response.
- */
- public String getCharacterEncoding() {
- return characterEncoding;
- }
-
-
- /**
- * Return the servlet output stream associated with this Response.
- *
- * @exception IllegalStateException if <code>getWriter</code> has
- * already been called for this response
- * @exception IOException if an input/output error occurs
- */
- public ServletOutputStream getOutputStream()
- throws IOException {
-
- if (usingWriter)
- throw new IllegalStateException
- ("usingWriter");
-
- usingOutputStream = true;
- return outputStream;
-
- }
-
- public BodyWriter getBodyWriter() {
- return outputBuffer;
- }
-
- /**
- * Return the Locale assigned to this response.
- */
- public Locale getLocale() {
- return locale;
- }
-
-
- /**
- * Return the writer associated with this Response.
- *
- * @exception IllegalStateException if <code>getOutputStream</code> has
- * already been called for this response
- * @exception IOException if an input/output error occurs
- */
- public PrintWriter getWriter()
- throws IOException {
-
- if (usingOutputStream)
- throw new IllegalStateException
- ("usingOutputStream");
-
- /*
- * If the response's character encoding has not been specified as
- * described in <code>getCharacterEncoding</code> (i.e., the method
- * just returns the default value <code>ISO-8859-1</code>),
- * <code>getWriter</code> updates it to <code>ISO-8859-1</code>
- * (with the effect that a subsequent call to getContentType() will
- * include a charset=ISO-8859-1 component which will also be
- * reflected in the Content-Type response header, thereby satisfying
- * the Servlet spec requirement that containers must communicate the
- * character encoding used for the servlet response's writer to the
- * client).
- */
- setCharacterEncoding(getCharacterEncoding());
-
- usingWriter = true;
- outputBuffer.checkConverter();
- if (writer == null) {
- writer = new ServletWriterImpl(outputBuffer);
- }
- return writer;
-
- }
-
-
- /**
- * Has the output of this response already been committed?
- */
- public boolean isCommitted() {
- return getHttpResponse().isCommitted();
- }
-
- /**
- * Clear any content written to the buffer.
- *
- * @exception IllegalStateException if this response has already
- * been committed
- */
- public void reset() {
-
- if (included)
- return; // Ignore any call from an included servlet
-
- 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();
- }
-
-
- /**
- * Reset the data buffer but not any status or header information.
- *
- * @exception IllegalStateException if the response has already
- * been committed
- */
- public void resetBuffer() {
-
- if (isCommitted())
- throw new IllegalStateException("isCommitted");
-
- outputBuffer.reset();
-
- }
-
-
- /**
- * Set the buffer size to be used for this Response.
- *
- * @param size The new buffer size
- *
- * @exception IllegalStateException if this method is called after
- * output has been committed for this response
- */
- public void setBufferSize(int size) {
-
- if (isCommitted() || !outputBuffer.isNew())
- throw new IllegalStateException
- ("isCommitted || !isNew");
-
- outputBuffer.setBufferSize(size);
-
- }
-
-
- /**
- * Set the content length (in bytes) for this Response.
- * Ignored for writers if non-ISO-8859-1 encoding ( we could add more
- * encodings that are constant.
- */
- public void setContentLength(int length) {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- // writers can use variable-length encoding.
- if (usingWriter && !"ISO-8859-1".equals(getCharacterEncoding())) {
- return;
- }
- getHttpResponse().setContentLength(length);
-
- }
-
-
- /**
- * Set the content type for this Response.
- *
- * @param type The new content type
- */
- public void setContentType(String type) {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- // Ignore charset if getWriter() has already been called
- if (usingWriter) {
- if (type != null) {
- int index = type.indexOf(";");
- if (index != -1) {
- type = type.substring(0, index);
- }
- }
- }
-
- getHttpResponse().setContentType(type);
-
- // Check to see if content type contains charset
- if (type != null) {
- int index = type.indexOf(";");
- if (index != -1) {
- int len = type.length();
- index++;
- while (index < len && Character.isSpace(type.charAt(index))) {
- index++;
- }
- if (index+7 < len
- && type.charAt(index) == 'c'
- && type.charAt(index+1) == 'h'
- && type.charAt(index+2) == 'a'
- && type.charAt(index+3) == 'r'
- && type.charAt(index+4) == 's'
- && type.charAt(index+5) == 'e'
- && type.charAt(index+6) == 't'
- && type.charAt(index+7) == '=') {
- isCharacterEncodingSet = true;
- }
- }
- }
- }
-
-
- /*
- * Overrides the name of the character encoding used in the body
- * of the request. This method must be called prior to reading
- * request parameters or reading input using getReader().
- *
- * @param charset String containing the name of the chararacter encoding.
- */
- public void setCharacterEncoding(String charset) {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- // Ignore any call made after the getWriter has been invoked
- // The default should be used
- if (usingWriter)
- return;
-
- if (isCommitted())
- return;
- if (charset == null)
- return;
-
- characterEncoding = charset;
- charsetSet=true;
- isCharacterEncodingSet = true;
- }
-
-
-
- /**
- * Set the Locale that is appropriate for this response, including
- * setting the appropriate character encoding.
- *
- * @param locale The new locale
- */
- public void setLocale(Locale locale) {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- 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
- if (usingWriter)
- return;
-
- if (isCharacterEncodingSet) {
- return;
- }
-
- Locale2Charset cm = req.getContext().getCharsetMapper();
- String charset = cm.getCharset( locale );
- if ( charset != null ){
- setCharacterEncoding(charset);
- }
-
- }
-
-
- // --------------------------------------------------- HttpResponse Methods
-
-
- /**
- * Return an array of all cookies set for this response, or
- * a zero-length array if no cookies have been set.
- */
- public Cookie[] getCookies() {
- return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));
- }
-
-
- /**
- * Return the value for the specified header, or <code>null</code> if this
- * header has not been set. If more than one value was added for this
- * name, only the first is returned; use getHeaderValues() to retrieve all
- * of them.
- *
- * @param name Header name to look up
- */
- public String getHeader(String name) {
- return getHttpResponse().getMimeHeaders().getHeader(name);
- }
-
-
- /**
- * Return an array of all the header names set for this response, or
- * a zero-length array if no headers have been set.
- */
- public Collection<String> getHeaderNames() {
-
- MimeHeaders headers = getHttpResponse().getMimeHeaders();
- int n = headers.size();
- ArrayList<String> result = new ArrayList<String>();
- for (int i = 0; i < n; i++) {
- result.add(headers.getName(i).toString());
- }
- return result;
- }
-
-
- /**
- * Return an array of all the header values associated with the
- * specified header name, or an zero-length array if there are no such
- * header values.
- *
- * @param name Header name to look up
- */
- public String[] getHeaderValues(String name) {
-
- Enumeration enumeration = getHttpResponse().getMimeHeaders().values(name);
- Vector result = new Vector();
- while (enumeration.hasMoreElements()) {
- result.addElement(enumeration.nextElement());
- }
- String[] resultArray = new String[result.size()];
- result.copyInto(resultArray);
- return resultArray;
-
- }
-
-
- /**
- * Return the error message that was set with <code>sendError()</code>
- * for this Response.
- */
- public String getMessage() {
- return getHttpResponse().getMessage();
- }
-
-
- /**
- * Return the HTTP status code associated with this Response.
- */
- public int getStatus() {
- return getHttpResponse().getStatus();
- }
-
-
- /**
- * Reset this response, and specify the values for the HTTP status code
- * and corresponding message.
- *
- * @exception IllegalStateException if this response has already been
- * committed
- */
- public void reset(int status, String message) {
- reset();
- setStatus(status, message);
- }
-
-
- // -------------------------------------------- HttpServletResponse Methods
-
-
- /**
- * Add the specified Cookie to those that will be included with
- * this Response.
- *
- * @param cookie Cookie to be added
- */
- public void addCookie(final Cookie cookie) {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- cookies.add(cookie);
-
- final StringBuffer sb = new StringBuffer();
- ServerCookie.appendCookieValue
- (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
- cookie.getPath(), cookie.getDomain(), cookie.getComment(),
- cookie.getMaxAge(), cookie.getSecure(), false);
-
- // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 )
- // RFC2965 is not supported by browsers and the Servlet spec
- // asks for 2109.
- addHeader("Set-Cookie", sb.toString());
-
- }
-
-
- /**
- * Add the specified date header to the specified value.
- *
- * @param name Name of the header to set
- * @param value Date value to be set
- */
- public void addDateHeader(String name, long value) {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included) {
- return;
- }
-
- if (format == null) {
- format = new SimpleDateFormat(HTTP_RESPONSE_DATE_HEADER,
- Locale.US);
- format.setTimeZone(TimeZone.getTimeZone("GMT"));
- }
-
- addHeader(name, FastHttpDateFormat.formatDate(value, format));
-
- }
-
-
- /**
- * Add the specified header to the specified value.
- *
- * @param name Name of the header to set
- * @param value Value to be set
- */
- public void addHeader(String name, String value) {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- getHttpResponse().addHeader(name, value);
-
- }
-
-
- /**
- * Add the specified integer header to the specified value.
- *
- * @param name Name of the header to set
- * @param value Integer value to be set
- */
- public void addIntHeader(String name, int value) {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- addHeader(name, "" + value);
-
- }
-
-
- /**
- * Has the specified header been set already in this response?
- *
- * @param name Name of the header to check
- */
- public boolean containsHeader(String name) {
- // Need special handling for Content-Type and Content-Length due to
- // special handling of these in coyoteResponse
- char cc=name.charAt(0);
- if(cc=='C' || cc=='c') {
- if(name.equalsIgnoreCase("Content-Type")) {
- // Will return null if this has not been set
- return getContentType() != null;
- }
- if(name.equalsIgnoreCase("Content-Length")) {
- // -1 means not known and is not sent to client
- return (getHttpResponse().getContentLength() != -1);
- }
- }
-
- return getHttpResponse().containsHeader(name);
- }
-
-
- /**
- * Encode the session identifier associated with this response
- * into the specified redirect URL, if necessary.
- *
- * @param url URL to be encoded
- */
- public String encodeRedirectURL(String url) {
-
- if (isEncodeable(toAbsolute(url))) {
- return (toEncoded(url, req.getSession().getId()));
- } else {
- return (url);
- }
-
- }
-
-
- /**
- * Encode the session identifier associated with this response
- * into the specified redirect URL, if necessary.
- *
- * @param url URL to be encoded
- *
- * @deprecated As of Version 2.1 of the Java Servlet API, use
- * <code>encodeRedirectURL()</code> instead.
- */
- public String encodeRedirectUrl(String url) {
- return (encodeRedirectURL(url));
- }
-
-
- /**
- * Encode the session identifier associated with this response
- * into the specified URL, if necessary.
- *
- * @param url URL to be encoded
- */
- public String encodeURL(String url) {
-
- String absolute = toAbsolute(url);
- if (isEncodeable(absolute)) {
- // W3c spec clearly said
- if (url.equalsIgnoreCase("")){
- url = absolute;
- }
- return (toEncoded(url, req.getSession().getId()));
- } else {
- return (url);
- }
-
- }
-
-
- /**
- * Encode the session identifier associated with this response
- * into the specified URL, if necessary.
- *
- * @param url URL to be encoded
- *
- * @deprecated As of Version 2.1 of the Java Servlet API, use
- * <code>encodeURL()</code> instead.
- */
- public String encodeUrl(String url) {
- return (encodeURL(url));
- }
-
-
- /**
- * Send an acknowledgment of a request.
- *
- * @exception IOException if an input/output error occurs
- */
- public void sendAcknowledgement()
- throws IOException {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- req.getConnector().acknowledge(this);
- }
-
-
- /**
- * Send an error response with the specified status and a
- * default message.
- *
- * @param status HTTP status code to send
- *
- * @exception IllegalStateException if this response has
- * already been committed
- * @exception IOException if an input/output error occurs
- */
- public void sendError(int status)
- throws IOException {
- sendError(status, null);
- }
-
-
- /**
- * Send an error response with the specified status and message.
- *
- * @param status HTTP status code to send
- * @param message Corresponding message to send
- *
- * @exception IllegalStateException if this response has
- * already been committed
- * @exception IOException if an input/output error occurs
- */
- public void sendError(int status, String message)
- throws IOException {
-
- if (isCommitted())
- throw new IllegalStateException
- ("isCommitted");
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- setError();
-
- getHttpResponse().setStatus(status);
- getHttpResponse().setMessage(message);
-
- // Clear any data content that has been buffered
- resetBuffer();
-
- // Cause the response to be finished (from the application perspective)
- String statusPage = req.getContext().findStatusPage(status);
-
- if (statusPage != null) {
- req.getContext().handleStatusPage(req, this, status, statusPage);
- } else {
- // Send a default message body.
- // TODO: maybe other mechanism to customize default.
- defaultStatusPage(status, message);
- }
- setSuspended(true);
- }
-
- /**
- * Default handler for status code != 200
- */
- void defaultStatusPage(int status, String message)
- throws IOException {
- setContentType("text/html");
- if (status > 400 && status < 600) {
- if (getOutputBuffer().getBytesWritten() == 0) {
- getOutputBuffer().write("<html><body><h1>Status: " +
- status + "</h1><h1>Message: " + message +
- "</h1></body></html>");
- getOutputBuffer().flush();
- }
- }
- }
-
-
-
- /**
- * Send a temporary redirect to the specified redirect location URL.
- *
- * @param location Location URL to redirect to
- *
- * @exception IllegalStateException if this response has
- * already been committed
- * @exception IOException if an input/output error occurs
- */
- public void sendRedirect(String location)
- throws IOException {
-
- if (isCommitted())
- throw new IllegalStateException
- ("isCommitted");
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- // Clear any data content that has been buffered
- resetBuffer();
-
- // Generate a temporary redirect to the specified location
- try {
- String absolute = toAbsolute(location);
- setStatus(SC_FOUND);
- setHeader("Location", absolute);
- } catch (IllegalArgumentException e) {
- setStatus(SC_NOT_FOUND);
- }
-
- // Cause the response to be finished (from the application perspective)
- setSuspended(true);
-
- }
-
-
- /**
- * Set the specified date header to the specified value.
- *
- * @param name Name of the header to set
- * @param value Date value to be set
- */
- public void setDateHeader(String name, long value) {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included) {
- return;
- }
-
- if (format == null) {
- format = new SimpleDateFormat(HTTP_RESPONSE_DATE_HEADER,
- Locale.US);
- format.setTimeZone(TimeZone.getTimeZone("GMT"));
- }
-
- setHeader(name, FastHttpDateFormat.formatDate(value, format));
-
- }
-
-
- /**
- * Set the specified header to the specified value.
- *
- * @param name Name of the header to set
- * @param value Value to be set
- */
- public void setHeader(String name, String value) {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- getHttpResponse().setHeader(name, value);
-
- }
-
-
- /**
- * Set the specified integer header to the specified value.
- *
- * @param name Name of the header to set
- * @param value Integer value to be set
- */
- public void setIntHeader(String name, int value) {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- setHeader(name, "" + value);
-
- }
-
-
- /**
- * Set the HTTP status to be returned with this response.
- *
- * @param status The new HTTP status
- */
- public void setStatus(int status) {
- setStatus(status, null);
- }
-
-
- /**
- * Set the HTTP status and message to be returned with this response.
- *
- * @param status The new HTTP status
- * @param message The associated text message
- *
- * @deprecated As of Version 2.1 of the Java Servlet API, this method
- * has been deprecated due to the ambiguous meaning of the message
- * parameter.
- */
- public void setStatus(int status, String message) {
-
- if (isCommitted())
- return;
-
- // Ignore any call from an included servlet
- if (included)
- return;
-
- getHttpResponse().setStatus(status);
- getHttpResponse().setMessage(message);
-
- }
-
-
- // ------------------------------------------------------ Protected Methods
-
-
- /**
- * Return <code>true</code> if the specified URL should be encoded with
- * a session identifier. This will be true if all of the following
- * conditions are met:
- * <ul>
- * <li>The request we are responding to asked for a valid session
- * <li>The requested session ID was not received via a cookie
- * <li>The specified URL points back to somewhere within the web
- * application that is responding to this request
- * </ul>
- *
- * @param location Absolute URL to be validated
- */
- protected boolean isEncodeable(final String location) {
-
- if (location == null)
- return (false);
-
- // Is this an intra-document reference?
- if (location.startsWith("#"))
- return (false);
-
- // Are we in a valid session that is not using cookies?
- final ServletRequestImpl hreq = req;
- final HttpSession session = hreq.getSession(false);
- if (session == null)
- return (false);
- if (hreq.isRequestedSessionIdFromCookie())
- return (false);
-
- // Is this a valid absolute URL?
- URL url = null;
- try {
- url = new URL(location);
- } catch (MalformedURLException e) {
- return (false);
- }
-
- // Does this URL match down to (and including) the context path?
- if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol()))
- return (false);
- if (!hreq.getServerName().equalsIgnoreCase(url.getHost()))
- return (false);
- int serverPort = hreq.getServerPort();
- if (serverPort == -1) {
- if ("https".equals(hreq.getScheme()))
- serverPort = 443;
- else
- serverPort = 80;
- }
- int urlPort = url.getPort();
- if (urlPort == -1) {
- if ("https".equals(url.getProtocol()))
- urlPort = 443;
- else
- urlPort = 80;
- }
- if (serverPort != urlPort)
- return (false);
-
- String contextPath = req.getContext().getContextPath();
- if (contextPath != null) {
- String file = url.getFile();
- if ((file == null) || !file.startsWith(contextPath))
- return (false);
- if( file.indexOf(";jsessionid=" + session.getId()) >= 0 )
- return (false);
- }
-
- // This URL belongs to our web application, so it is encodeable
- return (true);
-
- }
-
-
- /**
- * Convert (if necessary) and return the absolute URL that represents the
- * resource referenced by this possibly relative URL. If this URL is
- * already absolute, return it unchanged.
- *
- * @param location URL to be (possibly) converted and then returned
- *
- * @exception IllegalArgumentException if a MalformedURLException is
- * thrown when converting the relative URL to an absolute one
- */
- private String toAbsolute(String location) {
-
- if (location == null)
- return (location);
-
- boolean leadingSlash = location.startsWith("/");
-
- if (leadingSlash || !hasScheme(location)) {
-
- redirectURLCC.recycle();
-
- String scheme = req.getScheme();
- String name = req.getServerName();
- int port = req.getServerPort();
-
- try {
- redirectURLCC.append(scheme, 0, scheme.length());
- redirectURLCC.append("://", 0, 3);
- redirectURLCC.append(name, 0, name.length());
- if ((scheme.equals("http") && port != 80)
- || (scheme.equals("https") && port != 443)) {
- redirectURLCC.append(':');
- String portS = port + "";
- redirectURLCC.append(portS, 0, portS.length());
- }
- if (!leadingSlash) {
- String relativePath = req.getDecodedRequestURI();
- int pos = relativePath.lastIndexOf('/');
- relativePath = relativePath.substring(0, pos);
-
- String encodedURI = null;
- encodedURI = urlEncoder.encodeURL(relativePath);
- redirectURLCC.append(encodedURI, 0, encodedURI.length());
- redirectURLCC.append('/');
- }
- redirectURLCC.append(location, 0, location.length());
- } catch (IOException e) {
- IllegalArgumentException iae =
- new IllegalArgumentException(location);
- iae.initCause(e);
- throw iae;
- }
-
- return redirectURLCC.toString();
-
- } else {
-
- return (location);
-
- }
-
- }
-
-
- /**
- * Determine if a URI string has a <code>scheme</code> component.
- */
- private boolean hasScheme(String uri) {
- int len = uri.length();
- for(int i=0; i < len ; i++) {
- char c = uri.charAt(i);
- if(c == ':') {
- return i > 0;
- } else if(!isSchemeChar(c)) {
- return false;
- }
- }
- return false;
- }
-
- /**
- * Determine if the character is allowed in the scheme of a URI.
- * See RFC 2396, Section 3.1
- */
- private static boolean isSchemeChar(char c) {
- return Character.isLetterOrDigit(c) ||
- c == '+' || c == '-' || c == '.';
- }
-
-
- /**
- * Return the specified URL with the specified session identifier
- * suitably encoded.
- *
- * @param url URL to be encoded with the session id
- * @param sessionId Session id to be included in the encoded URL
- */
- protected String toEncoded(String url, String sessionId) {
-
- if ((url == null) || (sessionId == null))
- return (url);
-
- String path = url;
- String query = "";
- String anchor = "";
- int question = url.indexOf('?');
- if (question >= 0) {
- path = url.substring(0, question);
- query = url.substring(question);
- }
- int pound = path.indexOf('#');
- if (pound >= 0) {
- anchor = path.substring(pound);
- path = path.substring(0, pound);
- }
- StringBuffer sb = new StringBuffer(path);
- if( sb.length() > 0 ) { // jsessionid can't be first.
- sb.append(";jsessionid=");
- sb.append(sessionId);
- }
- sb.append(anchor);
- sb.append(query);
- return (sb.toString());
-
- }
-
-
- public int getBytesWritten() {
- return outputBuffer.getBytesWritten();
- }
-
- public BodyWriter getOutputBuffer() {
- return outputBuffer;
- }
-
- public void setWriter(BodyWriter ob) {
- outputBuffer = ob;
- outputStream = new ServletOutputStreamImpl(outputBuffer);
- }
-
- public CharSequence getResponseHeader(String name) {
- MessageBytes v = getHttpResponse().getMimeHeaders().getValue(name);
- return (v == null) ? null : v.toString();
- }
-
-
- public HttpResponse getHttpResponse() {
- return resB;
- }
-
-
- public void setHttpResponse(HttpResponse resB, BodyWriter ob) {
- this.resB = resB;
- setWriter(ob);
- }
-
-
-
- @Override
- public Collection<String> getHeaders(String name) {
- return null;
- }
-
-
-}
-
+++ /dev/null
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.tomcat.lite;
-
-
-import java.io.IOException;
-import java.util.Locale;
-
-import javax.servlet.ServletResponse;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpServletResponseWrapper;
-
-
-/**
- * Wrapper around the response object received as parameter to
- * RequestDispatcher.include().
- *
- * @author Costin Manolache
- */
-public class ServletResponseIncludeWrapper extends HttpServletResponseWrapper {
- public ServletResponseIncludeWrapper(ServletResponse current) {
- super((HttpServletResponse) current);
- }
-
- // Not overriden:
- /*
- public boolean containsHeader(String name)
- public String encodeRedirectUrl(String url)
- public String encodeRedirectURL(String url)
- public String encodeUrl(String url)
- public String encodeURL(String url)
- public void flushBuffer() throws IOException
- public int getBufferSize()
- public String getCharacterEncoding()
- public String getContentType()
- public Locale getLocale()
- public ServletOutputStream getOutputStream() throws IOException
- public ServletResponse getResponse()
- public PrintWriter getWriter() throws IOException
- public boolean isCommitted()
- public void resetBuffer()
- public void setCharacterEncoding(String charset)
- public void setResponse(ServletResponse response)
- */
-
- public void reset() {
- if (getResponse().isCommitted())
- getResponse().reset();
- else
- throw new IllegalStateException();
- }
-
- public void setContentLength(int len) {
- }
-
- public void setContentType(String type) {
- }
-
- public void setLocale(Locale loc) {
- }
-
- public void setBufferSize(int size) {
- }
-
- public void addCookie(Cookie cookie) {
- }
-
- public void addDateHeader(String name, long value) {
- }
-
- public void addHeader(String name, String value) {
- }
-
- public void addIntHeader(String name, int value) {
- }
-
- public void sendError(int sc) throws IOException {
- }
-
- public void sendError(int sc, String msg) throws IOException {
- }
-
- public void sendRedirect(String location) throws IOException {
- }
-
- public void setDateHeader(String name, long value) {
- }
-
- public void setHeader(String name, String value) {
- }
-
- public void setIntHeader(String name, int value) {
- }
-
- public void setStatus(int sc) {
- }
-
- public void setStatus(int sc, String msg) {
- }
-}
+++ /dev/null
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.tomcat.lite;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.Writer;
-
-/**
- * Coyote implementation of the servlet writer.
- *
- * @author Remy Maucherat
- */
-public class ServletWriterImpl
- extends PrintWriter {
-
-
- // -------------------------------------------------------------- Constants
-
-
- private static final char[] LINE_SEP = { '\r', '\n' };
-
-
- // ----------------------------------------------------- Instance Variables
-
-
- protected Writer ob;
- protected boolean error = false;
-
-
- // ----------------------------------------------------------- Constructors
-
-
- public ServletWriterImpl(Writer ob) {
- super(ob);
- this.ob = ob;
- }
-
-
- // --------------------------------------------------------- Public Methods
-
-
- /**
- * Prevent cloning the facade.
- */
- protected Object clone()
- throws CloneNotSupportedException {
- throw new CloneNotSupportedException();
- }
-
-
- // -------------------------------------------------------- Package Methods
-
-
- /**
- * Clear facade.
- */
- void clear() {
- ob = null;
- }
-
-
- /**
- * Recycle.
- */
- void recycle() {
- error = false;
- }
-
-
- // --------------------------------------------------------- Writer Methods
-
-
- public void flush() {
-
- if (error)
- return;
-
- try {
- ob.flush();
- } catch (IOException e) {
- error = true;
- }
-
- }
-
-
- public void close() {
-
- // We don't close the PrintWriter - super() is not called,
- // so the stream can be reused. We close ob.
- try {
- ob.close();
- } catch (IOException ex ) {
- ;
- }
- error = false;
-
- }
-
-
- public boolean checkError() {
- flush();
- return error;
- }
-
-
- public void write(int c) {
-
- if (error)
- return;
-
- try {
- ob.write(c);
- } catch (IOException e) {
- error = true;
- }
-
- }
-
-
- public void write(char buf[], int off, int len) {
-
- if (error)
- return;
-
- try {
- ob.write(buf, off, len);
- } catch (IOException e) {
- error = true;
- }
-
- }
-
-
- public void write(char buf[]) {
- write(buf, 0, buf.length);
- }
-
-
- public void write(String s, int off, int len) {
-
- if (error)
- return;
-
- try {
- ob.write(s, off, len);
- } catch (IOException e) {
- error = true;
- }
-
- }
-
-
- public void write(String s) {
- write(s, 0, s.length());
- }
-
-
- // ---------------------------------------------------- PrintWriter Methods
-
-
- public void print(boolean b) {
- if (b) {
- write("true");
- } else {
- write("false");
- }
- }
-
-
- public void print(char c) {
- write(c);
- }
-
-
- public void print(int i) {
- write(String.valueOf(i));
- }
-
-
- public void print(long l) {
- write(String.valueOf(l));
- }
-
-
- public void print(float f) {
- write(String.valueOf(f));
- }
-
-
- public void print(double d) {
- write(String.valueOf(d));
- }
-
-
- public void print(char s[]) {
- write(s);
- }
-
-
- public void print(String s) {
- if (s == null) {
- s = "null";
- }
- write(s);
- }
-
-
- public void print(Object obj) {
- write(String.valueOf(obj));
- }
-
-
- public void println() {
- write(LINE_SEP);
- }
-
-
- public void println(boolean b) {
- print(b);
- println();
- }
-
-
- public void println(char c) {
- print(c);
- println();
- }
-
-
- public void println(int i) {
- print(i);
- println();
- }
-
-
- public void println(long l) {
- print(l);
- println();
- }
-
-
- public void println(float f) {
- print(f);
- println();
- }
-
-
- public void println(double d) {
- print(d);
- println();
- }
-
-
- public void println(char c[]) {
- print(c);
- println();
- }
-
-
- public void println(String s) {
- print(s);
- println();
- }
-
-
- public void println(Object o) {
- print(o);
- println();
- }
-
-
-}
+++ /dev/null
-/*
- * 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.File;
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import javax.servlet.Filter;
-import javax.servlet.Servlet;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.UnavailableException;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.tomcat.integration.ObjectManager;
-import org.apache.tomcat.integration.simple.SimpleObjectManager;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.buf.UriNormalizer;
-import org.apache.tomcat.util.http.mapper.MappingData;
-
-/**
- * Simpler, lower footprint serlvet engine.
- *
- * Uses ObjectManager to integate with an embedding app
- * - the object names it uses:
- *
- * Internal objects created by Tomcat and registered for management
- * and injection:
- * - Servlet:CONTEXT_PATH:SERVLETNAME - a ServletWrapper
- * - ServletContext:CONTEXT_PATH
- * - ProtocolHandler:ep-PORT - coyote ProtocolHandler
- * - CoyoteServer:CoyoteServer-PORT
- * - CoyoteAdapter:PATH - for the coyote used Adapter
- * - TomcatLite - this object.
- * - Connector - the connector object
- *
- * Plugins to be constructed by framework ( defaults set in initDefaults ):
- * - UserSessionManager
- * - UserTemplateClassMapper
- * - ContextPreinitListener
- * - Connector
- * - WebappServletMapper
- * - WebappFilterMapper
- * - default-servlet
- * - jspwildcard-servlet
- * - Foo-servlet - servlet named Foo
- *
- *
- * @author Costin Manolache
- */
-public class TomcatLite implements Runnable {
-
- private String serverDirName;
- private File workDir;
-
- // all contexts - hostMapper knows about hostnames and how they are mapped.
- // this shouldn't be needed if we want to delegate ctx management
- private ArrayList<ServletContextImpl> contexts = new ArrayList();
-
- URLClassLoader contextParentLoader;
-
- // Discovered or default Host/Context mapper
- Filter hostMapper;
-
- // Servlets to preload in each context, configurable from CLI or API
- Map<String,String> preloadServlets = new HashMap();
- Map<String,String> preloadMappings = new HashMap();
-
- Map<String,String> ctxDefaultInitParam = new HashMap();
-
- Connector connector;
-
- ObjectManager om;
-
- static String SERVLETS_PACKAGE = "org.apache.tomcat.servlets";
-
-
- protected boolean daemon = false;
-
- public TomcatLite() {
- }
-
- public TomcatLite(ObjectManager om) {
- this.setObjectManager(om);
- }
-
- // --------------- 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
- * values.
- */
- public ObjectManager getObjectManager() {
- if (om == null) {
- om = defaultObjectManager();
- }
- return om;
- }
-
- public void setObjectManager(ObjectManager om) {
- this.om = om;
- }
-
- public List/*<ServletContextImpl>*/ getWebapps() {
- return contexts;
- }
-
- public URLClassLoader getContextParentLoader() {
- if (contextParentLoader == null) {
-
- ClassLoader parent = this.getClass().getClassLoader();
- contextParentLoader = new URLClassLoader(new URL[] {},
- parent);
-
- /*if (engineRepo == null) {
- engineRepo = new Repository();
- engineRepo.setParentClassLoader(parent);
- }
-
- contextParentLoader =
- engineRepo.getClassLoader();
- */
- }
- return contextParentLoader;
- }
-
- public void start() throws IOException {
- long t0 = System.currentTimeMillis();
-
- // start all contexts
- // init all contexts
- Iterator i1 = contexts.iterator();
- while (i1.hasNext()) {
- ServletContextImpl ctx = (ServletContextImpl) i1.next();
- try {
- ctx.start();
- } catch (Throwable e) {
- e.printStackTrace();
- }
- }
- long t1 = System.currentTimeMillis();
- System.err.println("Engine.start() " + (t1-t0));
- }
-
-
- /**
- * Add a context - used for IntrospectionUtils.
- *
- * ContextPath:ContextBaseDir
- */
- public void setContext(String c) throws ServletException {
- String[] pathDir = c.split(":", 2);
- addServletContext("", pathDir[1], pathDir[0]);
- }
-
- public void setServletContexts(List<ServletContext> c) throws ServletException {
- for (ServletContext ctx: c) {
- addServletContext((ServletContextImpl) ctx);
- }
- }
-
- public void setPreload(String servletNameClass) {
- String[] nv = servletNameClass.split(":");
- preloadServlets.put(nv[0], nv[1]);
- }
-
- public void addPreload(String servletName, String servletClassName) {
- preloadServlets.put(servletName, servletClassName);
- }
-
- public void setDefaultInitParam(String nameValue) {
- String[] nv = nameValue.split(":");
- ctxDefaultInitParam.put(nv[0], nv[1]);
- }
-
- public void addDefaultInitParam(String name, String value) {
- ctxDefaultInitParam.put(name, value);
- }
-
- public void setPreloadMappings(String servletPath) {
- String[] nv = servletPath.split(":");
- preloadMappings.put(nv[0], nv[1]);
- }
-
- public void addPreloadMapping(String servletName, String path) {
- preloadMappings.put(servletName, path);
- }
-
- public void stop() {
- Iterator i1 = contexts.iterator();
- while (i1.hasNext()) {
- ServletContextImpl ctx = (ServletContextImpl) i1.next();
- try {
- ctx.destroy();
- } catch (Throwable e) {
- e.printStackTrace();
- }
- }
- try {
- stopConnector();
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- // -------------- Context add/remove --------------
-
- public static String[] DEFAULT_WELCOME = { "index.html" };
-
- public void addServletContext(ServletContextImpl ctx) throws ServletException {
- ctx.setTomcat(this);
- if (hostMapper == null) {
- hostMapper = new WebappContextMapper();
- }
-
- ((WebappContextMapper) hostMapper).addHost(ctx.getHostname(), null);
- ((WebappContextMapper) hostMapper).addContext(ctx.getHostname(),
- ctx);
-
- contexts.add(ctx);
-
- getObjectManager().bind("ServletContext:" + ctx.getContextPath(),
- ctx);
-
- }
-
- /**
- * Add a context.
- *
- * web.xml will be read as part of init, and the initialization will be
- * part of start or lazy.
- *
- * @param hostname - ""
- * if default host, or string to be matched with Host header
- * @param basePath = directory where the webapp is installed
- * @param path -
- * context path, "/" for root, "/examples", etc
- * @return a servlet context
- * @throws ServletException
- */
- public ServletContext addServletContext(String hostname,
- String basePath,
- String path)
- throws ServletException
- {
- ServletContextImpl ctx = new ServletContextImpl();
- ctx.setContextPath(path);
- ctx.setBasePath(basePath);
- addServletContext(ctx);
- return ctx;
- }
-
- public void removeServletContext(ServletContext sctx)
- throws ServletException
- {
- ServletContextImpl ctx = (ServletContextImpl) sctx;
- // TODO: destroy all servlets and filters
- // TODO: clean up any other reference to the context or its loader
- notifyRemove(ctx);
- }
-
-
- /**
- * Required for ServletContext.getContext(uri);
- * @throws ServletException
- * @throws IOException
- */
- public ServletContextImpl getContext(ServletContextImpl impl, String uri)
- throws IOException, ServletException {
- // Create a request - needs to be simplified
- ServletRequestImpl req = createMessage(impl, impl.contextPath, uri);
- hostMapper.doFilter(req, null, null);
- return req.getContext();
- }
-
- public ServletResponseImpl service(ServletRequestImpl req) throws IOException, Exception {
- ServletResponseImpl res = req.getResponse();
- service(req, res);
- endRequest(req, res);
- return res;
- }
-
- public void service(ServletRequestImpl req, ServletResponseImpl res)
- throws Exception, IOException {
- // parse the session id from URI
- req.parseSessionId();
-
- try {
- UriNormalizer.decodeRequest(req.getHttpRequest().decodedURI(),
- req.getHttpRequest().requestURI(),
- req.getHttpRequest().getURLDecoder());
- } catch(IOException ioe) {
- res.setStatus(400);
- return;
- }
-
- MappingData mapRes = req.getMappingData();
- try {
- // TODO: make hostMapper configurable, implement interface,
- // simple to set on ROOT context
- hostMapper.doFilter(req, null, null);
-
-
- ServletContextImpl ctx = (ServletContextImpl)mapRes.context;
- if( ctx == null ) {
- // TODO: 404
- res.setStatus(404);
- return;
- }
- req.setContext(ctx);
-
- // bind class loader
- Thread.currentThread().setContextClassLoader(ctx.getClassLoader());
-
- WebappServletMapper mapper = ctx.getMapper();
- mapper.map(req.getHttpRequest().decodedURI(), mapRes);
-
- // Possible redirect
- MessageBytes redirectPathMB = mapRes.redirectPath;
- if (!redirectPathMB.isNull()) {
- String redirectPath = res.urlEncoder.encodeURL(redirectPathMB.toString());
- String query = req.getQueryString();
- if (req.isRequestedSessionIdFromURL()) {
- // This is not optimal, but as this is not very common, it
- // shouldn't matter
- redirectPath = redirectPath + ";" + ServletRequestImpl.SESSION_PARAMETER_NAME + "="
- + req.getRequestedSessionId();
- }
- if (query != null) {
- // This is not optimal, but as this is not very common, it
- // shouldn't matter
- redirectPath = redirectPath + "?" + query;
- }
- res.sendRedirect(redirectPath);
- return;
- }
-
- req.parseSessionCookiesId();
-
- ServletConfigImpl h=(ServletConfigImpl)mapRes.wrapper;
- if (h != null) {
- req.setWrapper((ServletConfigImpl)mapRes.wrapper);
- serviceServlet(ctx, req, res, h, mapRes );
- // send the response...
-
- //res.flushBuffer();
-
- // Recycle the wrapper request and response
- //req.recycle();
- //res.recycle();
- }
- } finally {
- if(mapRes != null )
- mapRes.recycle();
- }
- }
-
- /** Coyote / mapper adapter. Result of the mapper.
- *
- * This replaces the valve chain, the path is:
- * 1. coyote calls mapper -> result Adapter
- * 2. service is called. Additional filters are set on the wrapper.
- * @param mapRes
- */
- private void serviceServlet(ServletContextImpl ctx,
- ServletRequestImpl req,
- ServletResponseImpl res,
- ServletConfigImpl servletConfig,
- MappingData mapRes)
- throws IOException {
- Servlet servlet = null;
- try {
- if (servletConfig.isUnavailable()) {
- handleUnavailable(res, servletConfig);
- return;
- }
- try {
- servlet = servletConfig.allocate();
- } catch(ServletException ex) {
- handleUnavailable(res, servletConfig);
- }
- WebappFilterMapper filterMap = ctx.getFilterMapper();
- FilterChainImpl chain =
- filterMap.createFilterChain(req, servletConfig, servlet);
-
- try {
- if (chain == null) {
- if (servlet != null) {
- servlet.service(req, res);
- } else {
- System.err.println("No servlet " + req.getRequestURI());
- res.sendError(404);
- }
- } else {
- chain.doFilter(req, res);
- }
- } catch(UnavailableException ex) {
- servletConfig.unavailable(ex);
- handleUnavailable(res, servletConfig);
- return;
- }
-
- // servlet completed without exception. Check status
- int status = res.getStatus();
- if (status != 200 && !res.isCommitted()) {
- String statusPage = ctx.findStatusPage(status);
-
- if (statusPage != null) {
- ctx.handleStatusPage(req, res, status, statusPage);
- } else {
- // Send a default message body.
- // TODO: maybe other mechanism to customize default.
- res.defaultStatusPage(status, res.getMessage());
- }
- }
- } catch (Throwable t) {
- ctx.handleError(req, res, t);
- } finally {
- if (servlet != null) {
- servletConfig.deallocate(servlet);
- }
- }
- }
-
- private void handleUnavailable(ServletResponseImpl response,
- ServletConfigImpl servletConfig)
- throws IOException {
- long available = servletConfig.getAvailable();
- if ((available > 0L) && (available < Long.MAX_VALUE))
- response.setDateHeader("Retry-After", available);
- // TODO: handle via error pages !
- response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
- "Service unavailable");
- }
-
-
- // ------------ Notifications for JMX ----------------
-
- void notifyAdd(Object o) {
- }
-
- void notifyRemove(Object o) {
- }
-
- public void setServerDir(String dir) {
- this.serverDirName = dir;
- }
-
- public File getWork() {
- if (workDir == null) {
- if (serverDirName == null) {
- serverDirName = "./";
- }
- File rootDirFile = new File(serverDirName);
- workDir = new File(rootDirFile, "tomcat-work");
- if (workDir.exists()) {
- workDir.mkdirs();
- }
- }
- return workDir;
- }
-
- /**
- * Init
- *
- * @throws ServletException
- * @throws IOException
- */
- public void init() throws ServletException, IOException {
- getObjectManager().bind("TomcatLite", this);
- if (contexts.size() == 0) {
- setContext("/:./webapps/ROOT");
- }
- getConnector().setObjectManager(getObjectManager());
- Iterator i1 = contexts.iterator();
- while (i1.hasNext()) {
- ServletContextImpl ctx = (ServletContextImpl) i1.next();
- try {
- ctx.init();
- } catch (Throwable e) {
- e.printStackTrace();
- }
- }
- }
-
- /**
- * Initialize an webapp and add it to the server.
- * - load web.xml
- * - call
- *
- * @param rootDir
- * @param path
- * @param deployServlet
- */
- public void init(String rootDir, String path)
- throws ServletException, IOException {
-
- long t0 = System.currentTimeMillis();
-
- ServletContextImpl ctx =
- (ServletContextImpl)addServletContext(null,
- rootDir,
- path);
- ctx.init();
-
- long t1 = System.currentTimeMillis();
-
- // At this point all config is loaded. Contexts are not yet init()
- // - this will happen on start.
- System.err.println("Context.init() " + path + " " + (t1-t0));
- }
-
- /**
- * Get an empty request/response pair ( response available
- * as getResponse() ). Optional set input and output buffers.
- *
- * This can be used for a connector-less interface to tomcat lite.
- *
- * TODO: make it independent of coyote !
- */
-
- public ServletRequestImpl createMessage() {
- ServletRequestImpl req = new ServletRequestImpl();
- ServletResponseImpl res = req.getResponse();
-
- getConnector().initRequest(req, res);
-
- req.getHttpRequest().method().setString("GET");
- req.getHttpRequest().protocol().setString("HTTP/1.1");
-
- return req;
- }
-
- /**
- * Used internally for mapping.
- */
- private ServletRequestImpl createMessage(ServletContextImpl deployCtx,
- String ctxPath,
- String reqPath) {
- ServletRequestImpl req = createMessage();
- req.setContextPath(ctxPath);
- req.setContext(deployCtx);
- req.setRequestURI(ctxPath + reqPath);
- return req;
- }
-
-
- /**
- * Set a global filter that will be used for context mapping.
- *
- * The filter will get a request, with requestUri and hostname set.
- *
- * It needs to compute the context path and set it as an attribute.
- *
- * Advanced features may include on-demand loading of webapps, large scale
- * virtual hosting, etc.
- */
- public void setContextMapper(Filter hostMapper2) {
- this.hostMapper = hostMapper2;
- }
-
- public void endRequest(ServletRequestImpl req,
- ServletResponseImpl res) throws IOException {
- res.outputBuffer.flush();
- req.getConnector().finishResponse(res);
- }
-
- public Connector getConnector() {
- if (connector == null) {
- connector = (Connector) getObjectManager().get(Connector.class);
- setConnector(connector);
- }
- return connector;
- }
-
- public void setConnector(Connector c) {
- connector = c;
- connector.setTomcatLite(this);
- getObjectManager().bind("Connector", connector);
- }
-
-
- public void setDaemon(boolean d) {
- getConnector();
- if (connector != null) {
- connector.setDaemon(d);
- }
- }
-
- public void startConnector() throws IOException {
- getConnector();
- if (connector != null) {
- connector.start();
- }
- }
-
- public void stopConnector() throws Exception {
- if (connector != null) {
- connector.stop();
- }
- }
-
- public void run() {
- try {
- execute();
- } catch (ServletException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- public void execute() throws ServletException, IOException {
- init();
- start();
- startConnector();
- }
-}
+++ /dev/null
-/*
- * 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.util.HashMap;
-import java.util.Map;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-import org.apache.tomcat.util.buf.CharChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.mapper.MappingData;
-
-/**
- * This handles host and context mapping.
- *
- * The default implementation for tomcat lite is very limitted -
- * no support for virtual hosts, no support for contexts deeper than
- * 1 level. The intention is to override this with more advanced mappers.
- *
- * With 'ConfigurableHosts' interface it is possible for a smart
- * mapper to load/unload virtual hosts at runtime, maybe from a
- * database. It should be possible to use databases to store huge number
- * of hosts or webapps.
- *
- */
-public class WebappContextMapper implements Filter {
-
- ServletContext rootContext;
- Map<MessageBytes, ServletContext> contexts = new HashMap();
-
- public WebappContextMapper() {
- }
-
- public void addHost(String name, String[] aliases) {
- }
-
- /**
- * Add a new Context to an existing Host.
- *
- * @param hostName Virtual host name this context belongs to
- * @param contextPath Context path
- * @param context Context object
- * @param welcomeResources Welcome files defined for this context
- * @param resources Static resources of the context
- */
- public void addContext(String hostName,
- ServletContext context)
- throws ServletException
- {
- String path = context.getContextPath();
- if (path.lastIndexOf("/") > 0) {
- throw new ServletException("Base context mapper supports only one level");
- }
- if ("/".equals(path)) {
- rootContext = context;
- }
- MessageBytes mb = MessageBytes.newInstance();
- mb.setChars(path.toCharArray(), 0, path.length());
- contexts.put(mb, context);
- }
-
-
- /**
- * Remove a context from an existing host.
- *
- * @param hostName Virtual host name this context belongs to
- * @param path Context path
- */
- public void removeContext(String hostName, String path)
- throws ServletException {
- if ("/".equals(path)) {
- rootContext = null;
- }
- contexts.remove(path);
- }
-
- /**
- * Map the specified URI.
- */
- private void mapContext(ServletRequestImpl req)
- throws IOException, ServletException {
- MessageBytes uriMB = req.getDecodedRequestURIMB();
- MappingData mappingData = req.getMappingData();
- uriMB.toChars();
- CharChunk uri = uriMB.getCharChunk();
-
-
- if (uri.length() < 2 || contexts.size() == 0) {
- mappingData.context = rootContext;
- if (rootContext != null) {
- mappingData.contextPath.setString(rootContext.getContextPath());
- }
- return;
- }
-
- int nextSlash = uri.indexOf('/', 1);
- if (nextSlash == -1) {
- nextSlash = uri.length();
- }
- mappingData.contextPath.setChars(uri.getChars(), 0, nextSlash);
- ServletContext servletContext = contexts.get(mappingData.contextPath);
-
- if (servletContext != null) {
- mappingData.context = servletContext;
- } else {
- mappingData.context = rootContext;
- if (rootContext != null) {
- mappingData.contextPath.setString(rootContext.getContextPath());
- }
- }
- }
-
- public void init(FilterConfig filterConfig) throws ServletException {
- }
-
- public void doFilter(ServletRequest request,
- ServletResponse response,
- FilterChain chain)
- throws IOException, ServletException {
- ServletRequestImpl req = (ServletRequestImpl)request;
- mapContext(req);
- }
-
- public void destroy() {
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package org.apache.tomcat.lite;
-
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.ArrayList;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.Servlet;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.tomcat.servlets.util.RequestUtil;
-
-/**
- * First filter after the context and servlet are mapped. It will add
- * web.xml-defined filters.
- *
- * costin: This is another mapping - done in RequestDispatcher or initial
- * mapping.
- * Also: StandardHostValve - sets attribute for error pages,
- * StandardWrapperValve - mapping per invocation
- *
- * @author Greg Murray
- * @author Remy Maucherat
- */
-public class WebappFilterMapper implements Filter {
-
-
- // -------------------------------------------------------------- Constants
-
-
- public static final int ERROR = 1;
- public static final Integer ERROR_INTEGER = new Integer(ERROR);
- public static final int FORWARD = 2;
- public static final Integer FORWARD_INTEGER = new Integer(FORWARD);
- public static final int INCLUDE = 4;
- public static final Integer INCLUDE_INTEGER = new Integer(INCLUDE);
- public static final int REQUEST = 8;
- public static final Integer REQUEST_INTEGER = new Integer(REQUEST);
-
- /**
- * Request dispatcher state.
- */
- public static final String DISPATCHER_TYPE_ATTR =
- "org.apache.catalina.core.DISPATCHER_TYPE";
-
- /**
- * Request dispatcher path.
- */
- public static final String DISPATCHER_REQUEST_PATH_ATTR =
- "org.apache.catalina.core.DISPATCHER_REQUEST_PATH";
-
-
- // ----------------------------------------------------------- Constructors
- ServletContextImpl servletContext;
-
- public WebappFilterMapper() {
- }
-
- public WebappFilterMapper(ServletContextImpl impl) {
- servletContext = impl;
- }
-
- public void setServletContext(ServletContextImpl sc) {
- servletContext = sc;
- }
-
- // --------------------------------------------------------- Public Methods
-
- ArrayList filterMaps = new ArrayList();
-
- public void addMapping(String filterName,
- String url,
- String servletName,
- String type[], boolean isMatchAfter) {
- FilterMap map = new FilterMap();
- map.setURLPattern(url);
- map.setFilterName(filterName);
- map.setServletName(servletName);
- if (isMatchAfter) {
- filterMaps.add(map);
- } else {
- filterMaps.add(0, map);
- }
- }
-
- /**
- * Construct and return a FilterChain implementation that will wrap the
- * execution of the specified servlet instance. If we should not execute
- * a filter chain at all, return <code>null</code>.
- *
- * @param request The servlet request we are processing
- * @param servlet The servlet instance to be wrapped
- */
- public FilterChainImpl createFilterChain(ServletRequest request,
- ServletConfigImpl wrapper,
- Servlet servlet) {
-
- // If there is no servlet to execute, return null
- if (servlet == null)
- return (null);
-
- // get the dispatcher type
- int dispatcher = -1;
- if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) {
- Integer dispatcherInt =
- (Integer) request.getAttribute(DISPATCHER_TYPE_ATTR);
- dispatcher = dispatcherInt.intValue();
- }
- String requestPath = null;
- Object attribute = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR);
-
- if (attribute != null){
- requestPath = attribute.toString();
- }
-
- HttpServletRequest hreq = null;
- if (request instanceof HttpServletRequest)
- hreq = (HttpServletRequest)request;
-
- // Create and initialize a filter chain object
- FilterChainImpl filterChain = null;
- if ((request instanceof ServletRequestImpl)) {
- ServletRequestImpl req = (ServletRequestImpl) request;
- filterChain = (FilterChainImpl) req.getFilterChain();
- filterChain.release();
- } else {
- // Security: Do not recycle
- filterChain = new FilterChainImpl();
- }
-
- filterChain.setServlet(wrapper, servlet);
-
- // If there are no filter mappings, we are done
- if ((filterMaps.size() == 0))
- return (filterChain);
-
- // Acquire the information we will need to match filter mappings
- String servletName = wrapper.getServletName();
-
- int n = 0;
-
- // TODO(costin): optimize: separate in 2 lists, one for url-mapped, one for
- // servlet-name. Maybe even separate list for dispatcher and
- // non-dispatcher
-
- // TODO(costin): optimize: set the FilterConfig in the FilterMap, to
- // avoid second hash lookup
-
- // Add the relevant path-mapped filters to this filter chain
- for (int i = 0; i < filterMaps.size(); i++) {
- FilterMap filterMap = (FilterMap)filterMaps.get(i);
- if (!matchDispatcher(filterMap ,dispatcher)) {
- continue;
- }
- if (!matchFiltersURL(filterMap, requestPath))
- continue;
- FilterConfigImpl filterConfig =
- servletContext.getFilter(filterMap.getFilterName());
- if (filterConfig == null) {
- // FIXME - log configuration problem
- continue;
- }
- filterChain.addFilter(filterConfig);
- n++;
- }
-
- // Add filters that match on servlet name second
- for (int i = 0; i < filterMaps.size(); i++) {
- FilterMap filterMap = (FilterMap)filterMaps.get(i);
- if (!matchDispatcher(filterMap ,dispatcher)) {
- continue;
- }
- if (!matchFiltersServlet(filterMap, servletName))
- continue;
- FilterConfigImpl filterConfig =
- servletContext.getFilter(filterMap.getFilterName());
- if (filterConfig == null) {
- ; // FIXME - log configuration problem
- continue;
- }
- filterChain.addFilter(filterConfig);
- n++;
- }
-
- // Return the completed filter chain
- return (filterChain);
-
- }
-
-
- // -------------------------------------------------------- Private Methods
-
-
- /**
- * Return <code>true</code> if the context-relative request path
- * matches the requirements of the specified filter mapping;
- * otherwise, return <code>null</code>.
- *
- * @param filterMap Filter mapping being checked
- * @param requestPath Context-relative request path of this request
- */
- private boolean matchFiltersURL(FilterMap filterMap, String requestPath) {
-
- if (requestPath == null)
- return (false);
-
- // Match on context relative request path
- String testPath = filterMap.getURLPattern();
- if (testPath == null)
- return (false);
-
- // Case 1 - Exact Match
- if (testPath.equals(requestPath))
- return (true);
-
- // Case 2 - Path Match ("/.../*")
- if (testPath.equals("/*"))
- return (true);
- if (testPath.endsWith("/*")) {
- if (testPath.regionMatches(0, requestPath, 0,
- testPath.length() - 2)) {
- if (requestPath.length() == (testPath.length() - 2)) {
- return (true);
- } else if ('/' == requestPath.charAt(testPath.length() - 2)) {
- return (true);
- }
- }
- return (false);
- }
-
- // Case 3 - Extension Match
- if (testPath.startsWith("*.")) {
- int slash = requestPath.lastIndexOf('/');
- int period = requestPath.lastIndexOf('.');
- if ((slash >= 0) && (period > slash)
- && (period != requestPath.length() - 1)
- && ((requestPath.length() - period)
- == (testPath.length() - 1))) {
- return (testPath.regionMatches(2, requestPath, period + 1,
- testPath.length() - 2));
- }
- }
-
- // Case 4 - "Default" Match
- return (false); // NOTE - Not relevant for selecting filters
-
- }
-
-
- /**
- * Return <code>true</code> if the specified servlet name matches
- * the requirements of the specified filter mapping; otherwise
- * return <code>false</code>.
- *
- * @param filterMap Filter mapping being checked
- * @param servletName Servlet name being checked
- */
- private boolean matchFiltersServlet(FilterMap filterMap,
- String servletName) {
-
- if (servletName == null) {
- return (false);
- } else {
- if (servletName.equals(filterMap.getServletName())) {
- return (true);
- } else {
- return false;
- }
- }
-
- }
-
-
- /**
- * Convienience method which returns true if the dispatcher type
- * matches the dispatcher types specified in the FilterMap
- */
- private boolean matchDispatcher(FilterMap filterMap, int dispatcher) {
- switch (dispatcher) {
- case FORWARD : {
- if (filterMap.getDispatcherMapping() == FilterMap.FORWARD ||
- filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR ||
- filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD ||
- filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) {
- return true;
- }
- break;
- }
- case INCLUDE : {
- if (filterMap.getDispatcherMapping() == FilterMap.INCLUDE ||
- filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR ||
- filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD ||
- filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) {
- return true;
- }
- break;
- }
- case REQUEST : {
- if (filterMap.getDispatcherMapping() == FilterMap.REQUEST ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE) {
- return true;
- }
- break;
- }
- case ERROR : {
- if (filterMap.getDispatcherMapping() == FilterMap.ERROR ||
- filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR ||
- filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR ||
- filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
- filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE) {
- return true;
- }
- break;
- }
- }
- return false;
- }
-
-
- // -------------------- Map elements -----------------------
-
- public static class FilterMap implements Serializable {
-
-
- // ------------------------------------------------------------- Properties
-
-
- /**
- * The name of this filter to be executed when this mapping matches
- * a particular request.
- */
-
- public static final int ERROR = 1;
- public static final int FORWARD = 2;
- public static final int FORWARD_ERROR =3;
- public static final int INCLUDE = 4;
- public static final int INCLUDE_ERROR = 5;
- public static final int INCLUDE_ERROR_FORWARD =6;
- public static final int INCLUDE_FORWARD = 7;
- public static final int REQUEST = 8;
- public static final int REQUEST_ERROR = 9;
- public static final int REQUEST_ERROR_FORWARD = 10;
- public static final int REQUEST_ERROR_FORWARD_INCLUDE = 11;
- public static final int REQUEST_ERROR_INCLUDE = 12;
- public static final int REQUEST_FORWARD = 13;
- public static final int REQUEST_INCLUDE = 14;
- public static final int REQUEST_FORWARD_INCLUDE= 15;
-
- // represents nothing having been set. This will be seen
- // as equal to a REQUEST
- private static final int NOT_SET = -1;
-
- private int dispatcherMapping=NOT_SET;
-
- private String filterName = null;
-
- /**
- * The URL pattern this mapping matches.
- */
- private String urlPattern = null;
-
- /**
- * The servlet name this mapping matches.
- */
- private String servletName = null;
-
-
-
- public String getFilterName() {
- return (this.filterName);
- }
-
- public void setFilterName(String filterName) {
- this.filterName = filterName;
- }
-
-
- public String getServletName() {
- return (this.servletName);
- }
-
- public void setServletName(String servletName) {
- this.servletName = servletName;
- }
-
-
- public String getURLPattern() {
- return (this.urlPattern);
- }
-
- public void setURLPattern(String urlPattern) {
- this.urlPattern = RequestUtil.URLDecode(urlPattern);
- }
-
- /**
- *
- * This method will be used to set the current state of the FilterMap
- * representing the state of when filters should be applied:
- *
- * ERROR
- * FORWARD
- * FORWARD_ERROR
- * INCLUDE
- * INCLUDE_ERROR
- * INCLUDE_ERROR_FORWARD
- * REQUEST
- * REQUEST_ERROR
- * REQUEST_ERROR_INCLUDE
- * REQUEST_ERROR_FORWARD_INCLUDE
- * REQUEST_INCLUDE
- * REQUEST_FORWARD,
- * REQUEST_FORWARD_INCLUDE
- *
- */
- public void setDispatcher(String dispatcherString) {
- String dispatcher = dispatcherString.toUpperCase();
-
- if (dispatcher.equals("FORWARD")) {
-
- // apply FORWARD to the global dispatcherMapping.
- switch (dispatcherMapping) {
- case NOT_SET : dispatcherMapping = FORWARD; break;
- case ERROR : dispatcherMapping = FORWARD_ERROR; break;
- case INCLUDE : dispatcherMapping = INCLUDE_FORWARD; break;
- case INCLUDE_ERROR : dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
- case REQUEST : dispatcherMapping = REQUEST_FORWARD; break;
- case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break;
- case REQUEST_ERROR_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
- case REQUEST_INCLUDE : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
- }
- } else if (dispatcher.equals("INCLUDE")) {
- // apply INCLUDE to the global dispatcherMapping.
- switch (dispatcherMapping) {
- case NOT_SET : dispatcherMapping = INCLUDE; break;
- case ERROR : dispatcherMapping = INCLUDE_ERROR; break;
- case FORWARD : dispatcherMapping = INCLUDE_FORWARD; break;
- case FORWARD_ERROR : dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
- case REQUEST : dispatcherMapping = REQUEST_INCLUDE; break;
- case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
- case REQUEST_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
- case REQUEST_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
- }
- } else if (dispatcher.equals("REQUEST")) {
- // apply REQUEST to the global dispatcherMapping.
- switch (dispatcherMapping) {
- case NOT_SET : dispatcherMapping = REQUEST; break;
- case ERROR : dispatcherMapping = REQUEST_ERROR; break;
- case FORWARD : dispatcherMapping = REQUEST_FORWARD; break;
- case FORWARD_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break;
- case INCLUDE : dispatcherMapping = REQUEST_INCLUDE; break;
- case INCLUDE_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
- case INCLUDE_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
- case INCLUDE_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
- }
- } else if (dispatcher.equals("ERROR")) {
- // apply ERROR to the global dispatcherMapping.
- switch (dispatcherMapping) {
- case NOT_SET : dispatcherMapping = ERROR; break;
- case FORWARD : dispatcherMapping = FORWARD_ERROR; break;
- case INCLUDE : dispatcherMapping = INCLUDE_ERROR; break;
- case INCLUDE_FORWARD : dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
- case REQUEST : dispatcherMapping = REQUEST_ERROR; break;
- case REQUEST_INCLUDE : dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
- case REQUEST_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD; break;
- case REQUEST_FORWARD_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
- }
- }
- }
-
- public int getDispatcherMapping() {
- // per the SRV.6.2.5 absence of any dispatcher elements is
- // equivelant to a REQUEST value
- if (dispatcherMapping == NOT_SET) return REQUEST;
- else return dispatcherMapping;
- }
-
- }
-
-
- public void init(FilterConfig filterConfig) throws ServletException {
- }
-
-
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain)
- throws IOException, ServletException {
- }
-
-
- public void destroy() {
- }
-
-}
+++ /dev/null
-/*
- * Copyright 1999-2004 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.tomcat.lite;
-
-import java.io.File;
-import java.io.IOException;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-import org.apache.tomcat.util.buf.Ascii;
-import org.apache.tomcat.util.buf.CharChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.mapper.MappingData;
-
-/**
- * Mapper, which implements the servlet API mapping rules (which are derived
- * from the HTTP rules).
- *
- * Based on catalina mapper - but simplified. All host and context mappings
- * is done in HostMapper - this is just dealing with web.xml.
- *
- * For corner cases ( very large number of rules, dynamic rules, etc ) you
- * can override the mapper for a context with a class extending this.
- *
- * TODO: remove, use coyote-level mapper or user-space
- */
-public class WebappServletMapper implements Filter {
-
- /**
- * Context associated with this wrapper, used for wrapper mapping.
- */
- public ContextMapElement contextMapElement = new ContextMapElement();
-
-
- // --------------------------------------------------------- Public Methods
- public WebappServletMapper() {
- }
-
- public void setServletContext(ServletContextImpl impl) {
- contextMapElement.object = impl;
- contextMapElement.name = impl.getContextPath();
- }
-
-
- /** Set context, used for wrapper mapping (request dispatcher).
- *
- * @param welcomeResources Welcome files defined for this context
- * @param resources Static resources of the context
- */
- public void setContext(String path, String[] welcomeResources,
- File resources) {
- contextMapElement.name = path;
- contextMapElement.welcomeResources = welcomeResources;
- contextMapElement.resources = resources;
- }
-
-
- /**
- * Add a wrapper to the context associated with this wrapper.
- *
- * @param path Wrapper mapping
- * @param wrapper The Wrapper object
- */
- public void addWrapper(String path, Object wrapper) {
- addWrapper(contextMapElement, path, wrapper);
- }
-
-
- public void addWrapper(String path, Object wrapper, boolean jspWildCard) {
- addWrapper(contextMapElement, path, wrapper, jspWildCard);
- }
-
-
- public void addWrapper(ContextMapElement context, String path, Object wrapper) {
- addWrapper(context, path, wrapper, false);
- }
-
-
- /**
- * Adds a wrapper to the given context.
- *
- * @param context The context to which to add the wrapper
- * @param path Wrapper mapping
- * @param wrapper The Wrapper object
- * @param jspWildCard true if the wrapper corresponds to the JspServlet
- * and the mapping path contains a wildcard; false otherwise
- */
- protected void addWrapper(ContextMapElement context, String path, Object wrapper,
- boolean jspWildCard) {
-
- synchronized (context) {
- WrapperMapElement newWrapper = new WrapperMapElement();
- newWrapper.object = wrapper;
- newWrapper.jspWildCard = jspWildCard;
- if (path.endsWith("/*")) {
- // Wildcard wrapper
- newWrapper.name = path.substring(0, path.length() - 2);
- WrapperMapElement[] oldWrappers = context.wildcardWrappers;
- WrapperMapElement[] newWrappers =
- new WrapperMapElement[oldWrappers.length + 1];
- if (insertMap(oldWrappers, newWrappers, newWrapper)) {
- context.wildcardWrappers = newWrappers;
- int slashCount = slashCount(newWrapper.name);
- if (slashCount > context.nesting) {
- context.nesting = slashCount;
- }
- }
- } else if (path.startsWith("*.")) {
- // Extension wrapper
- newWrapper.name = path.substring(2);
- WrapperMapElement[] oldWrappers = context.extensionWrappers;
- WrapperMapElement[] newWrappers =
- new WrapperMapElement[oldWrappers.length + 1];
- if (insertMap(oldWrappers, newWrappers, newWrapper)) {
- context.extensionWrappers = newWrappers;
- }
- } else if (path.equals("/")) {
- // Default wrapper
- newWrapper.name = "";
- context.defaultWrapper = newWrapper;
- } else {
- // Exact wrapper
- newWrapper.name = path;
- WrapperMapElement[] oldWrappers = context.exactWrappers;
- WrapperMapElement[] newWrappers =
- new WrapperMapElement[oldWrappers.length + 1];
- if (insertMap(oldWrappers, newWrappers, newWrapper)) {
- context.exactWrappers = newWrappers;
- }
- }
- }
- }
-
-
- /**
- * Remove a wrapper from the context associated with this wrapper.
- *
- * @param path Wrapper mapping
- */
- public void removeWrapper(String path) {
- removeWrapper(contextMapElement, path);
- }
-
-
- protected void removeWrapper(ContextMapElement context, String path) {
- synchronized (context) {
- if (path.endsWith("/*")) {
- // Wildcard wrapper
- String name = path.substring(0, path.length() - 2);
- WrapperMapElement[] oldWrappers = context.wildcardWrappers;
- WrapperMapElement[] newWrappers =
- new WrapperMapElement[oldWrappers.length - 1];
- if (removeMap(oldWrappers, newWrappers, name)) {
- // Recalculate nesting
- context.nesting = 0;
- for (int i = 0; i < newWrappers.length; i++) {
- int slashCount = slashCount(newWrappers[i].name);
- if (slashCount > context.nesting) {
- context.nesting = slashCount;
- }
- }
- context.wildcardWrappers = newWrappers;
- }
- } else if (path.startsWith("*.")) {
- // Extension wrapper
- String name = path.substring(2);
- WrapperMapElement[] oldWrappers = context.extensionWrappers;
- WrapperMapElement[] newWrappers =
- new WrapperMapElement[oldWrappers.length - 1];
- if (removeMap(oldWrappers, newWrappers, name)) {
- context.extensionWrappers = newWrappers;
- }
- } else if (path.equals("/")) {
- // Default wrapper
- context.defaultWrapper = null;
- } else {
- // Exact wrapper
- String name = path;
- WrapperMapElement[] oldWrappers = context.exactWrappers;
- WrapperMapElement[] newWrappers =
- new WrapperMapElement[oldWrappers.length - 1];
- if (removeMap(oldWrappers, newWrappers, name)) {
- context.exactWrappers = newWrappers;
- }
- }
- }
- }
-
- /**
- * Map the specified URI relative to the context,
- * mutating the given mapping data.
- *
- * @param uri URI
- * @param mappingData This structure will contain the result of the mapping
- * operation
- */
- public void map(MessageBytes uri, MappingData mappingData)
- throws Exception {
-
- uri.toChars();
- CharChunk uricc = uri.getCharChunk();
- //uricc.setLimit(-1);
- internalMapWrapper(contextMapElement, uricc, mappingData);
-
- }
-
-
- // -------------------------------------------------------- Private Methods
-
-
- /**
- * Wrapper mapping.
- */
- private final void internalMapWrapper(ContextMapElement context,
- CharChunk path,
- MappingData mappingData)
- throws Exception {
-
- int pathOffset = path.getOffset();
- int pathEnd = path.getEnd();
- int servletPath = pathOffset;
- boolean noServletPath = false;
-
- int length = context.name.length();
- if (length == 1) length--;
- if (length != (pathEnd - pathOffset)) {
- servletPath = pathOffset + length;
- } else {
- noServletPath = true;
- // What is this doing ???
- path.append('/');
- pathOffset = path.getOffset();
- pathEnd = path.getEnd();
- servletPath = pathOffset+length;
- }
-
- path.setOffset(servletPath);
-
- // Rule 1 -- Exact Match
- WrapperMapElement[] exactWrappers = context.exactWrappers;
- internalMapExactWrapper(exactWrappers, path, mappingData);
-
- // Rule 2 -- Prefix Match
- boolean checkJspWelcomeFiles = false;
- WrapperMapElement[] wildcardWrappers = context.wildcardWrappers;
- if (mappingData.wrapper == null) {
- internalMapWildcardWrapper(wildcardWrappers, context.nesting,
- path, mappingData);
- if (mappingData.wrapper != null && mappingData.jspWildCard) {
- char[] buf = path.getBuffer();
- if (buf[pathEnd - 1] == '/') {
- /*
- * Path ending in '/' was mapped to JSP servlet based on
- * wildcard match (e.g., as specified in url-pattern of a
- * jsp-property-group.
- * Force the context's welcome files, which are interpreted
- * as JSP files (since they match the url-pattern), to be
- * considered. See Bugzilla 27664.
- */
- mappingData.wrapper = null;
- checkJspWelcomeFiles = true;
- } else {
- // See Bugzilla 27704
- mappingData.wrapperPath.setChars(buf, path.getStart(),
- path.getLength());
- mappingData.pathInfo.recycle();
- }
- }
- }
-
- if(mappingData.wrapper == null && noServletPath) {
- // The path is empty, redirect to "/"
- mappingData.redirectPath.setChars
- (path.getBuffer(), pathOffset, pathEnd);
- path.setEnd(pathEnd - 1);
- return;
- }
-
- // Rule 3 -- Extension Match
- WrapperMapElement[] extensionWrappers = context.extensionWrappers;
- if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
- internalMapExtensionWrapper(extensionWrappers, path, mappingData);
- }
-
- File file = null;
- // Rule 4 -- Welcome resources processing for servlets
- if (mappingData.wrapper == null) {
- boolean checkWelcomeFiles = checkJspWelcomeFiles;
- if (!checkWelcomeFiles) {
- char[] buf = path.getBuffer();
- checkWelcomeFiles = (buf[pathEnd - 1] == '/');
- }
- if (checkWelcomeFiles) {
- for (int i = 0; (i < context.welcomeResources.length)
- && (mappingData.wrapper == null); i++) {
- path.setOffset(pathOffset);
- path.setEnd(pathEnd);
- path.append(context.welcomeResources[i], 0,
- context.welcomeResources[i].length());
- path.setOffset(servletPath);
-
- // Rule 4a -- Welcome resources processing for exact macth
- internalMapExactWrapper(exactWrappers, path, mappingData);
-
- // Rule 4b -- Welcome resources processing for prefix match
- if (mappingData.wrapper == null) {
- internalMapWildcardWrapper
- (wildcardWrappers, context.nesting,
- path, mappingData);
- }
-
- // Rule 4c -- Welcome resources processing
- // for physical folder
- if (mappingData.wrapper == null
- && context.resources != null) {
- // Default servlet: check if it's file or dir to apply
- // welcome files rules.
- // TODO: Save the File in attributes,
- // to avoid duplication in DefaultServlet.
-
- String pathStr = path.toString();
- file = new File(context.resources, pathStr);
- if (file.exists() && !(file.isDirectory()) ) {
-
- internalMapExtensionWrapper(extensionWrappers,
- path, mappingData);
- if (mappingData.wrapper == null
- && context.defaultWrapper != null) {
- mappingData.wrapper =
- context.defaultWrapper.object;
- mappingData.requestPath.setChars
- (path.getBuffer(), path.getStart(),
- path.getLength());
- mappingData.wrapperPath.setChars
- (path.getBuffer(), path.getStart(),
- path.getLength());
- mappingData.requestPath.setString(pathStr);
- mappingData.wrapperPath.setString(pathStr);
- }
- }
- }
- }
-
- path.setOffset(servletPath);
- path.setEnd(pathEnd);
- }
-
- }
-
-
- // Rule 7 -- Default servlet
- if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
- if (context.defaultWrapper != null) {
- mappingData.wrapper = context.defaultWrapper.object;
- mappingData.requestPath.setChars
- (path.getBuffer(), path.getStart(), path.getLength());
- mappingData.wrapperPath.setChars
- (path.getBuffer(), path.getStart(), path.getLength());
- }
- // Redirection to a folder
- char[] buf = path.getBuffer();
- if (context.resources != null && buf[pathEnd -1 ] != '/') {
- String pathStr = path.toString();
- file = new File( context.resources, pathStr);
- if (file.exists() && file.isDirectory()) {
- // Note: this mutates the path: do not do any processing
- // after this (since we set the redirectPath, there
- // shouldn't be any)
- path.setOffset(pathOffset);
- path.append('/');
- mappingData.redirectPath.setChars
- (path.getBuffer(), path.getStart(), path.getLength());
- } else {
- mappingData.requestPath.setString(pathStr);
- mappingData.wrapperPath.setString(pathStr);
- }
- }
- }
-
- path.setOffset(pathOffset);
- path.setEnd(pathEnd);
- }
-
-
- /**
- * Exact mapping.
- */
- private final void internalMapExactWrapper
- (WrapperMapElement[] wrappers, CharChunk path, MappingData mappingData) {
- int pos = find(wrappers, path);
- if ((pos != -1) && (path.equals(wrappers[pos].name))) {
- mappingData.requestPath.setString(wrappers[pos].name);
- mappingData.wrapperPath.setString(wrappers[pos].name);
- mappingData.wrapper = wrappers[pos].object;
- }
- }
-
-
- /**
- * Wildcard mapping.
- */
- private final void internalMapWildcardWrapper
- (WrapperMapElement[] wrappers, int nesting, CharChunk path,
- MappingData mappingData) {
-
- int pathEnd = path.getEnd();
- int pathOffset = path.getOffset();
-
- int lastSlash = -1;
- int length = -1;
- int pos = find(wrappers, path);
- if (pos != -1) {
- boolean found = false;
- while (pos >= 0) {
- if (path.startsWith(wrappers[pos].name)) {
- length = wrappers[pos].name.length();
- if (path.getLength() == length) {
- found = true;
- break;
- } else if (path.startsWithIgnoreCase("/", length)) {
- found = true;
- break;
- }
- }
- if (lastSlash == -1) {
- lastSlash = nthSlash(path, nesting + 1);
- } else {
- lastSlash = lastSlash(path);
- }
- path.setEnd(lastSlash);
- pos = find(wrappers, path);
- }
- path.setEnd(pathEnd);
- if (found) {
- mappingData.wrapperPath.setString(wrappers[pos].name);
- if (path.getLength() > length) {
- mappingData.pathInfo.setChars
- (path.getBuffer(),
- path.getOffset() + length,
- path.getLength() - length);
- }
- mappingData.requestPath.setChars
- (path.getBuffer(), path.getOffset(), path.getLength());
- mappingData.wrapper = wrappers[pos].object;
- mappingData.jspWildCard = wrappers[pos].jspWildCard;
- }
- }
- }
-
-
- /**
- * Extension mappings.
- */
- private final void internalMapExtensionWrapper
- (WrapperMapElement[] wrappers, CharChunk path, MappingData mappingData) {
- char[] buf = path.getBuffer();
- int pathEnd = path.getEnd();
- int servletPath = path.getOffset();
- int slash = -1;
- for (int i = pathEnd - 1; i >= servletPath; i--) {
- if (buf[i] == '/') {
- slash = i;
- break;
- }
- }
- if (slash == -1 ) slash = 0;
- if (slash >= 0) {
- int period = -1;
- for (int i = pathEnd - 1; i > slash; i--) {
- if (buf[i] == '.') {
- period = i;
- break;
- }
- }
- if (period >= 0) {
- path.setOffset(period + 1);
- path.setEnd(pathEnd);
- int pos = find(wrappers, path);
- if ((pos != -1)
- && (path.equals(wrappers[pos].name))) {
- mappingData.wrapperPath.setChars
- (buf, servletPath, pathEnd - servletPath);
- mappingData.requestPath.setChars
- (buf, servletPath, pathEnd - servletPath);
- mappingData.wrapper = wrappers[pos].object;
- }
- path.setOffset(servletPath);
- path.setEnd(pathEnd);
- }
- }
- }
-
-
- /**
- * Find a map elemnt given its name in a sorted array of map elements.
- * This will return the index for the closest inferior or equal item in the
- * given array.
- */
- public static final int find(MapElement[] map, CharChunk name) {
- return find(map, name, name.getStart(), name.getEnd());
- }
-
-
- /**
- * Find a map elemnt given its name in a sorted array of map elements.
- * This will return the index for the closest inferior or equal item in the
- * given array.
- */
- private static final int find(MapElement[] map, CharChunk name,
- int start, int end) {
-
- int a = 0;
- int b = map.length - 1;
-
- // Special cases: -1 and 0
- if (b == -1) {
- return -1;
- }
-
- if (compare(name, start, end, map[0].name) < 0 ) {
- return -1;
- }
- if (b == 0) {
- return 0;
- }
-
- int i = 0;
- while (true) {
- i = (b + a) / 2;
- int result = compare(name, start, end, map[i].name);
- if (result == 1) {
- a = i;
- } else if (result == 0) {
- return i;
- } else {
- b = i;
- }
- if ((b - a) == 1) {
- int result2 = compare(name, start, end, map[b].name);
- if (result2 < 0) {
- return a;
- } else {
- return b;
- }
- }
- }
-
- }
-
- /**
- * Find a map elemnt given its name in a sorted array of map elements.
- * This will return the index for the closest inferior or equal item in the
- * given array.
- */
- private static final int findIgnoreCase(MapElement[] map, CharChunk name) {
- return findIgnoreCase(map, name, name.getStart(), name.getEnd());
- }
-
-
- /**
- * Find a map elemnt given its name in a sorted array of map elements.
- * This will return the index for the closest inferior or equal item in the
- * given array.
- */
- private static final int findIgnoreCase(MapElement[] map, CharChunk name,
- int start, int end) {
-
- int a = 0;
- int b = map.length - 1;
-
- // Special cases: -1 and 0
- if (b == -1) {
- return -1;
- }
- if (compareIgnoreCase(name, start, end, map[0].name) < 0 ) {
- return -1;
- }
- if (b == 0) {
- return 0;
- }
-
- int i = 0;
- while (true) {
- i = (b + a) / 2;
- int result = compareIgnoreCase(name, start, end, map[i].name);
- if (result == 1) {
- a = i;
- } else if (result == 0) {
- return i;
- } else {
- b = i;
- }
- if ((b - a) == 1) {
- int result2 = compareIgnoreCase(name, start, end, map[b].name);
- if (result2 < 0) {
- return a;
- } else {
- return b;
- }
- }
- }
-
- }
-
-
- /**
- * Find a map elemnt given its name in a sorted array of map elements.
- * This will return the index for the closest inferior or equal item in the
- * given array.
- */
- public static final int find(MapElement[] map, String name) {
-
- int a = 0;
- int b = map.length - 1;
-
- // Special cases: -1 and 0
- if (b == -1) {
- return -1;
- }
-
- if (name.compareTo(map[0].name) < 0) {
- return -1;
- }
- if (b == 0) {
- return 0;
- }
-
- int i = 0;
- while (true) {
- i = (b + a) / 2;
- int result = name.compareTo(map[i].name);
- if (result > 0) {
- a = i;
- } else if (result == 0) {
- return i;
- } else {
- b = i;
- }
- if ((b - a) == 1) {
- int result2 = name.compareTo(map[b].name);
- if (result2 < 0) {
- return a;
- } else {
- return b;
- }
- }
- }
-
- }
-
-
- /**
- * Compare given char chunk with String.
- * Return -1, 0 or +1 if inferior, equal, or superior to the String.
- */
- private static final int compare(CharChunk name, int start, int end,
- String compareTo) {
- int result = 0;
- char[] c = name.getBuffer();
- int len = compareTo.length();
- if ((end - start) < len) {
- len = end - start;
- }
- for (int i = 0; (i < len) && (result == 0); i++) {
- if (c[i + start] > compareTo.charAt(i)) {
- result = 1;
- } else if (c[i + start] < compareTo.charAt(i)) {
- result = -1;
- }
- }
- if (result == 0) {
- if (compareTo.length() > (end - start)) {
- result = -1;
- } else if (compareTo.length() < (end - start)) {
- result = 1;
- }
- }
- return result;
- }
-
-
- /**
- * Compare given char chunk with String ignoring case.
- * Return -1, 0 or +1 if inferior, equal, or superior to the String.
- */
- private static final int compareIgnoreCase(CharChunk name, int start, int end,
- String compareTo) {
- int result = 0;
- char[] c = name.getBuffer();
- int len = compareTo.length();
- if ((end - start) < len) {
- len = end - start;
- }
- for (int i = 0; (i < len) && (result == 0); i++) {
- if (Ascii.toLower(c[i + start]) > Ascii.toLower(compareTo.charAt(i))) {
- result = 1;
- } else if (Ascii.toLower(c[i + start]) < Ascii.toLower(compareTo.charAt(i))) {
- result = -1;
- }
- }
- if (result == 0) {
- if (compareTo.length() > (end - start)) {
- result = -1;
- } else if (compareTo.length() < (end - start)) {
- result = 1;
- }
- }
- return result;
- }
-
-
- /**
- * Find the position of the last slash in the given char chunk.
- */
- public static final int lastSlash(CharChunk name) {
-
- char[] c = name.getBuffer();
- int end = name.getEnd();
- int start = name.getStart();
- int pos = end;
-
- while (pos > start) {
- if (c[--pos] == '/') {
- break;
- }
- }
-
- return (pos);
-
- }
-
-
- /**
- * Find the position of the nth slash, in the given char chunk.
- */
- public static final int nthSlash(CharChunk name, int n) {
-
- char[] c = name.getBuffer();
- int end = name.getEnd();
- int start = name.getStart();
- int pos = start;
- int count = 0;
-
- while (pos < end) {
- if ((c[pos++] == '/') && ((++count) == n)) {
- pos--;
- break;
- }
- }
-
- return (pos);
-
- }
-
-
- /**
- * Return the slash count in a given string.
- */
- public static final int slashCount(String name) {
- int pos = -1;
- int count = 0;
- while ((pos = name.indexOf('/', pos + 1)) != -1) {
- count++;
- }
- return count;
- }
-
-
- /**
- * Insert into the right place in a sorted MapElement array, and prevent
- * duplicates.
- */
- public static final boolean insertMap
- (MapElement[] oldMap, MapElement[] newMap, MapElement newElement) {
- int pos = find(oldMap, newElement.name);
- if ((pos != -1) && (newElement.name.equals(oldMap[pos].name))) {
- return false;
- }
- System.arraycopy(oldMap, 0, newMap, 0, pos + 1);
- newMap[pos + 1] = newElement;
- System.arraycopy
- (oldMap, pos + 1, newMap, pos + 2, oldMap.length - pos - 1);
- return true;
- }
-
-
- /**
- * Insert into the right place in a sorted MapElement array.
- */
- public static final boolean removeMap
- (MapElement[] oldMap, MapElement[] newMap, String name) {
- int pos = find(oldMap, name);
- if ((pos != -1) && (name.equals(oldMap[pos].name))) {
- System.arraycopy(oldMap, 0, newMap, 0, pos);
- System.arraycopy(oldMap, pos + 1, newMap, pos,
- oldMap.length - pos - 1);
- return true;
- }
- return false;
- }
-
-
- // ------------------------------------------------- MapElement Inner Class
-
-
- protected static abstract class MapElement {
- /** hostname or path
- */
- public String name = null;
- public Object object = null;
-
- public String toString() {
- return "MapElement: \"" + name +"\"";
- }
- }
-
-
- // ---------------------------------------------------- Context Inner Class
-
-
- public static final class ContextMapElement
- extends MapElement {
-
- public String[] welcomeResources = new String[0];
- public File resources = null;
- public WrapperMapElement defaultWrapper = null;
- public WrapperMapElement[] exactWrappers = new WrapperMapElement[0];
- public WrapperMapElement[] wildcardWrappers = new WrapperMapElement[0];
- public WrapperMapElement[] extensionWrappers = new WrapperMapElement[0];
- public int nesting = 0;
-
- public String toString() {
- return "ContextMapElement {" +
- "name: \"" + name +
- "\"\nnesting: \"" + nesting +
- "\"\n}";
- }
- }
-
-
- // ---------------------------------------------------- Wrapper Inner Class
-
-
- public static class WrapperMapElement
- extends MapElement {
- public boolean jspWildCard = false;
- }
-
-
- public void destroy() {
- }
-
-
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain) throws IOException,
- ServletException {
- }
-
-
- public void init(FilterConfig filterConfig) throws ServletException {
- }
-
-
-}
+++ /dev/null
-# Support for PropertiesSpi - the 'dummy' framework used for tomcat-lite
-# 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
-org.apache.tomcat.lite.WebappFilterMapper.(class)=org.apache.tomcat.lite.WebappFilterMapper
-
-# Sessions
-org.apache.tomcat.addons.UserSessionManager.(class)=org.apache.tomcat.servlets.session.SimpleSessionManager
-
-# *.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.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
-
-
+++ /dev/null
-/*
- * 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 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;
- }
-
- public boolean asyncDispatch(Request req,Response res, SocketStatus status) throws Exception {
- // implement me
- return false;
- }
-
-}
--- /dev/null
+/*
+ */
+package org.apache.tomcat.lite.service;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tomcat.lite.http.HttpRequest;
+import org.apache.tomcat.lite.http.HttpResponse;
+import org.apache.tomcat.lite.http.HttpWriter;
+import org.apache.tomcat.lite.http.HttpChannel.HttpService;
+import org.apache.tomcat.lite.http.HttpConnector.ConnectionPool;
+import org.apache.tomcat.lite.http.HttpConnector.RemoteServer;
+import org.apache.tomcat.lite.io.IOChannel;
+
+/**
+ * Dump status of a connection pool.
+ */
+public class IOStatus implements HttpService {
+
+ private ConnectionPool pool;
+
+ public IOStatus() {
+
+ }
+
+ public IOStatus(ConnectionPool pool) {
+ this.pool = pool;
+ }
+
+ @Override
+ public void service(HttpRequest httpReq, HttpResponse httpRes)
+ throws IOException {
+ ConnectionPool sc = pool == null ?
+ httpReq.getHttpChannel().getConnector().cpool :
+ pool;
+ HttpWriter out = httpRes.getBodyWriter();
+
+ httpRes.setContentType("text/plain");
+ out.println("hosts=" + sc.getTargetCount());
+ out.println("waiting=" + sc.getSocketCount());
+ out.println("closed=" + sc.getClosedSockets());
+ out.println();
+
+ for (Map.Entry<CharSequence, RemoteServer> e: sc.hosts.entrySet()) {
+ out.append(e.getKey());
+ out.append("=");
+ out.println(Integer.toString(e.getValue().connections.size()));
+
+ for (IOChannel ch: e.getValue().connections) {
+ out.println(ch.getId() +
+ " " + ch.toString());
+ }
+ out.println();
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * 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.service;
+
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.apache.tomcat.integration.DynamicObject;
+import org.apache.tomcat.integration.ObjectManager;
+
+/**
+ * Send all registered JMX objects and properties as JSON.
+ *
+ * Based on JMXProxy servlet, but:
+ * - Async handler instead of servlet - so it works with 'raw' connector
+ * - doesn't use JMX - integrates with the ObjectManager ( assuming OM
+ * provies a list of managed objects )
+ * - all the reflection magic from modeler is implemented here.
+ *
+ * @author Costin Manolache
+ */
+public class JMXProxy extends ObjectManager implements Runnable {
+
+ static Logger log = Logger.getLogger(JMXProxy.class.getName());
+
+ protected ObjectManager om;
+
+ Map<Class, DynamicObject> types = new HashMap<Class, DynamicObject>();
+
+ Map<String, Object> objects = new HashMap();
+
+
+ public void bind(String name, Object o) {
+ objects.put(name, o);
+ }
+
+ public void unbind(String name) {
+ objects.remove(name);
+ }
+
+
+ public void setObjectManager(ObjectManager om) {
+ this.om = om;
+ }
+
+
+ private DynamicObject getClassInfo(Class beanClass) {
+ if (types.get(beanClass) != null) {
+ return types.get(beanClass);
+ }
+ DynamicObject res = new DynamicObject(beanClass);
+ types.put(beanClass, res);
+ return res;
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+ public void getAttribute(PrintWriter writer, String onameStr, String att) {
+ try {
+
+ Object bean = objects.get(onameStr);
+ Class beanClass = bean.getClass();
+ DynamicObject ci = getClassInfo(beanClass);
+
+ Object value = ci.getAttribute(bean, att);
+ writer.println("OK - Attribute get '" + onameStr + "' - " + att
+ + "= " + escape(value.toString()));
+ } catch (Exception ex) {
+ writer.println("Error - " + ex.toString());
+ }
+ }
+
+
+ public void setAttribute( PrintWriter writer,
+ String onameStr, String att, String val )
+ {
+ try {
+ Object bean = objects.get(onameStr);
+ Class beanClass = bean.getClass();
+ DynamicObject ci = getClassInfo(beanClass);
+
+ ci.setProperty(bean, att, val);
+ writer.println("OK - Attribute set");
+ } catch( Exception ex ) {
+ writer.println("Error - " + ex.toString());
+ }
+ }
+
+ public void listBeans( PrintWriter writer, String qry, boolean json )
+ {
+ if (json) {
+ listBeansJson(writer, qry);
+ return;
+ }
+ Set<String> names = objects.keySet();
+ writer.println("OK - Number of results: " + names.size());
+ writer.println();
+
+ Iterator<String> it=names.iterator();
+ while( it.hasNext()) {
+ String oname=it.next();
+ writer.println( "Name: " + oname);
+
+ try {
+ Object bean = objects.get(oname);
+ Class beanClass = bean.getClass();
+ DynamicObject ci = getClassInfo(beanClass);
+ writer.println("modelerType: " + beanClass.getName());
+
+ Object value=null;
+ for (String attName: ci.attributeNames()) {
+ try {
+ value = ci.getAttribute(bean, attName);
+ } catch( Throwable t) {
+ System.err.println("Error getting attribute " + oname +
+ " " + attName + " " + t.toString());
+ continue;
+ }
+ if( value==null ) continue;
+ String valueString=value.toString();
+ writer.println( attName + ": " + escape(valueString));
+ }
+ } catch (Exception e) {
+ // Ignore
+ }
+ writer.println();
+ }
+
+ }
+
+ private static void json(PrintWriter writer, String name, String value) {
+ writer.write("\"" + name +"\":" + "\"" + escapeJson(value) + "\",");
+ }
+
+ private void listBeansJson(PrintWriter writer, String qry) {
+ Set<String> names = objects.keySet();
+ writer.println("[");
+
+ Iterator<String> it=names.iterator();
+ while( it.hasNext()) {
+ writer.print("{");
+ String oname=it.next();
+ json(writer, "name", oname);
+
+ try {
+ Object bean = objects.get(oname);
+ Class beanClass = bean.getClass();
+ DynamicObject ci = getClassInfo(beanClass);
+ json(writer, "modelerType", beanClass.getName());
+
+ Object value=null;
+ for (String attName: ci.attributeNames()) {
+ try {
+ value = ci.getAttribute(bean, attName);
+ } catch( Throwable t) {
+ System.err.println("Error getting attribute " + oname +
+ " " + attName + " " + t.toString());
+ continue;
+ }
+ if( value==null ) continue;
+ String valueString=value.toString();
+ json(writer, attName, valueString);
+ }
+ writer.println("}");
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ writer.println("]");
+ }
+
+ public static String escapeJson(String value) {
+ return value;
+ }
+
+ public static String escape(String value) {
+ // The only invalid char is \n
+ // We also need to keep the string short and split it with \nSPACE
+ // XXX TODO
+ int idx=value.indexOf( "\n" );
+ if( idx < 0 ) return value;
+
+ int prev=0;
+ StringBuffer sb=new StringBuffer();
+ while( idx >= 0 ) {
+ appendHead(sb, value, prev, idx);
+
+ sb.append( "\\n\n ");
+ prev=idx+1;
+ if( idx==value.length() -1 ) break;
+ idx=value.indexOf('\n', idx+1);
+ }
+ if( prev < value.length() )
+ appendHead( sb, value, prev, value.length());
+ return sb.toString();
+ }
+
+ private static void appendHead( StringBuffer sb, String value, int start, int end) {
+ if (end < 1) return;
+
+ int pos=start;
+ while( end-pos > 78 ) {
+ sb.append( value.substring(pos, pos+78));
+ sb.append( "\n ");
+ pos=pos+78;
+ }
+ sb.append( value.substring(pos,end));
+ }
+
+ public boolean isSupported( String type ) {
+ return true;
+ }
+
+ @Override
+ public void run() {
+
+ }
+}
--- /dev/null
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * Copyright 2004 Costin Manolache
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tomcat.lite.service;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.tomcat.lite.http.HttpRequest;
+import org.apache.tomcat.lite.http.HttpResponse;
+import org.apache.tomcat.lite.http.HttpChannel.HttpService;
+
+/**
+ * Log configuration
+ *
+ */
+public class LogConfig implements HttpService {
+
+ /**
+ * Framework can set this attribute with comma separated
+ * list of loggers to set to debug level.
+ * This is used at startup.
+ */
+ public void setDebug(String debug) {
+ for (String log : debug.split(",")) {
+ Logger logger = Logger.getLogger(log);
+ logger.setLevel(Level.INFO);
+ }
+ }
+
+ /**
+ *
+ */
+ public void setWarn(String nodebug) {
+ for (String log : nodebug.split(",")) {
+ Logger logger = Logger.getLogger(log);
+ logger.setLevel(Level.WARNING);
+ }
+ }
+
+ @Override
+ public void service(HttpRequest httpReq, HttpResponse httpRes)
+ throws IOException {
+ String debug = httpReq.getParameter("debug");
+ setDebug(debug);
+ String warn = httpReq.getParameter("warn");
+ setWarn(warn);
+ }
+}
+++ /dev/null
-/*
- * 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.webxml;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-/**
- * All the data in web.xml, annotations, etc should be represented
- * here. This class is serializable.
- *
- * Public fields to make it easy to access it.
- * Naming should match the web.xml element name.
- *
- * @author Costin Manolache
- */
-public class ServletContextConfig implements Serializable {
-
- private static final long serialVersionUID = 1728492145981883124L;
-
- public String fileName;
- public long timestamp;
-
- public boolean full;
-
- public String displayName;
-
- public HashMap<String, String> contextParam = new HashMap<String, String>();
-
- public HashMap<String, String> mimeMapping = new HashMap<String, String>(); // extension -> mime-type
-
- public ArrayList<String> listenerClass = new ArrayList<String>();
-
- public ArrayList<String> welcomeFileList = new ArrayList<String>();
-
- // code -> location
- public HashMap<String, String> errorPageCode= new HashMap<String, String>();
-
- // exception -> location
- public HashMap<String, String> errorPageException= new HashMap<String, String>();
-
- public HashMap<String, String> localeEncodingMapping= new HashMap<String, String>(); // locale -> encoding
-
- // public HashMap tagLibs; // uri->location
- // jsp-property-group
-
- // securityConstraint
- public ArrayList<SecurityConstraintData> securityConstraint = new ArrayList<SecurityConstraintData>();
-
- // loginConfig
- public String authMethod;
- public String realmName;
- public String formLoginPage;
- public String formErrorPage;
-
- public ArrayList<String> securityRole = new ArrayList<String>();
-
- // envEntry
- public ArrayList<EnvEntryData> envEntry = new ArrayList<EnvEntryData>();
-
- // ejbRef
- // ejbLocalRef
- // serviceRef
- // resourceRef
- // resourceEnvRef
- // message-destination
- // message-destinationRef
- public HashMap<String, FilterData> filters = new HashMap<String, FilterData>();
- public HashMap<String, ServletData> servlets = new HashMap<String, ServletData>();
-
- public int sessionTimeout;
- public boolean distributable;
-
- public HashMap<String, String> servletMapping = new HashMap<String, String>(); // url -> servlet
- public ArrayList<FilterMappingData> filterMappings = new ArrayList<FilterMappingData>();
-
-
- public static class FilterData implements Serializable {
- private static final long serialVersionUID = -535820271746973166L;
-
- public HashMap<String, String> initParams = new HashMap<String, String>();
- public String filterClass;
- public String filterName;
- }
-
- // Normalized
- public static class FilterMappingData implements Serializable {
- private static final long serialVersionUID = -4533568066713041994L;
- public String filterName;
-
- // Only one of the 2
- public String urlPattern;
- public String servletName;
-
- // REQUEST, FORWARD, INCLUDE, ERROR, ASYNC
- public ArrayList<String> dispatcher = new ArrayList<String>();
- }
-
- public static class EnvEntryData implements Serializable {
- private static final long serialVersionUID = 7023847615343715257L;
- public String envEntryName;
- public String envEntryType;
- public String envEntryValue;
- }
-
- public static class ServletData implements Serializable {
- private static final long serialVersionUID = -3216904178501185930L;
-
- public ServletData() {
- }
- public ServletData(String servletName, String servletClass) {
- this.servletClass = servletClass;
- this.servletName = servletName;
- }
-
- public HashMap<String, String> initParams = new HashMap<String, String>();
- public String servletName;
- public String servletClass;
- public String jspFile;
- public int loadOnStartup = -1;
- public String runAs;
- public HashMap<String, String> securityRoleRef = new HashMap<String, String>(); // roleName -> [roleLink]
-
- }
-
- public static class WebResourceCollectionData implements Serializable {
- public String webResourceName;
- public ArrayList urlPattern = new ArrayList();
- public ArrayList httpMethod = new ArrayList();
- }
-
- public static class SecurityConstraintData implements Serializable {
- private static final long serialVersionUID = -4780214921810871769L;
-
- public ArrayList<String> roleName = new ArrayList<String>(); // auth-constraint/role
-
- public ArrayList<WebResourceCollectionData> webResourceCollection =
- new ArrayList<WebResourceCollectionData>();
- public String transportGuarantee;
-
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * 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.webxml;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-
-import org.apache.tomcat.lite.ContextPreinitListener;
-import org.apache.tomcat.lite.ServletContextImpl;
-
-/**
- * Default configurator - parse web.xml, init the context.
- *
- * Will be executed first - if set as the default config addon.
- *
- * Possible extensions:
- * - read from a .ser file instead of web.xml
- * - custom code for manual/extra config
- * - read from a central repo
- *
- * @author Costin Manolache
- */
-public class TomcatLiteWebXmlConfig implements ContextPreinitListener {
-
- protected void readWebXml(ServletContextImpl ctx,
- String base) throws ServletException {
- // TODO: .ser, reloading, etc
-// if (contextConfig != null && contextConfig.fileName != null) {
-// // TODO: this should move to deploy - if not set, there is no point
-// File f = new File(contextConfig.fileName);
-// if (f.exists()) {
-// if (f.lastModified() > contextConfig.timestamp + 1000) {
-// log("Reloading web.xml");
-// contextConfig = null;
-// }
-// } else {
-// log("Old web.xml");
-// contextConfig = null;
-// }
-// }
- if (base != null) {
- WebXml webXml = new WebXml(ctx.getContextConfig());
- webXml.readWebXml(base);
- }
- }
-
- @Override
- public void preInit(ServletContext ctx) {
- ServletContextImpl servletContext =
- (ServletContextImpl) ctx;
-
- String base = servletContext.getBasePath();
- if (base == null) {
- return; // nothing we can do
- }
- try {
- readWebXml(servletContext, base);
- } catch (ServletException e) {
- // TODO Auto-generated catch block
- throw new RuntimeException(e);
- }
- }
-
-}
+++ /dev/null
-/*
- * 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.webxml;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-import javax.servlet.ServletException;
-
-import org.apache.tomcat.lite.webxml.ServletContextConfig.EnvEntryData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.FilterData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.FilterMappingData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.SecurityConstraintData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.ServletData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.WebResourceCollectionData;
-import org.apache.tomcat.util.DomUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-/**
- * General-purpose utility to process an web.xml file. Result
- * is a tree of objects starting with WebAppData.
- *
- * TODO: allow writting of web.xml, allow modification ( preserving
- * comments )
- *
- * @author costin
- */
-public class WebXml {
- ServletContextConfig d;
-
- public WebXml(ServletContextConfig cfg) {
- d = cfg;
- }
-
- public ServletContextConfig getWebAppData() {
- return d;
- }
-
- public void readWebXml(String baseDir) throws ServletException {
- try {
- File webXmlFile = new File( baseDir + "/WEB-INF/web.xml");
- if (!webXmlFile.exists()) {
- return;
- }
- d.fileName = webXmlFile.getCanonicalPath();
- d.timestamp = webXmlFile.lastModified();
-
- FileInputStream fileInputStream = new FileInputStream(webXmlFile);
- readWebXml(fileInputStream);
- } catch (Exception e) {
- e.printStackTrace();
- throw new ServletException(e);
- }
- }
-
- public void readWebXml(InputStream fileInputStream)
- throws ServletException {
- try {
-
- Document document = DomUtil.readXml(fileInputStream);
- Node webappNode = DomUtil.getChild(document, "web-app");
-
- String fullS = DomUtil.getAttribute(webappNode, "full");
- if (fullS != null && fullS.equalsIgnoreCase("true")) {
- d.full = true;
- }
-
- d.displayName = DomUtil.getAttribute(webappNode, "display-name");
-
- // Process each child of web-app
- Node confNode = DomUtil.getChild(webappNode, "filter");
- while (confNode != null ) {
- processFilter(confNode);
- confNode = DomUtil.getNext(confNode);
- }
-
- confNode = DomUtil.getChild(webappNode, "filter-mapping");
- while (confNode != null ) {
- processFilterMapping(confNode);
- confNode = DomUtil.getNext(confNode);
- }
-
- confNode = DomUtil.getChild(webappNode, "context-param");
- while (confNode != null ) {
- String n = DomUtil.getChildContent(confNode, "param-name").trim();
- String v = DomUtil.getChildContent(confNode, "param-value").trim();
- d.contextParam.put(n, v);
- confNode = DomUtil.getNext(confNode);
- }
-
- confNode = DomUtil.getChild(webappNode, "mime-mapping");
- while (confNode != null ) {
- String n = DomUtil.getChildContent(confNode, "extension");
- String t = DomUtil.getChildContent(confNode, "mime-type");
- d.mimeMapping.put(n, t);
- confNode = DomUtil.getNext(confNode);
- }
-
- confNode = DomUtil.getChild(webappNode, "error-page");
- while (confNode != null ) {
- processErrorPage(confNode);
- confNode = DomUtil.getNext(confNode);
- }
-
- confNode = DomUtil.getChild(webappNode, "jsp-config");
- while (confNode != null ) {
- processJspConfig(confNode);
- confNode = DomUtil.getNext(confNode);
- }
-
- confNode = DomUtil.getChild(webappNode, "servlet");
- while (confNode != null ) {
- processServlet(confNode);
- confNode = DomUtil.getNext(confNode);
- }
-
- confNode = DomUtil.getChild(webappNode, "servlet-mapping");
- while (confNode != null ) {
- processServletMapping(confNode);
- confNode = DomUtil.getNext(confNode);
- }
-
- confNode = DomUtil.getChild(webappNode, "listener");
- while (confNode != null ) {
- String lClass = DomUtil.getChildContent(confNode, "listener-class");
- d.listenerClass.add(lClass);
- confNode = DomUtil.getNext(confNode);
- }
-
- confNode = DomUtil.getChild(webappNode, "security-constraint");
- while (confNode != null ) {
- processSecurityConstraint(confNode);
- confNode = DomUtil.getNext(confNode);
- }
-
- confNode = DomUtil.getChild(webappNode, "login-config");
- while (confNode != null ) {
- processLoginConfig(confNode);
- confNode = DomUtil.getNext(confNode);
- if (confNode != null)
- throw new ServletException("Multiple login-config");
- }
-
- confNode = DomUtil.getChild(webappNode, "session-config");
- while (confNode != null ) {
- String n = DomUtil.getChildContent(confNode, "session-timeout");
- int stout = Integer.parseInt(n);
- d.sessionTimeout = stout;
- confNode = DomUtil.getNext(confNode);
- if (confNode != null)
- throw new ServletException("Multiple session-config");
- }
-
- confNode = DomUtil.getChild(webappNode, "welcome-file-list");
- while (confNode != null ) {
- Node wf = DomUtil.getChild(confNode, "welcome-file");
- while (wf != null) {
- String file = DomUtil.getContent(wf);
- d.welcomeFileList.add(file);
- wf = DomUtil.getNext(wf);
- }
- // more sections ?
- confNode = DomUtil.getNext(confNode);
- }
-
- // Not supported right now - TODO: collect, have jndi plugin
- confNode = DomUtil.getChild(webappNode, "env-entry");
- while (confNode != null ) {
- processEnvEntry(confNode);
- confNode = DomUtil.getNext(confNode);
- }
-
- confNode = DomUtil.getChild(webappNode, "locale-encoding-mapping-list");
- while (confNode != null ) {
- confNode = DomUtil.getNext(confNode);
- String n = DomUtil.getChildContent(confNode, "locale");
- String t = DomUtil.getChildContent(confNode, "encoding");
- d.localeEncodingMapping.put(n, t);
- }
-
- confNode = DomUtil.getChild(webappNode, "distributable");
- while (confNode != null ) {
- d.distributable = true;
- confNode = DomUtil.getNext(confNode);
- }
-
- confNode = DomUtil.getChild(confNode, "security-role");
- while (confNode != null ) {
- String n = DomUtil.getChildContent(confNode, "role-name");
- d.securityRole.add(n);
- confNode = DomUtil.getNext(confNode);
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- throw new ServletException(e);
- }
- }
-
- private void processJspConfig(Node confNode) {
- Node tagLib = DomUtil.getChild(confNode, "taglib");
- while (tagLib != null) {
- String uri = DomUtil.getChildContent(tagLib, "taglib-uri");
- String l = DomUtil.getChildContent(tagLib, "taglib-location");
- //d.tagLibs.put(uri, l);
- tagLib = DomUtil.getNext(tagLib);
- }
-
- tagLib = DomUtil.getChild(confNode, "jsp-property-group");
- while (tagLib != null) {
- // That would be the job of the JSP servlet to process.
- tagLib = DomUtil.getNext(tagLib);
- }
- }
-
- private void processEnvEntry(Node confNode) {
- EnvEntryData ed = new EnvEntryData();
- ed.envEntryName = DomUtil.getChildContent(confNode,"env-entry-name");
- ed.envEntryType = DomUtil.getChildContent(confNode,"env-entry-type");
- ed.envEntryValue = DomUtil.getChildContent(confNode,"env-entry-value");
- d.envEntry.add(ed);
- }
-
- private void processLoginConfig(Node confNode) {
- d.authMethod = DomUtil.getChildContent(confNode,"auth-method");
- d.realmName = DomUtil.getChildContent(confNode,"auth-method");
- Node formNode = DomUtil.getChild(confNode, "form-login-config");
- if (formNode != null) {
- d.formLoginPage = DomUtil.getChildContent(formNode,"form-login-page");
- d.formErrorPage = DomUtil.getChildContent(formNode,"form-error-page");
- }
- }
-
- private void processSecurityConstraint(Node confNode) {
- SecurityConstraintData sd = new SecurityConstraintData();
- Node cn = DomUtil.getChild(confNode, "web-resource-collection");
- while (cn != null) {
- WebResourceCollectionData wrd = new WebResourceCollectionData();
- wrd.webResourceName = DomUtil.getChildContent(cn, "web-resource-name");
- Node scn = DomUtil.getChild(cn,"url-pattern");
- while (scn != null) {
- wrd.urlPattern.add(DomUtil.getContent(scn));
- scn = DomUtil.getNext(scn);
- }
- scn = DomUtil.getChild(cn,"http-method");
- while (scn != null) {
- wrd.httpMethod.add(DomUtil.getContent(scn));
- scn = DomUtil.getNext(scn);
- }
- cn = DomUtil.getNext(cn);
- sd.webResourceCollection.add(wrd);
- }
-
- d.securityConstraint.add(sd);
- }
-
- private void processErrorPage(Node confNode) {
- String name = DomUtil.getChildContent(confNode,"location");
- String c = DomUtil.getChildContent(confNode,"error-code");
- String t = DomUtil.getChildContent(confNode,"exception-type");
- if (c != null) {
- d.errorPageCode.put(c, name);
- }
- if (t != null) {
- d.errorPageException.put(t, name);
- }
- }
-
- private void processServlet(Node confNode) throws ServletException {
- ServletData sd = new ServletData();
-
- sd.servletName = DomUtil.getChildContent(confNode,"servlet-name");
- sd.servletClass = DomUtil.getChildContent(confNode,"servlet-class");
- sd.jspFile = DomUtil.getChildContent(confNode,"jsp-file");
-
- processInitParams(confNode, sd.initParams);
-
- d.servlets.put( sd.servletName, sd );
-
- String los = DomUtil.getChildContent(confNode, "load-on-startup");
- if (los != null ) {
- sd.loadOnStartup = Integer.parseInt(los);
- }
-
- Node sn = DomUtil.getChild(confNode, "security-role-ref");
- while (sn != null ) {
- String roleName = DomUtil.getChildContent(sn, "role-name");
- String roleLink = DomUtil.getChildContent(sn, "role-link");
- if (roleLink == null) {
- sd.securityRoleRef.put(roleName, "");
- } else {
- sd.securityRoleRef.put(roleName, roleLink);
- }
- sn = DomUtil.getNext(sn);
- }
- }
-
- private void processInitParams(Node confNode, HashMap initParams) {
- Node initN = DomUtil.getChild(confNode, "init-param");
- while (initN != null ) {
- String n = DomUtil.getChildContent(initN, "param-name");
- String v = DomUtil.getChildContent(initN, "param-value");
- initParams.put(n, v);
- initN = DomUtil.getNext(initN);
- }
- }
-
- private void processServletMapping(Node confNode) {
- String name = DomUtil.getChildContent(confNode,"servlet-name");
- Node dataN = DomUtil.getChild(confNode, "url-pattern");
- while (dataN != null) {
- String path = DomUtil.getContent(dataN).trim();
- dataN = DomUtil.getNext(dataN);
-
- if (! (path.startsWith("/") || path.startsWith("*"))) {
- // backward compat
- path = "/" + path;
- }
- d.servletMapping.put(path, name);
- }
- }
-
- private void processFilterMapping(Node confNode) {
- String filterName = DomUtil.getChildContent(confNode,"filter-name");
- // multiple
- ArrayList dispatchers = new ArrayList();
- Node dataN = DomUtil.getChild(confNode, "dispatcher");
- while (dataN != null ) {
- String d = DomUtil.getContent(dataN);
- dispatchers.add(d);
- dataN = DomUtil.getNext(dataN);
- }
-
- // Multiple url-pattern and servlet-name in one
- // mapping rule. Need to be applied in order.
- dataN = DomUtil.getChild(confNode, "url-pattern");
- while (dataN != null ) {
- FilterMappingData fm = new FilterMappingData();
- fm.filterName = filterName;
- fm.dispatcher = dispatchers;
- String path = DomUtil.getContent(dataN);
- dataN = DomUtil.getNext(dataN);
- fm.urlPattern = path;
- d.filterMappings.add(fm);
- }
- dataN = DomUtil.getChild(confNode, "servlet-name");
- while (dataN != null ) {
- FilterMappingData fm = new FilterMappingData();
- fm.filterName = filterName;
- fm.dispatcher = dispatchers;
- String sn = DomUtil.getContent(dataN);
- dataN = DomUtil.getNext(dataN);
- fm.servletName = sn;
- d.filterMappings.add(fm);
- }
- }
-
- private void processFilter(Node confNode) {
- String name = DomUtil.getChildContent(confNode,"filter-name");
- String sclass = DomUtil.getChildContent(confNode,"filter-class");
-
- FilterData fd = new FilterData();
- processInitParams(confNode, fd.initParams);
- fd.filterName = name;
- fd.filterClass = sclass;
- d.filters.put(name, fd);
- }
-
-}