You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by pa...@apache.org on 2002/08/04 21:39:50 UTC
cvs commit: jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5 Constants.java CoyoteAdapter.java CoyoteConnector.java CoyoteInputStream.java CoyoteOutputStream.java CoyoteRequest.java CoyoteRequestFacade.java CoyoteResponse.java CoyoteResponseFacade.java CoyoteServerSocketFactory.java CoyoteWriter.java LocalStrings.properties OutputBuffer.java
patrickl 2002/08/04 12:39:50
Modified: coyote build.xml
coyote/src/java/org/apache/coyote/tomcat4
CoyoteResponse.java
Added: coyote/src/java/org/apache/coyote/tomcat5 Constants.java
CoyoteAdapter.java CoyoteConnector.java
CoyoteInputStream.java CoyoteOutputStream.java
CoyoteRequest.java CoyoteRequestFacade.java
CoyoteResponse.java CoyoteResponseFacade.java
CoyoteServerSocketFactory.java CoyoteWriter.java
LocalStrings.properties OutputBuffer.java
Log:
Create separate Tomcat 5 Coyote adapter and back out recent commits to Tomcat 4 Coyote adapter
Revision Changes Path
1.11 +41 -4 jakarta-tomcat-connectors/coyote/build.xml
Index: build.xml
===================================================================
RCS file: /home/cvs/jakarta-tomcat-connectors/coyote/build.xml,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- build.xml 24 Jun 2002 19:32:39 -0000 1.10
+++ build.xml 4 Aug 2002 19:39:49 -0000 1.11
@@ -111,6 +111,9 @@
<!-- ========== Detection and Reports ===================================== -->
+ <target name="report-tc5" if="tomcat5.detect" >
+ <echo message="Tomcat5 detected " />
+ </target>
<target name="report-tc4" if="tomcat4.detect" >
<echo message="Tomcat4 detected " />
</target>
@@ -118,7 +121,7 @@
<echo message="Tomcat3.3 detected " />
</target>
- <target name="report" depends="report-tc4, report-tc33" />
+ <target name="report" depends="report-tc5, report-tc4, report-tc33" />
<!-- ========== Executable Targets ======================================== -->
@@ -141,7 +144,26 @@
<mkdir dir="${build.home}/docs/api"/>
<mkdir dir="${build.home}/lib"/>
<mkdir dir="${build.home}/tests"/>
- <available property="tomcat4.detect" file="${catalina.home}/server/lib/catalina.jar" />
+ <condition property="tomcat5.detect">
+ <and>
+ <available file="${catalina.home}/server/lib/catalina.jar" />
+ <available
+ classname="javax.servlet.ServletRequestEvent"
+ classpath="${catalina.home}/common/lib/servlet.jar"
+ />
+ </and>
+ </condition>
+ <condition property="tomcat4.detect">
+ <and>
+ <available file="${catalina.home}/server/lib/catalina.jar" />
+ <not>
+ <available
+ classname="javax.servlet.ServletRequestEvent"
+ classpath="${catalina.home}/common/lib/servlet.jar"
+ />
+ </not>
+ </and>
+ </condition>
<available property="tomcat33.detect" file="${tomcat33.home}/lib/common/tomcat_core.jar" />
</target>
@@ -172,6 +194,21 @@
</target>
+ <target name="compile.tomcat5" if="tomcat5.detect"
+ description="Compile Tomcat 5.x Adapter">
+ <javac srcdir="${source.home}"
+ destdir="${build.home}/classes"
+ debug="${compile.debug}"
+ deprecation="${compile.deprecation}"
+ optimize="${compile.optimize}">
+ <classpath refid="compile.classpath"/>
+ <include name="org/apache/coyote/tomcat5/**" />
+ </javac>
+ <copy todir="${build.home}/classes" filtering="on">
+ <fileset dir="${source.home}" excludes="**/*.java"/>
+ </copy>
+ </target>
+
<target name="compile.tomcat4" if="tomcat4.detect"
description="Compile Tomcat 4.x Adapter">
<javac srcdir="${source.home}"
@@ -280,4 +317,4 @@
</target>
-</project>
\ No newline at end of file
+</project>
1.20 +0 -18 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponse.java
Index: CoyoteResponse.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat4/CoyoteResponse.java,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -r1.19 -r1.20
--- CoyoteResponse.java 1 Aug 2002 17:20:36 -0000 1.19
+++ CoyoteResponse.java 4 Aug 2002 19:39:49 -0000 1.20
@@ -717,24 +717,6 @@
}
- /*
- * 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;
-
- if (included)
- return; // Ignore any call from an included servlet
-
- coyoteResponse.setCharacterEncoding(charset);
- }
-
/**
* Set the Locale that is appropriate for this response, including
* setting the appropriate character encoding.
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/Constants.java
Index: Constants.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.coyote.tomcat5;
import java.util.Locale;
/**
* Constants.
*
* @author Remy Maucherat
*/
public final class Constants {
// -------------------------------------------------------------- Constants
public static final String Package = "org.apache.coyote.tomcat5";
public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
public static final int PROCESSOR_IDLE = 0;
public static final int PROCESSOR_ACTIVE = 1;
/**
* Default header names.
*/
public static final String AUTHORIZATION_HEADER = "authorization";
}
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteAdapter.java
Index: CoyoteAdapter.java
===================================================================
/* * $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteAdapter.java,v 1.1 2002/08/04 19:39:49 patrickl Exp $
* $Revision: 1.1 $
* $Date: 2002/08/04 19:39:49 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.coyote.tomcat5;
import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.InterruptedIOException;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Locale;
import java.util.StringTokenizer;
import java.util.TreeMap;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.HexUtils;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.Cookies;
import org.apache.tomcat.util.http.ServerCookie;
import org.apache.coyote.ActionCode;
import org.apache.coyote.ActionHook;
import org.apache.coyote.Adapter;
import org.apache.coyote.InputBuffer;
import org.apache.coyote.OutputBuffer;
import org.apache.coyote.Request;
import org.apache.coyote.Response;
import org.apache.catalina.Connector;
import org.apache.catalina.Container;
import org.apache.catalina.Globals;
import org.apache.catalina.HttpRequest;
import org.apache.catalina.HttpResponse;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Logger;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.catalina.util.RequestUtil;
import org.apache.catalina.util.StringManager;
import org.apache.catalina.util.StringParser;
/**
* Implementation of a request processor which delegates the processing to a
* Coyote processor.
*
* @author Craig R. McClanahan
* @author Remy Maucherat
* @version $Revision: 1.1 $ $Date: 2002/08/04 19:39:49 $
*/
final class CoyoteAdapter
implements Adapter {
// -------------------------------------------------------------- Constants
public static final int ADAPTER_NOTES = 1;
// ----------------------------------------------------------- Constructors
/**
* Construct a new CoyoteProcessor associated with the specified connector.
*
* @param connector CoyoteConnector that owns this processor
* @param id Identifier of this CoyoteProcessor (unique per connector)
*/
public CoyoteAdapter(CoyoteConnector connector) {
super();
this.connector = connector;
this.debug = connector.getDebug();
}
// ----------------------------------------------------- Instance Variables
/**
* The CoyoteConnector with which this processor is associated.
*/
private CoyoteConnector connector = null;
/**
* The debugging detail level for this component.
*/
private int debug = 0;
/**
* The match string for identifying a session ID parameter.
*/
private static final String match =
";" + Globals.SESSION_PARAMETER_NAME + "=";
/**
* The match string for identifying a session ID parameter.
*/
private static final char[] SESSION_ID = match.toCharArray();
/**
* The string manager for this package.
*/
protected StringManager sm =
StringManager.getManager(Constants.Package);
// -------------------------------------------------------- Adapter Methods
/**
* Service method.
*/
public void service(Request req, Response res)
throws Exception {
CoyoteRequest request = (CoyoteRequest) req.getNote(ADAPTER_NOTES);
CoyoteResponse response = (CoyoteResponse) res.getNote(ADAPTER_NOTES);
if (request == null) {
// Create objects
request = (CoyoteRequest) connector.createRequest();
request.setCoyoteRequest(req);
response = (CoyoteResponse) connector.createResponse();
response.setCoyoteResponse(res);
// Link objects
request.setResponse(response);
response.setRequest(request);
// Set as notes
req.setNote(ADAPTER_NOTES, request);
res.setNote(ADAPTER_NOTES, response);
}
try {
// Parse and set Catalina and configuration specific
// request parameters
postParseRequest(req, request, res, response);
// Calling the container
connector.getContainer().invoke(request, response);
response.finishResponse();
req.action( ActionCode.ACTION_POST_REQUEST , null);
} catch (IOException e) {
;
} catch (Throwable t) {
log(sm.getString("coyoteAdapter.service"), t);
} finally {
// Recycle the wrapper request and response
request.recycle();
response.recycle();
}
}
// ------------------------------------------------------ Protected Methods
/**
* Parse additional request parameters.
*/
protected void postParseRequest(Request req, CoyoteRequest request,
Response res, CoyoteResponse response)
throws IOException {
request.setSecure(connector.getSecure());
req.scheme().setString(connector.getScheme());
request.setAuthorization
(req.getHeader(Constants.AUTHORIZATION_HEADER));
// Replace the default port if we are in secure mode
if (req.getServerPort() == 80
&& connector.getScheme().equals("https")) {
req.setServerPort(443);
}
// At this point the Host header has been processed.
// Override if the proxyPort/proxyHost are set
String proxyName = connector.getProxyName();
int proxyPort = connector.getProxyPort();
if (proxyPort != 0) {
request.setServerPort(proxyPort);
req.setServerPort(proxyPort);
} else {
request.setServerPort(req.getServerPort());
}
if (proxyName != null) {
request.setServerName(proxyName);
req.serverName().setString(proxyName);
} else {
request.setServerName(req.serverName().toString());
}
// URI decoding
req.decodedURI().duplicate(req.requestURI());
req.getURLDecoder().convert(req.decodedURI(), true);
req.decodedURI().setEncoding("UTF-8");
// Normalize decoded URI
if (!normalize(req.decodedURI())) {
res.setStatus(400);
res.setMessage("Invalid URI");
throw new IOException("Invalid URI");
}
// Parse session Id
parseSessionId(req, request);
// Additional URI normalization and validation is needed for security
// reasons on Tomcat 4.0.x
if (connector.getUseURIValidationHack()) {
String uri = validate(request.getRequestURI());
if (uri == null) {
res.setStatus(400);
res.setMessage("Invalid URI");
throw new IOException("Invalid URI");
} else {
req.requestURI().setString(uri);
// Redoing the URI decoding
req.decodedURI().duplicate(req.requestURI());
req.getURLDecoder().convert(req.decodedURI(), true);
}
}
// Parse cookies
parseCookies(req, request);
// Set the SSL properties
res.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE,request.getRequest());
}
/**
* Parse session id in URL.
* FIXME: Optimize this.
*/
protected void parseSessionId(Request req, CoyoteRequest request) {
ByteChunk uriBC = req.decodedURI().getByteChunk();
int semicolon = uriBC.indexOf(match, 0, match.length(), 0);
if (semicolon > 0) {
// Parse session ID, and extract it from the decoded request URI
String uri = uriBC.toString();
String rest = uri.substring(semicolon + match.length());
int semicolon2 = rest.indexOf(';');
if (semicolon2 >= 0) {
request.setRequestedSessionId(rest.substring(0, semicolon2));
rest = rest.substring(semicolon2);
} else {
request.setRequestedSessionId(rest);
rest = "";
}
request.setRequestedSessionURL(true);
req.decodedURI().setString(uri.substring(0, semicolon) + rest);
// Extract session ID from request URI
uri = req.requestURI().toString();
semicolon = uri.indexOf(match);
if (semicolon > 0) {
rest = uri.substring(semicolon + match.length());
semicolon2 = rest.indexOf(';');
if (semicolon2 >= 0) {
rest = rest.substring(semicolon2);
} else {
rest = "";
}
req.requestURI().setString(uri.substring(0, semicolon) + rest);
}
} else {
request.setRequestedSessionId(null);
request.setRequestedSessionURL(false);
}
}
/**
* Parse cookies.
*/
protected void parseCookies(Request req, CoyoteRequest request) {
Cookies serverCookies = req.getCookies();
int count = serverCookies.getCookieCount();
if (count <= 0)
return;
Cookie[] cookies = new Cookie[count];
for (int i = 0; i < count; i++) {
ServerCookie scookie = serverCookies.getCookie(i);
if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) {
// Override anything requested in the URL
if (!request.isRequestedSessionIdFromCookie()) {
// Accept only the first session id cookie
request.setRequestedSessionId
(scookie.getValue().toString());
request.setRequestedSessionCookie(true);
request.setRequestedSessionURL(false);
if (debug >= 1)
log(" Requested cookie session id is " +
((HttpServletRequest) request.getRequest())
.getRequestedSessionId());
}
}
Cookie cookie = new Cookie(scookie.getName().toString(),
scookie.getValue().toString());
cookies[i] = cookie;
}
request.setCookies(cookies);
}
/**
* Return a context-relative path, beginning with a "/", that represents
* the canonical version of the specified path after ".." and "." elements
* are resolved out. If the specified path attempts to go outside the
* boundaries of the current context (i.e. too many ".." path elements
* are present), return <code>null</code> instead.
* This code is not optimized, and is only needed for Tomcat 4.0.x.
*
* @param path Path to be validated
*/
protected static String validate(String path) {
if (path == null)
return null;
// Create a place for the normalized path
String normalized = path;
// Normalize "/%7E" and "/%7e" at the beginning to "/~"
if (normalized.startsWith("/%7E") ||
normalized.startsWith("/%7e"))
normalized = "/~" + normalized.substring(4);
// Prevent encoding '%', '/', '.' and '\', which are special reserved
// characters
if ((normalized.indexOf("%25") >= 0)
|| (normalized.indexOf("%2F") >= 0)
|| (normalized.indexOf("%2E") >= 0)
|| (normalized.indexOf("%5C") >= 0)
|| (normalized.indexOf("%2f") >= 0)
|| (normalized.indexOf("%2e") >= 0)
|| (normalized.indexOf("%5c") >= 0)) {
return null;
}
if (normalized.equals("/."))
return "/";
// Normalize the slashes and add leading slash if necessary
if (normalized.indexOf('\\') >= 0)
normalized = normalized.replace('\\', '/');
if (!normalized.startsWith("/"))
normalized = "/" + normalized;
// Resolve occurrences of "//" in the normalized path
while (true) {
int index = normalized.indexOf("//");
if (index < 0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 1);
}
// Resolve occurrences of "/./" in the normalized path
while (true) {
int index = normalized.indexOf("/./");
if (index < 0)
break;
normalized = normalized.substring(0, index) +
normalized.substring(index + 2);
}
// Resolve occurrences of "/../" in the normalized path
while (true) {
int index = normalized.indexOf("/../");
if (index < 0)
break;
if (index == 0)
return (null); // Trying to go outside our context
int index2 = normalized.lastIndexOf('/', index - 1);
normalized = normalized.substring(0, index2) +
normalized.substring(index + 3);
}
// Declare occurrences of "/..." (three or more dots) to be invalid
// (on some Windows platforms this walks the directory tree!!!)
if (normalized.indexOf("/...") >= 0)
return (null);
// Return the normalized path that we have completed
return (normalized);
}
/**
* Normalize URI.
* <p>
* This method normalizes "\", "//", "/./" and "/../". This method will
* return false when trying to go above the root, or if the URI contains
* a null byte.
*
* @param uriMB URI to be normalized
*/
public static boolean normalize(MessageBytes uriMB) {
ByteChunk uriBC = uriMB.getByteChunk();
byte[] b = uriBC.getBytes();
int start = uriBC.getStart();
int end = uriBC.getEnd();
int pos = 0;
int index = 0;
// Replace '\' with '/'
// Check for null byte
for (pos = start; pos < end; pos++) {
if (b[pos] == (byte) '\\')
b[pos] = (byte) '/';
if (b[pos] == (byte) 0)
return false;
}
// Replace "//" with "/"
for (pos = start; pos < (end - 1); pos++) {
if ((b[pos] == (byte) '/') && (b[pos + 1] == (byte) '/')) {
copyBytes(b, pos, pos + 1, end - pos - 1);
end--;
}
}
// If the URI ends with "/." or "/..", then we append an extra "/"
// Note: It is possible to extend the URI by 1 without any side effect
// as the next character is a non-significant WS.
if (((end - start) > 2) && (b[end - 1] == (byte) '.')) {
if ((b[end - 2] == (byte) '/')
|| ((b[end - 2] == (byte) '.')
&& (b[end - 3] == (byte) '/'))) {
b[end] = (byte) '/';
end++;
}
}
uriBC.setEnd(end);
index = 0;
// Resolve occurrences of "/./" in the normalized path
while (true) {
index = uriBC.indexOf("/./", 0, 3, index);
if (index < 0)
break;
copyBytes(b, start + index, start + index + 2,
end - start - index - 2);
end = end - 2;
uriBC.setEnd(end);
}
index = 0;
// Resolve occurrences of "/../" in the normalized path
while (true) {
index = uriBC.indexOf("/../", 0, 4, index);
if (index < 0)
break;
// Prevent from going outside our context
if (index == 0)
return false;
int index2 = -1;
for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos --) {
if (b[pos] == (byte) '/') {
index2 = pos;
}
}
copyBytes(b, start + index2, start + index + 3,
end - start - index - 3);
end = end + index2 - index - 3;
uriBC.setEnd(end);
index = index2;
}
uriBC.setBytes(b, start, end);
return true;
}
// ------------------------------------------------------ Protected Methods
/**
* Copy an array of bytes to a different position. Used during
* normalization.
*/
protected static void copyBytes(byte[] b, int dest, int src, int len) {
for (int pos = 0; pos < len; pos++) {
b[pos + dest] = b[pos + src];
}
}
/**
* Log a message on the Logger associated with our Container (if any)
*
* @param message Message to be logged
*/
protected void log(String message) {
Logger logger = connector.getContainer().getLogger();
if (logger != null)
logger.log("CoyoteAdapter " + message);
}
/**
* Log a message on the Logger associated with our Container (if any)
*
* @param message Message to be logged
* @param throwable Associated exception
*/
protected void log(String message, Throwable throwable) {
Logger logger = connector.getContainer().getLogger();
if (logger != null)
logger.log("CoyoteAdapter " + message, throwable);
}
}
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteConnector.java
Index: CoyoteConnector.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteConnector.java,v 1.1 2002/08/04 19:39:49 patrickl Exp $
* $Revision: 1.1 $
* $Date: 2002/08/04 19:39:49 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.coyote.tomcat5;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.AccessControlException;
import java.util.Stack;
import java.util.Vector;
import java.util.Enumeration;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.UnrecoverableKeyException;
import java.security.KeyManagementException;
import org.apache.tomcat.util.IntrospectionUtils;
import org.apache.coyote.ActionCode;
import org.apache.coyote.ActionHook;
import org.apache.coyote.Adapter;
import org.apache.coyote.InputBuffer;
import org.apache.coyote.OutputBuffer;
import org.apache.coyote.ProtocolHandler;
import org.apache.catalina.Connector;
import org.apache.catalina.Container;
import org.apache.catalina.HttpRequest;
import org.apache.catalina.HttpResponse;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Logger;
import org.apache.catalina.Request;
import org.apache.catalina.Response;
import org.apache.catalina.Service;
import org.apache.catalina.net.DefaultServerSocketFactory;
import org.apache.catalina.net.ServerSocketFactory;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.catalina.util.StringManager;
/**
* Implementation of a Coyote connector for Tomcat 5.x.
*
* @author Craig R. McClanahan
* @author Remy Maucherat
* @version $Revision: 1.1 $ $Date: 2002/08/04 19:39:49 $
*/
public final class CoyoteConnector
implements Connector, Lifecycle {
// ----------------------------------------------------- Instance Variables
/**
* The <code>Service</code> we are associated with (if any).
*/
private Service service = null;
/**
* The accept count for this Connector.
*/
private int acceptCount = 10;
/**
* The IP address on which to bind, if any. If <code>null</code>, all
* addresses on the server will be bound.
*/
private String address = null;
/**
* The input buffer size we should create on input streams.
*/
private int bufferSize = 2048;
/**
* The Container used for processing requests received by this Connector.
*/
protected Container container = null;
/**
* The set of processors that have ever been created.
*/
private Vector created = new Vector();
/**
* The current number of processors that have been created.
*/
private int curProcessors = 0;
/**
* The debugging detail level for this component.
*/
private int debug = 0;
/**
* The "enable DNS lookups" flag for this Connector.
*/
private boolean enableLookups = false;
/**
* The server socket factory for this component.
*/
private ServerSocketFactory factory = null;
/**
* Descriptive information about this Connector implementation.
*/
private static final String info =
"org.apache.coyote.tomcat5.CoyoteConnector2/1.0";
/**
* The lifecycle event support for this component.
*/
protected LifecycleSupport lifecycle = new LifecycleSupport(this);
/**
* The minimum number of processors to start at initialization time.
*/
protected int minProcessors = 5;
/**
* The maximum number of processors allowed, or <0 for unlimited.
*/
private int maxProcessors = 20;
/**
* Timeout value on the incoming connection.
* Note : a value of 0 means no timeout.
*/
private int connectionTimeout = Constants.DEFAULT_CONNECTION_TIMEOUT;
/**
* The port number on which we listen for requests.
*/
private int port = 8080;
/**
* The server name to which we should pretend requests to this Connector
* were directed. This is useful when operating Tomcat behind a proxy
* server, so that redirects get constructed accurately. If not specified,
* the server name included in the <code>Host</code> header is used.
*/
private String proxyName = null;
/**
* The server port to which we should pretent requests to this Connector
* were directed. This is useful when operating Tomcat behind a proxy
* server, so that redirects get constructed accurately. If not specified,
* the port number specified by the <code>port</code> property is used.
*/
private int proxyPort = 0;
/**
* The redirect port for non-SSL to SSL redirects.
*/
private int redirectPort = 443;
/**
* The request scheme that will be set on all requests received
* through this connector.
*/
private String scheme = "http";
/**
* The secure connection flag that will be set on all requests received
* through this connector.
*/
private boolean secure = false;
/**
* The string manager for this package.
*/
private StringManager sm =
StringManager.getManager(Constants.Package);
/**
* Has this component been initialized yet?
*/
private boolean initialized = false;
/**
* Has this component been started yet?
*/
private boolean started = false;
/**
* The shutdown signal to our background thread
*/
private boolean stopped = false;
/**
* The background thread.
*/
private Thread thread = null;
/**
* Use TCP no delay ?
*/
private boolean tcpNoDelay = true;
/**
* Coyote Protocol handler class name.
* Defaults to the Coyote HTTP/1.1 protocolHandler.
*/
private String protocolHandlerClassName =
"org.apache.coyote.http11.Http11Protocol";
/**
* Use URI validation for Tomcat 5.0.x.
*/
private boolean useURIValidationHack = true;
/**
* Coyote protocol handler.
*/
private ProtocolHandler protocolHandler = null;
/**
* Coyote adapter.
*/
private Adapter adapter = null;
// ------------------------------------------------------------- Properties
/**
* Return the <code>Service</code> with which we are associated (if any).
*/
public Service getService() {
return (this.service);
}
/**
* Set the <code>Service</code> with which we are associated (if any).
*
* @param service The service that owns this Engine
*/
public void setService(Service service) {
this.service = service;
}
/**
* Return the connection timeout for this Connector.
*/
public int getConnectionTimeout() {
return (connectionTimeout);
}
/**
* Set the connection timeout for this Connector.
*
* @param count The new connection timeout
*/
public void setConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
/**
* Return the accept count for this Connector.
*/
public int getAcceptCount() {
return (acceptCount);
}
/**
* Set the accept count for this Connector.
*
* @param count The new accept count
*/
public void setAcceptCount(int count) {
this.acceptCount = count;
}
/**
* Return the bind IP address for this Connector.
*/
public String getAddress() {
return (this.address);
}
/**
* Set the bind IP address for this Connector.
*
* @param address The bind IP address
*/
public void setAddress(String address) {
this.address = address;
}
/**
* Is this connector available for processing requests?
*/
public boolean isAvailable() {
return (started);
}
/**
* Return the input buffer size for this Connector.
*/
public int getBufferSize() {
return (this.bufferSize);
}
/**
* Set the input buffer size for this Connector.
*
* @param bufferSize The new input buffer size.
*/
public void setBufferSize(int bufferSize) {
this.bufferSize = bufferSize;
}
/**
* Return the Container used for processing requests received by this
* Connector.
*/
public Container getContainer() {
return (container);
}
/**
* Set the Container used for processing requests received by this
* Connector.
*
* @param container The new Container to use
*/
public void setContainer(Container container) {
this.container = container;
}
/**
* Return the current number of processors that have been created.
*/
public int getCurProcessors() {
return (curProcessors);
}
/**
* Return the debugging detail level for this component.
*/
public int getDebug() {
return (debug);
}
/**
* Set the debugging detail level for this component.
*
* @param debug The new debugging detail level
*/
public void setDebug(int debug) {
this.debug = debug;
}
/**
* Return the "enable DNS lookups" flag.
*/
public boolean getEnableLookups() {
return (this.enableLookups);
}
/**
* Set the "enable DNS lookups" flag.
*
* @param enableLookups The new "enable DNS lookups" flag value
*/
public void setEnableLookups(boolean enableLookups) {
this.enableLookups = enableLookups;
}
/**
* Return the server socket factory used by this Container.
*/
public ServerSocketFactory getFactory() {
if (this.factory == null) {
synchronized (this) {
this.factory = new DefaultServerSocketFactory();
}
}
return (this.factory);
}
/**
* Set the server socket factory used by this Container.
*
* @param factory The new server socket factory
*/
public void setFactory(ServerSocketFactory factory) {
this.factory = factory;
}
/**
* Return descriptive information about this Connector implementation.
*/
public String getInfo() {
return (info);
}
/**
* Return the minimum number of processors to start at initialization.
*/
public int getMinProcessors() {
return (minProcessors);
}
/**
* Set the minimum number of processors to start at initialization.
*
* @param minProcessors The new minimum processors
*/
public void setMinProcessors(int minProcessors) {
this.minProcessors = minProcessors;
}
/**
* Return the maximum number of processors allowed, or <0 for unlimited.
*/
public int getMaxProcessors() {
return (maxProcessors);
}
/**
* Set the maximum number of processors allowed, or <0 for unlimited.
*
* @param maxProcessors The new maximum processors
*/
public void setMaxProcessors(int maxProcessors) {
this.maxProcessors = maxProcessors;
}
/**
* Return the port number on which we listen for requests.
*/
public int getPort() {
return (this.port);
}
/**
* Set the port number on which we listen for requests.
*
* @param port The new port number
*/
public void setPort(int port) {
this.port = port;
}
/**
* Return the class name of the Coyote protocol handler in use.
*/
public String getProtocolHandlerClassName() {
return (this.protocolHandlerClassName);
}
/**
* Set the class name of the Coyote protocol handler which will be used
* by the connector.
*
* @param protocolHandlerClassName The new class name
*/
public void setProtocolHandlerClassName(String protocolHandlerClassName) {
this.protocolHandlerClassName = protocolHandlerClassName;
}
/**
* Return the proxy server name for this Connector.
*/
public String getProxyName() {
return (this.proxyName);
}
/**
* Set the proxy server name for this Connector.
*
* @param proxyName The new proxy server name
*/
public void setProxyName(String proxyName) {
this.proxyName = proxyName;
}
/**
* Return the proxy server port for this Connector.
*/
public int getProxyPort() {
return (this.proxyPort);
}
/**
* Set the proxy server port for this Connector.
*
* @param proxyPort The new proxy server port
*/
public void setProxyPort(int proxyPort) {
this.proxyPort = proxyPort;
}
/**
* Return the port number to which a request should be redirected if
* it comes in on a non-SSL port and is subject to a security constraint
* with a transport guarantee that requires SSL.
*/
public int getRedirectPort() {
return (this.redirectPort);
}
/**
* Set the redirect port number.
*
* @param redirectPort The redirect port number (non-SSL to SSL)
*/
public void setRedirectPort(int redirectPort) {
this.redirectPort = redirectPort;
}
/**
* Return the scheme that will be assigned to requests received
* through this connector. Default value is "http".
*/
public String getScheme() {
return (this.scheme);
}
/**
* Set the scheme that will be assigned to requests received through
* this connector.
*
* @param scheme The new scheme
*/
public void setScheme(String scheme) {
this.scheme = scheme;
}
/**
* Return the secure connection flag that will be assigned to requests
* received through this connector. Default value is "false".
*/
public boolean getSecure() {
return (this.secure);
}
/**
* Set the secure connection flag that will be assigned to requests
* received through this connector.
*
* @param secure The new secure connection flag
*/
public void setSecure(boolean secure) {
this.secure = secure;
}
/**
* Return the TCP no delay flag value.
*/
public boolean getTcpNoDelay() {
return (this.tcpNoDelay);
}
/**
* Set the TCP no delay flag which will be set on the socket after
* accepting a connection.
*
* @param tcpNoDelay The new TCP no delay flag
*/
public void setTcpNoDelay(boolean tcpNoDelay) {
this.tcpNoDelay = tcpNoDelay;
}
/**
* Return the value of the Uri validation flag.
*/
public boolean getUseURIValidationHack() {
return (this.useURIValidationHack);
}
/**
* Set the value of the Uri validation flag.
*
* @param useURIValidationHack The new flag value
*/
public void setUseURIValidationHack(boolean useURIValidationHack) {
this.useURIValidationHack = useURIValidationHack;
}
// --------------------------------------------------------- Public Methods
/**
* Create (or allocate) and return a Request object suitable for
* specifying the contents of a Request to the responsible Container.
*/
public Request createRequest() {
CoyoteRequest request = new CoyoteRequest();
request.setConnector(this);
return (request);
}
/**
* Create (or allocate) and return a Response object suitable for
* receiving the contents of a Response from the responsible Container.
*/
public Response createResponse() {
CoyoteResponse response = new CoyoteResponse();
response.setConnector(this);
return (response);
}
// -------------------------------------------------------- Private Methods
/**
* Log a message on the Logger associated with our Container (if any).
*
* @param message Message to be logged
*/
private void log(String message) {
Logger logger = container.getLogger();
String localName = "CoyoteConnector";
if (logger != null)
logger.log(localName + " " + message);
else
System.out.println(localName + " " + message);
}
/**
* Log a message on the Logger associated with our Container (if any).
*
* @param message Message to be logged
* @param throwable Associated exception
*/
private void log(String message, Throwable throwable) {
Logger logger = container.getLogger();
String localName = "CoyoteConnector";
if (logger != null)
logger.log(localName + " " + message, throwable);
else {
System.out.println(localName + " " + message);
throwable.printStackTrace(System.out);
}
}
// ------------------------------------------------------ Lifecycle Methods
/**
* Add a lifecycle event listener to this component.
*
* @param listener The listener to add
*/
public void addLifecycleListener(LifecycleListener listener) {
lifecycle.addLifecycleListener(listener);
}
/**
* Get the lifecycle listeners associated with this lifecycle. If this
* Lifecycle has no listeners registered, a zero-length array is returned.
*/
public LifecycleListener[] findLifecycleListeners() {
return null;//lifecycle.findLifecycleListeners();
}
/**
* Remove a lifecycle event listener from this component.
*
* @param listener The listener to add
*/
public void removeLifecycleListener(LifecycleListener listener) {
lifecycle.removeLifecycleListener(listener);
}
/**
* Initialize this connector (create ServerSocket here!)
*/
public void initialize()
throws LifecycleException {
if (initialized)
throw new LifecycleException
(sm.getString("coyoteConnector.alreadyInitialized"));
this.initialized = true;
// Initializa adapter
adapter = new CoyoteAdapter(this);
// Instantiate protocol handler
try {
Class clazz = Class.forName(protocolHandlerClassName);
protocolHandler = (ProtocolHandler) clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new LifecycleException
(sm.getString
("coyoteConnector.protocolHandlerInstantiationFailed", e));
}
protocolHandler.setAdapter(adapter);
IntrospectionUtils.setProperty(protocolHandler, "jkHome",
System.getProperty("catalina.base"));
// Set attributes
IntrospectionUtils.setProperty(protocolHandler, "port", "" + port);
IntrospectionUtils.setProperty(protocolHandler, "maxThreads",
"" + maxProcessors);
IntrospectionUtils.setProperty(protocolHandler, "backlog",
"" + acceptCount);
IntrospectionUtils.setProperty(protocolHandler, "tcpNoDelay",
"" + tcpNoDelay);
IntrospectionUtils.setProperty(protocolHandler, "soTimeout",
"" + connectionTimeout);
IntrospectionUtils.setProperty(protocolHandler, "timeout",
"" + connectionTimeout);
if (address != null) {
IntrospectionUtils.setProperty(protocolHandler, "address",
address);
}
// Configure secure socket factory
if (factory instanceof CoyoteServerSocketFactory) {
IntrospectionUtils.setProperty(protocolHandler, "secure",
"" + true);
CoyoteServerSocketFactory ssf =
(CoyoteServerSocketFactory) factory;
IntrospectionUtils.setProperty(protocolHandler, "algorithm",
ssf.getAlgorithm());
if (ssf.getClientAuth()) {
IntrospectionUtils.setProperty(protocolHandler, "clientauth",
"" + ssf.getClientAuth());
}
IntrospectionUtils.setProperty(protocolHandler, "keystore",
ssf.getKeystoreFile());
IntrospectionUtils.setProperty(protocolHandler, "randomfile",
ssf.getRandomFile());
IntrospectionUtils.setProperty(protocolHandler, "rootfile",
ssf.getRootFile());
IntrospectionUtils.setProperty(protocolHandler, "keypass",
ssf.getKeystorePass());
IntrospectionUtils.setProperty(protocolHandler, "keytype",
ssf.getKeystoreType());
IntrospectionUtils.setProperty(protocolHandler, "protocol",
ssf.getProtocol());
IntrospectionUtils.setProperty(protocolHandler,
"sSLImplementation",
ssf.getSSLImplementation());
} else {
IntrospectionUtils.setProperty(protocolHandler, "secure",
"" + false);
}
try {
protocolHandler.init();
} catch (Exception e) {
throw new LifecycleException
(sm.getString
("coyoteConnector.protocolHandlerInitializationFailed", e));
}
}
/**
* Begin processing requests via this Connector.
*
* @exception LifecycleException if a fatal startup error occurs
*/
public void start() throws LifecycleException {
// Validate and update our current state
if (started)
throw new LifecycleException
(sm.getString("coyoteConnector.alreadyStarted"));
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
try {
protocolHandler.start();
} catch (Exception e) {
throw new LifecycleException
(sm.getString
("coyoteConnector.protocolHandlerStartFailed", e));
}
}
/**
* Terminate processing requests via this Connector.
*
* @exception LifecycleException if a fatal shutdown error occurs
*/
public void stop() throws LifecycleException {
// Validate and update our current state
if (!started)
throw new LifecycleException
(sm.getString("coyoteConnector.notStarted"));
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;
try {
protocolHandler.destroy();
} catch (Exception e) {
throw new LifecycleException
(sm.getString
("coyoteConnector.protocolHandlerDestroyFailed", e));
}
}
}
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteInputStream.java
Index: CoyoteInputStream.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.coyote.tomcat5;
import java.io.InputStream;
import java.io.IOException;
import javax.servlet.ServletInputStream;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.coyote.Request;
/**
* This class handles the readin input bytes, as well as the input buffering.
*
* @author Remy Maucherat
*/
public class CoyoteInputStream extends ServletInputStream {
// ----------------------------------------------------- Instance Variables
private boolean closed = false;
private Request coyoteRequest;
private ByteChunk readChunk = new ByteChunk();
/**
* Current read position in the byte buffer.
*/
private int pos = -1;
private int end = -1;
private byte[] readBuffer = null;
// --------------------------------------------------------- Public Methods
void setRequest(Request coyoteRequest) {
this.coyoteRequest = coyoteRequest;
}
/**
* Recycle the input stream.
*/
void recycle() {
closed = false;
pos = -1;
end = -1;
readBuffer = null;
}
// --------------------------------------------- ServletInputStream Methods
public int read()
throws IOException {
if (closed)
throw new IOException("Stream closed");
// Read additional bytes if none are available
while (pos >= end) {
if (readBytes() < 0)
return -1;
}
return (readBuffer[pos++] & 0xFF);
}
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
public int read(byte[] b, int off, int len)
throws IOException {
if (closed)
throw new IOException("Stream closed");
// Read additional bytes if none are available
while (pos >= end) {
if (readBytes() < 0)
return -1;
}
int n = -1;
if ((end - pos) > len) {
n = len;
} else {
n = end - pos;
}
System.arraycopy(readBuffer, pos, b, off, n);
pos += n;
return n;
}
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() {
closed = true;
}
// ------------------------------------------------------ Protected Methods
/**
* Read bytes to the read chunk buffer.
*/
protected int readBytes()
throws IOException {
int result = coyoteRequest.doRead(readChunk);
if (result > 0) {
readBuffer = readChunk.getBytes();
end = readChunk.getEnd();
pos = readChunk.getStart();
}
return result;
}
}
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteOutputStream.java
Index: CoyoteOutputStream.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.coyote.tomcat5;
import java.io.IOException;
import javax.servlet.ServletOutputStream;
import org.apache.coyote.Response;
/**
* Coyote implementation of the servlet output stream.
*
* @author Costin Manolache
* @author Remy Maucherat
*/
final class CoyoteOutputStream
extends ServletOutputStream {
// ----------------------------------------------------- Instance Variables
protected OutputBuffer ob;
// ----------------------------------------------------------- Constructors
protected CoyoteOutputStream(OutputBuffer ob) {
this.ob = ob;
}
// --------------------------------------------------- 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 {
if (ob.flushCharsNeeded())
ob.flushChars();
ob.flushBytes();
}
public void close()
throws IOException {
if (ob.flushCharsNeeded())
ob.flushChars();
ob.flushBytes();
}
// -------------------------------------------- ServletOutputStream Methods
public void print(String s)
throws IOException {
ob.write(s);
}
}
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteRequest.java
Index: CoyoteRequest.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteRequest.java,v 1.1 2002/08/04 19:39:49 patrickl Exp $
* $Revision: 1.1 $
* $Date: 2002/08/04 19:39:49 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.coyote.tomcat5;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.AccessController;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.tomcat.util.http.Parameters;
import org.apache.coyote.ActionCode;
import org.apache.coyote.Request;
import org.apache.catalina.Connector;
import org.apache.catalina.Context;
import org.apache.catalina.Globals;
import org.apache.catalina.HttpRequest;
import org.apache.catalina.Manager;
import org.apache.catalina.Realm;
import org.apache.catalina.Session;
import org.apache.catalina.Wrapper;
import org.apache.catalina.util.Enumerator;
import org.apache.catalina.util.ParameterMap;
import org.apache.catalina.util.RequestUtil;
import org.apache.catalina.util.StringManager;
import org.apache.catalina.util.StringParser;
import org.apache.tomcat.util.net.SSLSupport;
/**
* Wrapper object for the Coyote request.
*
* @author Remy Maucherat
* @author Craig R. McClanahan
* @version $Revision: 1.1 $ $Date: 2002/08/04 19:39:49 $
*/
public class CoyoteRequest
implements HttpRequest, HttpServletRequest {
// --------------------------------------- PrivilegedGetSession Inner Class
protected class PrivilegedGetSession
implements PrivilegedAction {
private boolean create;
PrivilegedGetSession(boolean create) {
this.create = create;
}
public Object run() {
return doGetSession(create);
}
}
// ------------------------------------------------------------- Properties
/**
* Coyote request.
*/
protected Request coyoteRequest;
/**
* Set the Coyote request.
*
* @param coyoteRequest The Coyote request
*/
public void setCoyoteRequest(Request coyoteRequest) {
this.coyoteRequest = coyoteRequest;
inputStream.setRequest(coyoteRequest);
}
/**
* Get the Coyote request.
*/
public Request getCoyoteRequest() {
return (this.coyoteRequest);
}
// ----------------------------------------------------- Instance Variables
/**
* The string manager for this package.
*/
protected static StringManager sm =
StringManager.getManager(Constants.Package);
/**
* The set of cookies associated with this Request.
*/
protected Cookie[] cookies = null;
/**
* The set of SimpleDateFormat formats to use in getDateHeader().
*/
protected SimpleDateFormat formats[] = {
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)
};
/**
* The default Locale if none are specified.
*/
protected static Locale defaultLocale = Locale.getDefault();
/**
* The attributes associated with this Request, keyed by attribute name.
*/
protected HashMap attributes = new HashMap();
/**
* The preferred Locales assocaited with this Request.
*/
protected ArrayList locales = new ArrayList();
/**
* Internal notes associated with this request by Catalina components
* and event listeners.
*/
private transient HashMap notes = new HashMap();
/**
* Authentication type.
*/
protected String authType = null;
/**
* Reader.
* Note: At the moment, no attempt is being made at recycling the reader,
* but this could be implemented in the future, using a design like the one
* used for the output buffer.
*/
protected BufferedReader reader = null;
/**
* ServletInputStream.
*/
protected CoyoteInputStream inputStream = new CoyoteInputStream();
/**
* Using stream flag.
*/
protected boolean usingInputStream = false;
/**
* Using writer flag.
*/
protected boolean usingReader = false;
/**
* Context path.
*/
protected String contextPath = "";
/**
* Path info.
*/
protected String pathInfo = null;
/**
* Servlet path.
*/
protected String servletPath = null;
/**
* User principal.
*/
protected Principal userPrincipal = null;
/**
* Session parsed flag.
*/
protected boolean sessionParsed = false;
/**
* Request parameters parsed flag.
*/
protected boolean requestParametersParsed = false;
/**
* Secure flag.
*/
protected boolean secure = false;
/**
* Post data buffer.
*/
protected static int CACHED_POST_LEN = 8192;
protected byte[] postData = null;
/**
* Hash map used in the getParametersMap method.
*/
protected ParameterMap parameterMap = new ParameterMap();
/**
* The currently active session for this request.
*/
protected Session session = 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;
/**
* The socket through which this Request was received.
*/
protected Socket socket = null;
/**
* Parse locales.
*/
protected boolean localesParsed = false;
/**
* The string parser we will use for parsing request lines.
*/
private StringParser parser = new StringParser();
/**
* Remote address.
*/
protected String remoteAddr = null;
/**
* Remote host.
*/
protected String remoteHost = null;
// --------------------------------------------------------- Public Methods
/**
* Release all object references, and initialize instance variables, in
* preparation for reuse of this object.
*/
public void recycle() {
context = null;
wrapper = null;
authorization = null;
authType = null;
usingInputStream = false;
usingReader = false;
contextPath = "";
pathInfo = null;
servletPath = null;
reader = null;
inputStream.recycle();
userPrincipal = null;
sessionParsed = false;
authorization = null;
requestParametersParsed = false;
locales.clear();
localesParsed = false;
secure = false;
remoteAddr = null;
remoteHost = null;
attributes.clear();
notes.clear();
cookies = null;
session = null;
requestedSessionCookie = false;
requestedSessionId = null;
requestedSessionURL = false;
parameterMap.setLocked(false);
parameterMap.clear();
if (facade != null) {
facade.clear();
facade = null;
}
}
// -------------------------------------------------------- Request Methods
/**
* The authorization credentials sent with this Request.
*/
protected String authorization = null;
/**
* Return the authorization credentials sent with this request.
*/
public String getAuthorization() {
return (this.authorization);
}
/**
* Set the authorization credentials sent with this request.
*
* @param authorization The new authorization credentials
*/
public void setAuthorization(String authorization) {
this.authorization = authorization;
}
/**
* Associated Catalina connector.
*/
protected Connector connector;
/**
* Return the Connector through which this Request was received.
*/
public Connector getConnector() {
return (this.connector);
}
/**
* Set the Connector through which this Request was received.
*
* @param connector The new connector
*/
public void setConnector(Connector connector) {
this.connector = connector;
}
/**
* The Context within which this Request is being processed.
*/
protected Context context = null;
/**
* Return the Context within which this Request is being processed.
*/
public Context getContext() {
return (this.context);
}
/**
* 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(Context context) {
this.context = context;
}
/**
* Descriptive information about this Request implementation.
*/
protected static final String info =
"org.apache.coyote.catalina.CoyoteRequest/1.0";
/**
* Return descriptive information about this Request implementation and
* the corresponding version number, in the format
* <code><description>/<version></code>.
*/
public String getInfo() {
return (info);
}
/**
* The facade associated with this request.
*/
protected CoyoteRequestFacade facade = null;
/**
* Return the <code>ServletRequest</code> for which this object
* is the facade. This method must be implemented by a subclass.
*/
public ServletRequest getRequest() {
if (facade == null) {
facade = new CoyoteRequestFacade(this);
}
return (facade);
}
/**
* The response with which this request is associated.
*/
protected org.apache.catalina.Response response = null;
/**
* Return the Response with which this Request is associated.
*/
public org.apache.catalina.Response getResponse() {
return (this.response);
}
/**
* Set the Response with which this Request is associated.
*
* @param response The new associated response
*/
public void setResponse(org.apache.catalina.Response response) {
this.response = response;
}
/**
* Return the Socket (if any) through which this Request was received.
* This should <strong>only</strong> be used to access underlying state
* information about this Socket, such as the SSLSession associated with
* an SSLSocket.
*/
public Socket getSocket() {
return (socket);
}
/**
* Set the Socket (if any) through which this Request was received.
*
* @param socket The socket through which this request was received
*/
public void setSocket(Socket socket) {
this.socket = socket;
remoteHost = null;
remoteAddr = null;
}
/**
* Return the input stream associated with this Request.
*/
public InputStream getStream() {
return inputStream;
}
/**
* Set the input stream associated with this Request.
*
* @param stream The new input stream
*/
public void setStream(InputStream stream) {
// Ignore
}
/**
* The Wrapper within which this Request is being processed.
*/
protected Wrapper wrapper = null;
/**
* Return the Wrapper within which this Request is being processed.
*/
public Wrapper getWrapper() {
return (this.wrapper);
}
/**
* 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(Wrapper wrapper) {
this.wrapper = wrapper;
}
// ------------------------------------------------- Request Public Methods
/**
* 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 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);
}
/**
* 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 protocol name and version associated with this Request.
*
* @param protocol Protocol name and version
*/
public void setProtocol(String protocol) {
// 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 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) {
coyoteRequest.serverName().setString(name);
}
/**
* Set the port number of the server to process this request.
*
* @param port The server port
*/
public void setServerPort(int port) {
coyoteRequest.setServerPort(port);
}
// ------------------------------------------------- ServletRequest Methods
/**
* 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) {
Object attr=attributes.get(name);
if(attr!=null)
return(attr);
return coyoteRequest.getAttribute(name);
}
/**
* Return the names of all request attributes for this Request, or an
* empty <code>Enumeration</code> if there are none.
*/
public Enumeration getAttributeNames() {
return (new Enumerator(attributes.keySet()));
}
/**
* Return the character encoding for this Request.
*/
public String getCharacterEncoding() {
return (coyoteRequest.getCharacterEncoding());
}
/**
* Return the content length for this Request.
*/
public int getContentLength() {
return (coyoteRequest.getContentLength());
}
/**
* Return the content type for this Request.
*/
public String getContentType() {
return (coyoteRequest.getContentType());
}
/**
* 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
(sm.getString("coyoteRequest.getInputStream.ise"));
usingInputStream = true;
return inputStream;
}
/**
* 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));
}
/**
* 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 (!requestParametersParsed)
parseRequestParameters();
return coyoteRequest.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 enum = getParameterNames();
while (enum.hasMoreElements()) {
String name = enum.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 (!requestParametersParsed)
parseRequestParameters();
return coyoteRequest.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 (!requestParametersParsed)
parseRequestParameters();
return coyoteRequest.getParameters().getParameterValues(name);
}
/**
* Return the protocol and version used to make this Request.
*/
public String getProtocol() {
return coyoteRequest.protocol().toString();
}
/**
* 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
(sm.getString("coyoteRequest.getReader.ise"));
usingReader = true;
if (reader == null) {
String encoding = getCharacterEncoding();
if (encoding == null) {
encoding =
org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
}
InputStreamReader r = new InputStreamReader(inputStream, encoding);
reader = new BufferedReader(r);
}
return (reader);
}
/**
* 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 (remoteAddr == null) {
if (socket != null) {
InetAddress inet = socket.getInetAddress();
remoteAddr = inet.getHostAddress();
} else {
remoteAddr = coyoteRequest.remoteAddr().toString();
}
}
return remoteAddr;
}
/**
* Return the remote host name making this Request.
*/
public String getRemoteHost() {
if (remoteHost == null) {
if (!connector.getEnableLookups()) {
remoteHost = getRemoteAddr();
} else if (socket != null) {
InetAddress inet = socket.getInetAddress();
remoteHost = inet.getHostName();
} else {
coyoteRequest.action
(ActionCode.ACTION_REQ_HOST_ATTRIBUTE, coyoteRequest);
remoteHost = coyoteRequest.remoteHost().toString();
}
}
return remoteHost;
}
/**
* 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(Globals.SERVLET_PATH_ATTR);
if (servletPath == null)
servletPath = getServletPath();
int pos = servletPath.lastIndexOf('/');
String relative = null;
if (pos >= 0) {
relative = RequestUtil.normalize
(servletPath.substring(0, pos + 1) + path);
} else {
relative = RequestUtil.normalize(servletPath + path);
}
return (context.getServletContext().getRequestDispatcher(relative));
}
/**
* Return the scheme used to make this Request.
*/
public String getScheme() {
return (coyoteRequest.scheme().toString());
}
/**
* Return the server name responding to this Request.
*/
public String getServerName() {
return (coyoteRequest.serverName().toString());
}
/**
* Return the server port responding to this Request.
*/
public int getServerPort() {
return (coyoteRequest.getServerPort());
}
/**
* Was this request received on a secure connection?
*/
public boolean isSecure() {
return (secure);
}
/**
* Remove the specified request attribute if it exists.
*
* @param name Name of the request attribute to remove
*/
public void removeAttribute(String name) {
attributes.remove(name);
}
/**
* 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
(sm.getString("coyoteRequest.setAttribute.namenull"));
// Null value is the same as removeAttribute()
if (value == null) {
removeAttribute(name);
return;
}
attributes.put(name, value);
}
/**
* 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
coyoteRequest.setCharacterEncoding(enc);
}
// ---------------------------------------------------- HttpRequest Methods
/**
* Add a Cookie to the set of Cookies associated with this Request.
*
* @param cookie The new cookie
*/
public void addCookie(Cookie cookie) {
// For compatibility only
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
}
/**
* 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[]) {
// Not used
}
/**
* Clear the collection of Cookies associated with this Request.
*/
public void clearCookies() {
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
}
/**
* 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;
}
/**
* 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) {
this.contextPath = "";
} else {
this.contextPath = path;
}
}
/**
* Set the HTTP request method used for this Request.
*
* @param method The request method
*/
public void setMethod(String method) {
// 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 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) {
this.pathInfo = path;
}
/**
* 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 unparsed request URI for this Request. This will normally be
* called by the HTTP Connector, when it parses the request headers.
*
* @param uri The request URI
*/
public void setRequestURI(String uri) {
// Not used
}
/**
* Set the decoded request URI.
*
* @param uri The decoded request URI
*/
public void setDecodedRequestURI(String uri) {
// Not used
}
/**
* Get the decoded request URI.
*
* @return the URL decoded request URI
*/
public String getDecodedRequestURI() {
return (coyoteRequest.decodedURI().toString());
}
/**
* 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) {
this.servletPath = path;
}
/**
* 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) {
this.userPrincipal = principal;
}
// --------------------------------------------- HttpServletRequest Methods
/**
* Return the authentication type used for this Request.
*/
public String getAuthType() {
return (authType);
}
/**
* Return the portion of the request URI used to select the Context
* of the Request.
*/
public String getContextPath() {
return (contextPath);
}
/**
* Return the set of Cookies received with this Request.
*/
public Cookie[] getCookies() {
return cookies;
}
/**
* Set the set of cookies recieved with this Request.
*/
public void setCookies(Cookie[] cookies) {
this.cookies = 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);
// Work around a bug in SimpleDateFormat in pre-JDK1.2b4
// (Bug Parade bug #4106807)
value += " ";
// Attempt to convert the date header in a variety of formats
for (int i = 0; i < formats.length; i++) {
try {
Date date = formats[i].parse(value);
return (date.getTime());
} catch (ParseException e) {
;
}
}
throw new IllegalArgumentException(value);
}
/**
* 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 coyoteRequest.getHeader(name);
}
/**
* 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 coyoteRequest.getMimeHeaders().values(name);
}
/**
* Return the names of all headers received with this request.
*/
public Enumeration getHeaderNames() {
return coyoteRequest.getMimeHeaders().names();
}
/**
* 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));
}
}
/**
* Return the HTTP request method used in this Request.
*/
public String getMethod() {
return coyoteRequest.method().toString();
}
/**
* Return the path information associated with this Request.
*/
public String getPathInfo() {
return (pathInfo);
}
/**
* Return the extra path information for this request, translated
* to a real path.
*/
public String getPathTranslated() {
if (context == null)
return (null);
if (pathInfo == null) {
return (null);
} else {
return (context.getServletContext().getRealPath(pathInfo));
}
}
/**
* Return the query string associated with this request.
*/
public String getQueryString() {
String queryString = coyoteRequest.queryString().toString();
if (queryString.equals("")) {
return (null);
} else {
return queryString;
}
}
/**
* 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 session identifier included in this request, if any.
*/
public String getRequestedSessionId() {
return (requestedSessionId);
}
/**
* Return the request URI for this request.
*/
public String getRequestURI() {
return coyoteRequest.requestURI().toString();
}
/**
* 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 portion of the request URI used to select the servlet
* that will process this request.
*/
public String getServletPath() {
return (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 (System.getSecurityManager() != null) {
PrivilegedGetSession dp = new PrivilegedGetSession(create);
return (HttpSession) AccessController.doPrivileged(dp);
}
return doGetSession(create);
}
/**
* 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.
*/
public boolean isRequestedSessionIdFromURL() {
if (requestedSessionId != null)
return (requestedSessionURL);
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 identifies a valid session.
*/
public boolean isRequestedSessionIdValid() {
if (requestedSessionId == null)
return (false);
if (context == null)
return (false);
Manager manager = context.getManager();
if (manager == null)
return (false);
Session session = null;
try {
session = manager.findSession(requestedSessionId);
} catch (IOException e) {
session = null;
}
if ((session != null) && session.isValid())
return (true);
else
return (false);
}
/**
* 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?
if (userPrincipal == null)
return (false);
// Identify the Realm we will use for checking role assignmenets
if (context == null)
return (false);
Realm realm = context.getRealm();
if (realm == null)
return (false);
// Check for a role alias defined in a <security-role-ref> element
if (wrapper != null) {
String realRole = wrapper.findSecurityReference(role);
if ((realRole != null) &&
realm.hasRole(userPrincipal, realRole))
return (true);
}
// Check for a role defined directly as a <security-role>
return (realm.hasRole(userPrincipal, role));
}
/**
* Return the principal that has been authenticated for this Request.
*/
public Principal getUserPrincipal() {
return (userPrincipal);
}
// ------------------------------------------------------ Protected Methods
protected HttpSession doGetSession(boolean create) {
// There cannot be a session if no context has been assigned yet
if (context == null)
return (null);
// Return the current session if it exists and is valid
if ((session != null) && !session.isValid())
session = null;
if (session != null)
return (session.getSession());
// Return the requested session if it exists and is valid
Manager manager = null;
if (context != null)
manager = context.getManager();
if (manager == null)
return (null); // Sessions are not supported
if (requestedSessionId != null) {
try {
session = manager.findSession(requestedSessionId);
} catch (IOException e) {
session = null;
}
if ((session != null) && !session.isValid())
session = null;
if (session != null) {
return (session.getSession());
}
}
// Create a new session if requested and the response is not committed
if (!create)
return (null);
if ((context != null) && (response != null) &&
context.getCookies() &&
response.getResponse().isCommitted()) {
throw new IllegalStateException
(sm.getString("coyoteRequest.sessionCreateCommitted"));
}
session = manager.createSession();
// Creating a new session cookie based on that session
if ((session != null) && (getContext() != null)
&& getContext().getCookies()) {
Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
session.getId());
cookie.setMaxAge(-1);
String contextPath = null;
if (context != null)
contextPath = context.getPath();
if ((contextPath != null) && (contextPath.length() > 0))
cookie.setPath(contextPath);
else
cookie.setPath("/");
if (isSecure())
cookie.setSecure(true);
((HttpServletResponse) response).addCookie(cookie);
}
if (session != null)
return (session.getSession());
else
return (null);
}
/**
* Parse request parameters.
*/
protected void parseRequestParameters() {
requestParametersParsed = true;
Parameters parameters = coyoteRequest.getParameters();
String enc = coyoteRequest.getCharacterEncoding();
if (enc != null) {
parameters.setEncoding(enc);
} else {
parameters.setEncoding
(org.apache.coyote.Constants.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) {
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];
}
readPostBody(formData, len);
parameters.processParameters(formData, 0, len);
} catch (Throwable t) {
; // Ignore
}
}
}
/**
* 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;
}
/**
* 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) {
// Store the accumulated languages that have been requested in
// a local collection, sorted by the quality value (so we can
// add Locales in descending order). The values will be ArrayLists
// containing the corresponding Locales to be added
TreeMap locales = new TreeMap();
// Preprocess the value to remove all whitespace
int white = value.indexOf(' ');
if (white < 0)
white = value.indexOf('\t');
if (white >= 0) {
StringBuffer sb = new StringBuffer();
int len = value.length();
for (int i = 0; i < len; i++) {
char ch = value.charAt(i);
if ((ch != ' ') && (ch != '\t'))
sb.append(ch);
}
value = sb.toString();
}
// Process each comma-delimited language specification
parser.setString(value); // ASSERT: parser is available to us
int length = parser.getLength();
while (true) {
// Extract the next comma-delimited entry
int start = parser.getIndex();
if (start >= length)
break;
int end = parser.findChar(',');
String entry = parser.extract(start, end).trim();
parser.advance(); // For the following entry
// Extract the quality factor for this entry
double quality = 1.0;
int semi = entry.indexOf(";q=");
if (semi >= 0) {
try {
quality = Double.parseDouble(entry.substring(semi + 3));
} catch (NumberFormatException e) {
quality = 0.0;
}
entry = entry.substring(0, semi);
}
// Skip entries we are not going to keep track of
if (quality < 0.00005)
continue; // Zero (or effectively zero) quality factors
if ("*".equals(entry))
continue; // FIXME - "*" entries are not handled
// Extract the language and country for this entry
String language = null;
String country = null;
String variant = null;
int dash = entry.indexOf('-');
if (dash < 0) {
language = entry;
country = "";
variant = "";
} else {
language = entry.substring(0, dash);
country = entry.substring(dash + 1);
int vDash = country.indexOf('-');
if (vDash > 0) {
String cTemp = country.substring(0, vDash);
variant = country.substring(vDash + 1);
country = cTemp;
} else {
variant = "";
}
}
// Add a new Locale to the list of Locales for this quality level
Locale locale = new Locale(language, country, variant);
Double key = new Double(-quality); // Reverse the order
ArrayList values = (ArrayList) locales.get(key);
if (values == null) {
values = new ArrayList();
locales.put(key, values);
}
values.add(locale);
}
// 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);
}
}
}
}
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteRequestFacade.java
Index: CoyoteRequestFacade.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteRequestFacade.java,v 1.1 2002/08/04 19:39:49 patrickl Exp $
* $Revision: 1.1 $
* $Date: 2002/08/04 19:39:49 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.coyote.tomcat5;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Locale;
import java.net.Socket;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.catalina.connector.RequestFacade;
import org.apache.catalina.session.StandardSessionFacade;
/**
* Facade class that wraps a Coyote request object.
* All methods are delegated to the wrapped request.
*
* @author Craig R. McClanahan
* @author Remy Maucherat
* @version $Revision: 1.1 $ $Date: 2002/08/04 19:39:49 $
*/
public class CoyoteRequestFacade
extends RequestFacade
implements HttpServletRequest {
// ----------------------------------------------------------- Constructors
/**
* Construct a wrapper for the specified request.
*
* @param request The request to be wrapped
*/
public CoyoteRequestFacade(CoyoteRequest request) {
super(request);
this.request = request;
}
// ----------------------------------------------------- Instance Variables
/**
* The wrapped request.
*/
protected CoyoteRequest request = null;
// --------------------------------------------------------- Public Methods
/**
* Clear facade.
*/
public void clear() {
request = null;
}
// ------------------------------------------------- ServletRequest Methods
public Object getAttribute(String name) {
return request.getAttribute(name);
}
public Enumeration getAttributeNames() {
return request.getAttributeNames();
}
public String getCharacterEncoding() {
return request.getCharacterEncoding();
}
public void setCharacterEncoding(String env)
throws java.io.UnsupportedEncodingException {
request.setCharacterEncoding(env);
}
public int getContentLength() {
return request.getContentLength();
}
public String getContentType() {
return request.getContentType();
}
public ServletInputStream getInputStream()
throws IOException {
return request.getInputStream();
}
public String getParameter(String name) {
return request.getParameter(name);
}
public Enumeration getParameterNames() {
return request.getParameterNames();
}
public String[] getParameterValues(String name) {
return request.getParameterValues(name);
}
public Map getParameterMap() {
return request.getParameterMap();
}
public String getProtocol() {
return request.getProtocol();
}
public String getScheme() {
return request.getScheme();
}
public String getServerName() {
return request.getServerName();
}
public int getServerPort() {
return request.getServerPort();
}
public BufferedReader getReader()
throws IOException {
return request.getReader();
}
public String getRemoteAddr() {
return request.getRemoteAddr();
}
public String getRemoteHost() {
return request.getRemoteHost();
}
public void setAttribute(String name, Object o) {
request.setAttribute(name, o);
}
public void removeAttribute(String name) {
request.removeAttribute(name);
}
public Locale getLocale() {
return request.getLocale();
}
public Enumeration getLocales() {
return request.getLocales();
}
public boolean isSecure() {
return request.isSecure();
}
public RequestDispatcher getRequestDispatcher(String path) {
// TODO : Facade !!
return request.getRequestDispatcher(path);
}
public String getRealPath(String path) {
return request.getRealPath(path);
}
public String getAuthType() {
return request.getAuthType();
}
public Cookie[] getCookies() {
return request.getCookies();
}
public long getDateHeader(String name) {
return request.getDateHeader(name);
}
public String getHeader(String name) {
return request.getHeader(name);
}
public Enumeration getHeaders(String name) {
return request.getHeaders(name);
}
public Enumeration getHeaderNames() {
return request.getHeaderNames();
}
public int getIntHeader(String name) {
return request.getIntHeader(name);
}
public String getMethod() {
return request.getMethod();
}
public String getPathInfo() {
return request.getPathInfo();
}
public String getPathTranslated() {
return request.getPathTranslated();
}
public String getContextPath() {
return request.getContextPath();
}
public String getQueryString() {
return request.getQueryString();
}
public String getRemoteUser() {
return request.getRemoteUser();
}
public boolean isUserInRole(String role) {
return request.isUserInRole(role);
}
public java.security.Principal getUserPrincipal() {
return request.getUserPrincipal();
}
public String getRequestedSessionId() {
return request.getRequestedSessionId();
}
public String getRequestURI() {
return request.getRequestURI();
}
public StringBuffer getRequestURL() {
return request.getRequestURL();
}
public String getServletPath() {
return request.getServletPath();
}
public HttpSession getSession(boolean create) {
HttpSession session =
request.getSession(create);
if (session == null)
return null;
else
return new StandardSessionFacade(session);
}
public HttpSession getSession() {
return getSession(true);
}
public boolean isRequestedSessionIdValid() {
return request.isRequestedSessionIdValid();
}
public boolean isRequestedSessionIdFromCookie() {
return request.isRequestedSessionIdFromCookie();
}
public boolean isRequestedSessionIdFromURL() {
return request.isRequestedSessionIdFromURL();
}
public boolean isRequestedSessionIdFromUrl() {
return request.isRequestedSessionIdFromURL();
}
}
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteResponse.java
Index: CoyoteResponse.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteResponse.java,v 1.1 2002/08/04 19:39:49 patrickl Exp $
* $Revision: 1.1 $
* $Date: 2002/08/04 19:39:49 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.coyote.tomcat5;
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.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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.HttpUtils;
import org.apache.tomcat.util.buf.CharChunk;
import org.apache.tomcat.util.buf.UEncoder;
import org.apache.tomcat.util.http.MimeHeaders;
import org.apache.tomcat.util.http.ServerCookie;
import org.apache.coyote.Response;
import org.apache.catalina.Connector;
import org.apache.catalina.Context;
import org.apache.catalina.Globals;
import org.apache.catalina.HttpResponse;
import org.apache.catalina.Manager;
import org.apache.catalina.Realm;
import org.apache.catalina.Session;
import org.apache.catalina.Wrapper;
import org.apache.catalina.util.CharsetMapper;
import org.apache.catalina.util.RequestUtil;
import org.apache.catalina.util.StringManager;
/**
* Wrapper object for the Coyote response.
*
* @author Remy Maucherat
* @author Craig R. McClanahan
* @version $Revision: 1.1 $ $Date: 2002/08/04 19:39:49 $
*/
public class CoyoteResponse
implements HttpResponse, HttpServletResponse {
// ----------------------------------------------------------- Constructors
public CoyoteResponse() {
format.setTimeZone(TimeZone.getTimeZone("GMT"));
urlEncoder.addSafeCharacter('/');
}
// ----------------------------------------------------- Instance Variables
/**
* The date format we will use for creating date headers.
*/
protected final SimpleDateFormat format =
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
/**
* Descriptive information about this Response implementation.
*/
protected static final String info =
"org.apache.coyote.tomcat5.CoyoteResponse/1.0";
/**
* The string manager for this package.
*/
protected static StringManager sm =
StringManager.getManager(Constants.Package);
// ------------------------------------------------------------- Properties
/**
* Associated Catalina connector.
*/
protected Connector connector;
/**
* Return the Connector through which this Request was received.
*/
public Connector getConnector() {
return (this.connector);
}
/**
* Set the Connector through which this Request was received.
*
* @param connector The new connector
*/
public void setConnector(Connector connector) {
this.connector = connector;
}
/**
* Coyote response.
*/
protected Response coyoteResponse;
/**
* Set the Coyote response.
*
* @param response The Coyote response
*/
public void setCoyoteResponse(Response coyoteResponse) {
this.coyoteResponse = coyoteResponse;
outputBuffer.setResponse(coyoteResponse);
}
/**
* Get the Coyote response.
*/
public Response getCoyoteResponse() {
return (coyoteResponse);
}
/**
* The Context within which this Request is being processed.
*/
protected Context context = null;
/**
* Return the Context within which this Request is being processed.
*/
public Context getContext() {
return (this.context);
}
/**
* 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(Context context) {
this.context = context;
}
/**
* The associated output buffer.
*/
protected OutputBuffer outputBuffer = new OutputBuffer();
/**
* The associated output stream.
*/
protected CoyoteOutputStream outputStream =
new CoyoteOutputStream(outputBuffer);
/**
* The associated writer.
*/
protected CoyoteWriter writer = new CoyoteWriter(outputBuffer);
/**
* The application commit flag.
*/
protected boolean appCommitted = false;
/**
* The included flag.
*/
protected boolean included = 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;
/**
* URL encoder.
*/
protected UEncoder urlEncoder = new UEncoder();
/**
* Recyclable buffer to hold the redirect URL.
*/
protected CharChunk redirectURLCC = new CharChunk();
// --------------------------------------------------------- Public Methods
/**
* Release all object references, and initialize instance variables, in
* preparation for reuse of this object.
*/
public void recycle() {
outputBuffer.recycle();
usingOutputStream = false;
usingWriter = false;
appCommitted = false;
included = false;
error = false;
cookies.clear();
if (facade != null) {
facade.clear();
facade = null;
}
}
// ------------------------------------------------------- Response Methods
/**
* Return the number of bytes actually written to the output stream.
*/
public int getContentCount() {
return outputBuffer.getBytesWritten();
}
/**
* 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());
}
/**
* 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 descriptive information about this Response implementation and
* the corresponding version number, in the format
* <code><description>/<version></code>.
*/
public String getInfo() {
return (info);
}
/**
* The request with which this response is associated.
*/
protected CoyoteRequest request = null;
/**
* Return the Request with which this Response is associated.
*/
public org.apache.catalina.Request getRequest() {
return (this.request);
}
/**
* Set the Request with which this Response is associated.
*
* @param request The new associated request
*/
public void setRequest(org.apache.catalina.Request request) {
this.request = (CoyoteRequest) request;
}
/**
* The facade associated with this response.
*/
protected CoyoteResponseFacade facade = null;
/**
* Return the <code>ServletResponse</code> for which this object
* is the facade.
*/
public ServletResponse getResponse() {
if (facade == null) {
facade = new CoyoteResponseFacade(this);
}
return (facade);
}
/**
* 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) {
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;
}
/**
* Perform whatever actions are required to flush and close the output
* stream or writer, in a single operation.
*
* @exception IOException if an input/output error occurs
*/
public void finishResponse()
throws IOException {
// Writing leftover bytes
try {
outputBuffer.close();
} catch(IOException e) {
;
} catch(Throwable t) {
t.printStackTrace();
}
coyoteResponse.finish();
}
/**
* Return the content length that was set or calculated for this Response.
*/
public int getContentLength() {
return (coyoteResponse.getContentLength());
}
/**
* 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() {
return (coyoteResponse.getContentType());
}
/**
* 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.
*/
public PrintWriter getReporter() {
if (outputBuffer.isNew()) {
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 (coyoteResponse.getCharacterEncoding());
}
/**
* 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
(sm.getString("coyoteResponse.getOutputStream.ise"));
usingOutputStream = true;
return outputStream;
}
/**
* Return the Locale assigned to this response.
*/
public Locale getLocale() {
return (coyoteResponse.getLocale());
}
/**
* 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
(sm.getString("coyoteResponse.getWriter.ise"));
usingWriter = true;
return writer;
}
/**
* Has the output of this response already been committed?
*/
public boolean isCommitted() {
return (coyoteResponse.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
coyoteResponse.reset();
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
(sm.getString("coyoteResponse.resetBuffer.ise"));
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
(sm.getString("coyoteResponse.setBufferSize.ise"));
outputBuffer.setBufferSize(size);
}
/**
* Set the content length (in bytes) for this Response.
*
* @param length The new content length
*/
public void setContentLength(int length) {
if (isCommitted())
return;
// Ignore any call from an included servlet
if (included)
return;
coyoteResponse.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;
coyoteResponse.setContentType(type);
}
/*
* 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;
if (included)
return; // Ignore any call from an included servlet
coyoteResponse.setCharacterEncoding(charset);
}
/**
* 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;
coyoteResponse.setLocale(locale);
}
// --------------------------------------------------- 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 coyoteResponse.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 String[] getHeaderNames() {
MimeHeaders headers = coyoteResponse.getMimeHeaders();
int n = headers.size();
String[] result = new String[n];
for (int i = 0; i < n; i++) {
result[i] = 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) {
MimeHeaders headers = coyoteResponse.getMimeHeaders();
int n = headers.size();
String[] result = new String[n];
for (int i = 0; i < n; i++) {
result[i] = headers.getValue(i).toString();
}
return result;
}
/**
* Return the error message that was set with <code>sendError()</code>
* for this Response.
*/
public String getMessage() {
return coyoteResponse.getMessage();
}
/**
* Return the HTTP status code associated with this Response.
*/
public int getStatus() {
return coyoteResponse.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(Cookie cookie) {
if (isCommitted())
return;
// Ignore any call from an included servlet
if (included)
return;
cookies.add(cookie);
StringBuffer sb = new StringBuffer();
ServerCookie.appendCookieValue
(sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
cookie.getPath(), cookie.getDomain(), cookie.getComment(),
cookie.getMaxAge(), cookie.getSecure());
// 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;
addHeader(name, format.format(new Date(value)));
}
/**
* 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;
coyoteResponse.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) {
return coyoteResponse.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))) {
HttpServletRequest hreq =
(HttpServletRequest) request.getRequest();
return (toEncoded(url, hreq.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) {
if (isEncodeable(toAbsolute(url))) {
HttpServletRequest hreq =
(HttpServletRequest) request.getRequest();
return (toEncoded(url, hreq.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;
coyoteResponse.acknowledge();
}
/**
* 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
(sm.getString("coyoteResponse.sendError.ise"));
// Ignore any call from an included servlet
if (included)
return;
setError();
coyoteResponse.setStatus(status);
coyoteResponse.setMessage(message);
// Clear any data content that has been buffered
resetBuffer();
// Cause the response to be finished (from the application perspective)
setSuspended(true);
}
/**
* 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
(sm.getString("coyoteResponse.sendRedirect.ise"));
// 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_MOVED_TEMPORARILY);
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;
setHeader(name, format.format(new Date(value)));
}
/**
* 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;
coyoteResponse.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;
coyoteResponse.setStatus(status);
coyoteResponse.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(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?
HttpServletRequest hreq = (HttpServletRequest) request.getRequest();
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 = getContext().getPath();
if ((contextPath != null) && (contextPath.length() > 0)) {
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
|| (!leadingSlash && (location.indexOf("://") == -1))) {
redirectURLCC.recycle();
String scheme = request.getScheme();
String name = request.getServerName();
int port = request.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 = request.getDecodedRequestURI();
int pos = relativePath.lastIndexOf('/');
relativePath = relativePath.substring(0, pos);
String encodedURI = urlEncoder.encodeURL(relativePath);
redirectURLCC.append(encodedURI, 0, encodedURI.length());
redirectURLCC.append('/');
}
redirectURLCC.append(location, 0, location.length());
} catch (IOException e) {
throw new IllegalArgumentException(location);
}
return redirectURLCC.toString();
} else {
return (location);
}
}
/**
* 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
*/
private 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());
}
}
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteResponseFacade.java
Index: CoyoteResponseFacade.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteResponseFacade.java,v 1.1 2002/08/04 19:39:49 patrickl Exp $
* $Revision: 1.1 $
* $Date: 2002/08/04 19:39:49 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.coyote.tomcat5;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Locale;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.connector.ResponseFacade;
/**
* Facade class that wraps a Coyote response object.
* All methods are delegated to the wrapped response.
*
* @author Remy Maucherat
* @version $Revision: 1.1 $ $Date: 2002/08/04 19:39:49 $
*/
public class CoyoteResponseFacade
extends ResponseFacade
implements HttpServletResponse {
// ----------------------------------------------------------- Constructors
/**
* Construct a wrapper for the specified response.
*
* @param response The response to be wrapped
*/
public CoyoteResponseFacade(CoyoteResponse response) {
super(response);
this.response = response;
}
// ----------------------------------------------------- Instance Variables
/**
* The wrapped response.
*/
protected CoyoteResponse response = null;
// --------------------------------------------------------- Public Methods
/**
* Clear facade.
*/
public void clear() {
response = null;
}
public void finish() {
response.setSuspended(true);
}
public boolean isFinished() {
return response.isSuspended();
}
// ------------------------------------------------ ServletResponse Methods
public String getCharacterEncoding() {
return response.getCharacterEncoding();
}
public ServletOutputStream getOutputStream()
throws IOException {
// if (isFinished())
// throw new IllegalStateException
// (/*sm.getString("responseFacade.finished")*/);
ServletOutputStream sos = response.getOutputStream();
if (isFinished())
response.setSuspended(true);
return (sos);
}
public PrintWriter getWriter()
throws IOException {
// if (isFinished())
// throw new IllegalStateException
// (/*sm.getString("responseFacade.finished")*/);
PrintWriter writer = response.getWriter();
if (isFinished())
response.setSuspended(true);
return (writer);
}
public void setContentLength(int len) {
if (isCommitted())
return;
response.setContentLength(len);
}
public void setContentType(String type) {
if (isCommitted())
return;
response.setContentType(type);
}
public void setBufferSize(int size) {
if (isCommitted())
throw new IllegalStateException
(/*sm.getString("responseBase.reset.ise")*/);
response.setBufferSize(size);
}
public int getBufferSize() {
return response.getBufferSize();
}
public void flushBuffer()
throws IOException {
if (isFinished())
// throw new IllegalStateException
// (/*sm.getString("responseFacade.finished")*/);
return;
response.setAppCommitted(true);
response.flushBuffer();
}
public void resetBuffer() {
if (isCommitted())
throw new IllegalStateException
(/*sm.getString("responseBase.reset.ise")*/);
response.resetBuffer();
}
public boolean isCommitted() {
return (response.isAppCommitted());
}
public void reset() {
if (isCommitted())
throw new IllegalStateException
(/*sm.getString("responseBase.reset.ise")*/);
response.reset();
}
public void setLocale(Locale loc) {
if (isCommitted())
return;
response.setLocale(loc);
}
public Locale getLocale() {
return response.getLocale();
}
public void addCookie(Cookie cookie) {
if (isCommitted())
return;
response.addCookie(cookie);
}
public boolean containsHeader(String name) {
return response.containsHeader(name);
}
public String encodeURL(String url) {
return response.encodeURL(url);
}
public String encodeRedirectURL(String url) {
return response.encodeRedirectURL(url);
}
public String encodeUrl(String url) {
return response.encodeURL(url);
}
public String encodeRedirectUrl(String url) {
return response.encodeRedirectURL(url);
}
public void sendError(int sc, String msg)
throws IOException {
if (isCommitted())
throw new IllegalStateException
(/*sm.getString("responseBase.reset.ise")*/);
response.setAppCommitted(true);
response.sendError(sc, msg);
}
public void sendError(int sc)
throws IOException {
if (isCommitted())
throw new IllegalStateException
(/*sm.getString("responseBase.reset.ise")*/);
response.setAppCommitted(true);
response.sendError(sc);
}
public void sendRedirect(String location)
throws IOException {
if (isCommitted())
throw new IllegalStateException
(/*sm.getString("responseBase.reset.ise")*/);
response.setAppCommitted(true);
response.sendRedirect(location);
}
public void setDateHeader(String name, long date) {
if (isCommitted())
return;
response.setDateHeader(name, date);
}
public void addDateHeader(String name, long date) {
if (isCommitted())
return;
response.addDateHeader(name, date);
}
public void setHeader(String name, String value) {
if (isCommitted())
return;
response.setHeader(name, value);
}
public void addHeader(String name, String value) {
if (isCommitted())
return;
response.addHeader(name, value);
}
public void setIntHeader(String name, int value) {
if (isCommitted())
return;
response.setIntHeader(name, value);
}
public void addIntHeader(String name, int value) {
if (isCommitted())
return;
response.addIntHeader(name, value);
}
public void setStatus(int sc) {
if (isCommitted())
return;
response.setStatus(sc);
}
public void setStatus(int sc, String sm) {
if (isCommitted())
return;
response.setStatus(sc, sm);
}
}
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteServerSocketFactory.java
Index: CoyoteServerSocketFactory.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.coyote.tomcat5;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.KeyManagementException;
import java.security.Security;
import java.security.cert.CertificateException;
/**
* This socket factory holds secure socket factory parameters. Besides the usual
* configuration mechanism based on setting JavaBeans properties, this
* component may also be configured by passing a series of attributes set
* with calls to <code>setAttribute()</code>. The following attribute
* names are recognized, with default values in square brackets:
* <ul>
* <li><strong>algorithm</strong> - Certificate encoding algorithm
* to use. [SunX509]</li>
* <li><strong>clientAuth</strong> - Require client authentication if
* set to <code>true</code>. [false]</li>
* <li><strong>keystoreFile</strong> - Pathname to the Key Store file to be
* loaded. This must be an absolute path, or a relative path that
* is resolved against the "catalina.base" system property.
* ["./keystore" in the user home directory]</li>
* <li><strong>keystorePass</strong> - Password for the Key Store file to be
* loaded. ["changeit"]</li>
* <li><strong>keystoreType</strong> - Type of the Key Store file to be
* loaded. ["JKS"]</li>
* <li><strong>protocol</strong> - SSL protocol to use. [TLS]</li>
* </ul>
*
* @author Harish Prabandham
* @author Costin Manolache
* @author Craig McClanahan
*/
public class CoyoteServerSocketFactory
implements org.apache.catalina.net.ServerSocketFactory {
// ------------------------------------------------------------- Properties
/**
* Certificate encoding algorithm to be used.
*/
private String algorithm = null;
public String getAlgorithm() {
return (this.algorithm);
}
public void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}
/**
* Should we require client authentication?
*/
private boolean clientAuth = false;
public boolean getClientAuth() {
return (this.clientAuth);
}
public void setClientAuth(boolean clientAuth) {
this.clientAuth = clientAuth;
}
/**
* Pathname to the key store file to be used.
*/
private String keystoreFile =
System.getProperty("user.home") + File.separator + ".keystore";
public String getKeystoreFile() {
return (this.keystoreFile);
}
public void setKeystoreFile(String keystoreFile) {
File file = new File(keystoreFile);
if (!file.isAbsolute())
file = new File(System.getProperty("catalina.base"),
keystoreFile);
this.keystoreFile = file.getAbsolutePath();
}
/**
* Pathname to the random file to be used.
*/
private String randomFile =
System.getProperty("user.home") + File.separator + "random.pem";
public String getRandomFile() {
return (this.randomFile);
}
public void setRandomFile(String randomFile) {
File file = new File(randomFile);
if (!file.isAbsolute())
file = new File(System.getProperty("catalina.base"),
randomFile);
this.randomFile = file.getAbsolutePath();
}
/**
* Pathname to the root list to be used.
*/
private String rootFile =
System.getProperty("user.home") + File.separator + "root.pem";
public String getRootFile() {
return (this.rootFile);
}
public void setRootFile(String rootFile) {
File file = new File(rootFile);
if (!file.isAbsolute())
file = new File(System.getProperty("catalina.base"),
rootFile);
this.rootFile = file.getAbsolutePath();
}
/**
* Password for accessing the key store file.
*/
private String keystorePass = "changeit";
public String getKeystorePass() {
return (this.keystorePass);
}
public void setKeystorePass(String keystorePass) {
this.keystorePass = keystorePass;
}
/**
* Storeage type of the key store file to be used.
*/
private String keystoreType = "JKS";
public String getKeystoreType() {
return (this.keystoreType);
}
public void setKeystoreType(String keystoreType) {
this.keystoreType = keystoreType;
}
/**
* SSL protocol variant to use.
*/
private String protocol = "TLS";
public String getProtocol() {
return (this.protocol);
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
/**
* SSL implementation to use.
*/
private String sslImplementation = null;
public String getSSLImplementation() {
return (this.sslImplementation);
}
public void setSSLImplementation(String sslImplementation) {
this.sslImplementation = sslImplementation;
}
// --------------------------------------------------------- Public Methods
public ServerSocket createSocket(int port) {
return (null);
}
public ServerSocket createSocket(int port, int backlog) {
return (null);
}
public ServerSocket createSocket(int port, int backlog,
InetAddress ifAddress) {
return (null);
}
}
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/CoyoteWriter.java
Index: CoyoteWriter.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.coyote.tomcat5;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletOutputStream;
/**
* Coyote implementation of the servlet writer.
*
* @author Costin Manolache
* @author Remy Maucherat
*/
final class CoyoteWriter
extends PrintWriter {
// ----------------------------------------------------- Instance Variables
protected OutputBuffer ob;
// ----------------------------------------------------------- Constructors
public CoyoteWriter(OutputBuffer ob) {
super(ob);
this.ob = ob;
}
// --------------------------------------------------------- Writer Methods
public void flush() {
super.flush();
}
public void write(char buf[], int offset, int count) {
super.write(buf, offset, count);
}
public void write(String str) {
super.write( str );
}
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 ) {
ex.printStackTrace();
}
}
// ---------------------------------------------------- PrintWriter Methods
public void print(String str) {
super.print( str );
}
public void println(String str) {
super.println(str);
}
}
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/LocalStrings.properties
Index: LocalStrings.properties
===================================================================
#
# CoyoteConnector
#
coyoteConnector.alreadyInitialized=The connector has already been initialized
coyoteConnector.alreadyStarted=The connector has already been started
coyoteConnector.notStarted=Coyote connector has not been started
coyoteConnector.protocolHandlerDestroyFailed=Protocol handler destroy failed: {0}
coyoteConnector.protocolHandlerInitializationFailed=Protocol handler initialization failed: {0}
coyoteConnector.protocolHandlerInstantiationFailed=Protocol handler instantiation failed: {0}
coyoteConnector.protocolHandlerStartFailed=Protocol handler start failed: {0}
#
# CoyoteAdapter
#
coyoteAdapter.service=An exception or error occurred in the container during the request processing
#
# CoyoteResponse
#
coyoteResponse.getOutputStream.ise=getWriter() has already been called for this response
coyoteResponse.getWriter.ise=getOutputStream() has already been called for this response
coyoteResponse.resetBuffer.ise=Cannot reset buffer after response has been committed
coyoteResponse.sendError.ise=Cannot call sendError() after the response has been committed
coyoteResponse.sendRedirect.ise=Cannot call sendRedirect() after the response has been committed
coyoteResponse.setBufferSize.ise=Cannot change buffer size after data has been written
#
# CoyoteRequest
#
coyoteRequest.getInputStream.ise=getReader() has already been called for this request
coyoteRequest.getReader.ise=getInputStream() has already been called for this request
coyoteRequest.sessionCreateCommitted=Cannot create a session after the response has been committed
coyoteRequest.setAttribute.namenull=Cannot call setAttribute with a null name
1.1 jakarta-tomcat-connectors/coyote/src/java/org/apache/coyote/tomcat5/OutputBuffer.java
Index: OutputBuffer.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.coyote.tomcat5;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.Hashtable;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.C2BConverter;
import org.apache.tomcat.util.buf.CharChunk;
import org.apache.coyote.Response;
/**
* The buffer used by Tomcat response. This is a derivative of the Tomcat 3.3
* OutputBuffer, with the removal of some of the state handling (which in
* Coyote is mostly the Processor's responsability).
*
* @author Costin Manolache
* @author Remy Maucherat
*/
public class OutputBuffer extends Writer
implements ByteChunk.ByteOutputChannel, 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;
static final int debug = 0;
// The buffer can be used for byte[] and char[] writing
// ( this is needed to support ServletOutputStream and for
// efficient implementations of templating systems )
public final int INITIAL_STATE = 0;
public final int CHAR_STATE = 1;
public final int BYTE_STATE = 2;
// ----------------------------------------------------- Instance Variables
/**
* The byte buffer.
*/
private ByteChunk bb;
/**
* The chunk buffer.
*/
private CharChunk cb;
/**
* State of the output buffer.
*/
private int state = 0;
/**
* Number of bytes written.
*/
private int bytesWritten = 0;
/**
* Number of chars written.
*/
private int charsWritten = 0;
/**
* Flag which indicates if the output buffer is closed.
*/
private boolean closed = false;
/**
* Do a flush on the next operation.
*/
private boolean doFlush = false;
/**
* Byte chunk used to output bytes.
*/
private ByteChunk outputChunk = new ByteChunk();
/**
* Encoding to use.
*/
private String enc;
/**
* Encoder is set.
*/
private boolean gotEnc = false;
/**
* List of encoders.
*/
protected Hashtable encoders = new Hashtable();
/**
* Current char to byte converter.
*/
protected C2BConverter conv;
/**
* Associated Coyote response.
*/
private Response coyoteResponse;
/**
* Suspended flag. All output bytes will be swallowed if this is true.
*/
private boolean suspended = false;
// ----------------------------------------------------------- Constructors
/**
* Default constructor. Allocate the buffer with the default buffer size.
*/
public OutputBuffer() {
this(DEFAULT_BUFFER_SIZE);
}
/**
* Alternate constructor which allows specifying the initial buffer size.
*
* @param size Buffer size to use
*/
public OutputBuffer(int size) {
bb = new ByteChunk(size);
bb.setLimit(size);
bb.setByteOutputChannel(this);
cb = new CharChunk(size);
cb.setCharOutputChannel(this);
cb.setLimit(size);
}
// ------------------------------------------------------------- Properties
/**
* Associated Coyote response.
*
* @param coyoteResponse Associated Coyote response
*/
public void setResponse(Response coyoteResponse) {
this.coyoteResponse = coyoteResponse;
}
/**
* Get associated Coyote response.
*
* @return the associated Coyote response
*/
public Response getResponse() {
return this.coyoteResponse;
}
/**
* Is the response output suspended ?
*
* @return suspended flag value
*/
public boolean isSuspended() {
return this.suspended;
}
/**
* Set the suspended flag.
*
* @param suspended New suspended flag value
*/
public void setSuspended(boolean suspended) {
this.suspended = suspended;
}
// --------------------------------------------------------- Public Methods
/**
* Recycle the output buffer.
*/
public void recycle() {
if (debug > 0)
log("recycle()");
state = INITIAL_STATE;
bytesWritten = 0;
charsWritten = 0;
cb.recycle();
bb.recycle();
closed = false;
suspended = false;
if (conv!= null) {
conv.recycle();
}
gotEnc = false;
enc = null;
}
/**
* Close the output buffer. This tries to calculate the response size if
* the response has not been committed yet.
*
* @throws IOException An underlying IOException occurred
*/
public void close()
throws IOException {
if (suspended)
return;
if ((!coyoteResponse.isCommitted())
&& (coyoteResponse.getContentLength() == -1)) {
// Flushing the char buffer
if (state == CHAR_STATE) {
cb.flushBuffer();
state = BYTE_STATE;
}
// If this didn't cause a commit of the response, the final content
// length can be calculated
if (!coyoteResponse.isCommitted()) {
coyoteResponse.setContentLength(bb.getLength());
}
}
flush();
closed = true;
}
/**
* Flush bytes or chars contained in the buffer.
*
* @throws IOException An underlying IOException occurred
*/
public void flush()
throws IOException {
if (suspended)
return;
doFlush = true;
if (state == CHAR_STATE) {
cb.flushBuffer();
bb.flushBuffer();
state = BYTE_STATE;
} else if (state == BYTE_STATE) {
bb.flushBuffer();
} else if (state == INITIAL_STATE)
realWriteBytes(null, 0, 0); // nothing written yet
doFlush = false;
}
// ------------------------------------------------- Bytes Handling Methods
/**
* Sends the buffer data to the client output, checking the
* state of Response and calling the right interceptors.
*
* @param buf Byte buffer to be written to the response
* @param off Offset
* @param cnt Length
*
* @throws IOException An underlying IOException occurred
*/
public void realWriteBytes(byte buf[], int off, int cnt)
throws IOException {
if (debug > 2)
log("realWrite(b, " + off + ", " + cnt + ") " + coyoteResponse);
if (closed)
return;
if (coyoteResponse == null)
return;
// If we really have something to write
if (cnt > 0) {
// real write to the adapter
outputChunk.setBytes(buf, off, cnt);
coyoteResponse.doWrite(outputChunk);
}
}
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;
if (debug > 0)
log("write(b,off,len)");
bb.append(b, off, len);
bytesWritten += len;
// if called from within flush(), then immediately flush
// remaining bytes
if (doFlush) {
bb.flushBuffer();
}
}
// XXX Char or byte ?
public void writeByte(int b)
throws IOException {
if (suspended)
return;
if (state == CHAR_STATE)
cb.flushBuffer();
state = BYTE_STATE;
if (debug > 0)
log("write(b)");
bb.append( (byte)b );
bytesWritten++;
}
// ------------------------------------------------- Chars Handling Methods
public void write(int c)
throws IOException {
if (suspended)
return;
state = CHAR_STATE;
if (debug > 0)
log("writeChar(b)");
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;
if (debug > 0)
log("write(c,off,len)" + cb.getLength() + " " + cb.getLimit());
cb.append(c, off, len);
charsWritten += len;
}
public void write(StringBuffer sb)
throws IOException {
if (suspended)
return;
state = CHAR_STATE;
if (debug > 1)
log("write(s,off,len)");
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;
if (debug > 1)
log("write(s,off,len)");
charsWritten += len;
if (s==null)
s="null";
cb.append( s, off, len );
}
public void write(String s)
throws IOException {
if (suspended)
return;
state = CHAR_STATE;
if (s==null)
s="null";
write(s, 0, s.length());
}
public void flushChars()
throws IOException {
if (debug > 0)
log("flushChars() " + cb.getLength());
cb.flushBuffer();
state = BYTE_STATE;
}
public boolean flushCharsNeeded() {
return state == CHAR_STATE;
}
public void setEncoding(String s) {
enc = s;
}
public void realWriteChars(char c[], int off, int len)
throws IOException {
if (debug > 0)
log("realWrite(c,o,l) " + cb.getOffset() + " " + len);
if (!gotEnc)
setConverter();
if (debug > 0)
log("encoder: " + conv + " " + gotEnc);
conv.convert(c, off, len);
conv.flushBuffer(); // ???
}
protected void setConverter() {
if (coyoteResponse != null)
enc = coyoteResponse.getCharacterEncoding();
if (debug > 0)
log("Got encoding: " + enc);
gotEnc = true;
if (enc == null)
enc = DEFAULT_ENCODING;
conv = (C2BConverter) encoders.get(enc);
if (conv == null) {
try {
conv = new C2BConverter(bb, enc);
encoders.put(enc, conv);
} catch (IOException e) {
conv = (C2BConverter) encoders.get(DEFAULT_ENCODING);
if (conv == null) {
try {
conv = new C2BConverter(bb, DEFAULT_ENCODING);
encoders.put(DEFAULT_ENCODING, conv);
} catch (IOException ex) {
// Ignore
}
}
}
}
}
// -------------------- BufferedOutputStream compatibility
/**
* Real write - this buffer will be sent to the client
*/
public void flushBytes()
throws IOException {
if (debug > 0)
log("flushBytes() " + bb.getLength());
bb.flushBuffer();
}
public int getBytesWritten() {
return bytesWritten;
}
public int getCharsWritten() {
return 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;
}
public int getBufferSize() {
return bb.getLimit();
}
protected void log( String s ) {
System.out.println("OutputBuffer: " + s);
}
}
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>