diff -Nru tomcat7-7.0.70/build.properties.default tomcat7-7.0.72/build.properties.default
--- tomcat7-7.0.70/build.properties.default 2016-06-15 14:24:03.000000000 +0000
+++ tomcat7-7.0.72/build.properties.default 2016-09-14 12:02:51.000000000 +0000
@@ -25,7 +25,7 @@
# ----- Version Control Flags -----
version.major=7
version.minor=0
-version.build=70
+version.build=72
version.patch=0
version.suffix=
@@ -67,7 +67,7 @@
compile.target=1.6
compile.debug=true
-base-apache.loc.1=http://www.apache.org/dist
+base-apache.loc.1=http://www.apache.org/dyn/closer.lua?action=download&filename=
base-apache.loc.2=http://archive.apache.org/dist
base-commons.loc.1=${base-apache.loc.1}/commons
base-commons.loc.2=${base-apache.loc.2}/commons
@@ -140,7 +140,7 @@
jdt.loc.2=http://download.eclipse.org/eclipse/downloads/drops4/${jdt.release}/ecj-${jdt.version}.jar
# ----- Tomcat native library -----
-tomcat-native.version=1.2.7
+tomcat-native.version=1.2.8
tomcat-native.home=${base.path}/tomcat-native-${tomcat-native.version}
tomcat-native.tar.gz=${tomcat-native.home}/tomcat-native.tar.gz
tomcat-native.loc.1=${base-tomcat.loc.1}/tomcat-connectors/native/${tomcat-native.version}/source/tomcat-native-${tomcat-native.version}-src.tar.gz
@@ -211,7 +211,7 @@
# ----- objenesis, used by EasyMock, version 1.2 or later -----
objenesis.version=1.2
objenesis.home=${base.path}/objenesis-${objenesis.version}
-objenesis.loc=https://objenesis.googlecode.com/files/objenesis-${objenesis.version}-bin.zip
+objenesis.loc=https://bintray.com/easymock/distributions/download_file?file_path=objenesis-${objenesis.version}-bin.zip
objenesis.jar=${objenesis.home}/objenesis-${objenesis.version}.jar
# ----- Checkstyle, version 6.0 or later -----
diff -Nru tomcat7-7.0.70/conf/web.xml tomcat7-7.0.72/conf/web.xml
--- tomcat7-7.0.70/conf/web.xml 2015-11-25 13:47:58.000000000 +0000
+++ tomcat7-7.0.72/conf/web.xml 2016-08-30 22:45:07.000000000 +0000
@@ -163,6 +163,8 @@
+
+
@@ -224,6 +226,8 @@
+
+
@@ -326,26 +330,18 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -362,14 +358,10 @@
+ * The default value for this implementation is {@code true}.
+ */
+ @Override
+ public boolean getDispatchersUseEncodedPaths() {
+ return dispatchersUseEncodedPaths;
+ }
+
+
+ @Override
public void setUseRelativeRedirects(boolean useRelativeRedirects) {
this.useRelativeRedirects = useRelativeRedirects;
}
@@ -2261,7 +2280,7 @@
log.warn(sm.getString(
"standardContext.pathInvalid", path, this.path));
}
- encodedPath = urlEncoder.encode(this.path);
+ encodedPath = urlEncoder.encode(this.path, "UTF-8");
if (getName() == null) {
setName(this.path);
}
diff -Nru tomcat7-7.0.70/java/org/apache/catalina/core/StandardWrapper.java tomcat7-7.0.72/java/org/apache/catalina/core/StandardWrapper.java
--- tomcat7-7.0.70/java/org/apache/catalina/core/StandardWrapper.java 2016-01-01 21:36:36.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/catalina/core/StandardWrapper.java 2016-07-14 20:07:54.000000000 +0000
@@ -573,35 +573,22 @@
/**
- * Return true
if the servlet class represented by this
- * component implements the SingleThreadModel
interface.
- */
- public boolean isSingleThreadModel() {
-
- // Short-cuts
- // If singleThreadModel is true, must have already checked this
- // If instance != null, must have already loaded
+ * Does the servlet class represented by this component implement the
+ * SingleThreadModel
interface? This can only be determined
+ * once the class is loaded. Calling this method will not trigger loading
+ * the class since that may cause the application to behave unexpectedly.
+ *
+ * @return {@code null} if the class has not been loaded, otherwise {@code
+ * true} if the servlet does implement {@code SingleThreadModel} and
+ * {@code false} if it does not.
+ */
+ public Boolean isSingleThreadModel() {
+ // If the servlet has been loaded either singleThreadModel will be true
+ // or instance will be non-null
if (singleThreadModel || instance != null) {
- return singleThreadModel;
- }
-
- // The logic to determine this safely is more complex than one might
- // expect. allocate() already has the necessary logic so re-use it.
- // Make sure the Servlet is loaded with the right class loader
- ClassLoader old = Thread.currentThread().getContextClassLoader();
- ClassLoader webappClassLoader =
- ((Context) getParent()).getLoader().getClassLoader();
- try {
- Thread.currentThread().setContextClassLoader(webappClassLoader);
- Servlet s = allocate();
- deallocate(s);
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
- } finally {
- Thread.currentThread().setContextClassLoader(old);
+ return Boolean.valueOf(singleThreadModel);
}
- return singleThreadModel;
-
+ return null;
}
@@ -1486,12 +1473,7 @@
instanceSupport.fireInstanceEvent
(InstanceEvent.AFTER_DESTROY_EVENT, instance);
-
- // Annotation processing
- if (!((Context) getParent()).getIgnoreAnnotations()) {
- ((StandardContext)getParent()).getInstanceManager().destroyInstance(instance);
- }
-
+
} catch (Throwable t) {
t = ExceptionUtils.unwrapInvocationTargetException(t);
ExceptionUtils.handleThrowable(t);
@@ -1506,6 +1488,15 @@
(sm.getString("standardWrapper.destroyException", getName()),
t);
} finally {
+ // Annotation processing
+ if (!((Context) getParent()).getIgnoreAnnotations()) {
+ try {
+ ((Context)getParent()).getInstanceManager().destroyInstance(instance);
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ log.error(sm.getString("standardWrapper.destroyInstance", getName()), t);
+ }
+ }
// Write captured output
if (swallowOutput) {
String log = SystemLogHandler.stopCapture();
diff -Nru tomcat7-7.0.70/java/org/apache/catalina/deploy/ErrorPage.java tomcat7-7.0.72/java/org/apache/catalina/deploy/ErrorPage.java
--- tomcat7-7.0.70/java/org/apache/catalina/deploy/ErrorPage.java 2014-01-27 14:53:14.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/catalina/deploy/ErrorPage.java 2016-08-11 20:17:20.000000000 +0000
@@ -92,9 +92,8 @@
try {
this.errorCode = Integer.parseInt(errorCode);
} catch (NumberFormatException nfe) {
- this.errorCode = 0;
+ throw new IllegalArgumentException(nfe);
}
-
}
diff -Nru tomcat7-7.0.70/java/org/apache/catalina/filters/CorsFilter.java tomcat7-7.0.72/java/org/apache/catalina/filters/CorsFilter.java
--- tomcat7-7.0.70/java/org/apache/catalina/filters/CorsFilter.java 2015-05-18 11:35:00.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/catalina/filters/CorsFilter.java 2016-08-23 13:24:51.000000000 +0000
@@ -863,8 +863,14 @@
return true;
}
- URI originURI;
+ // RFC6454, section 4. "If uri-scheme is file, the implementation MAY
+ // return an implementation-defined value.". No limits are placed on
+ // that value so treat all file URIs as valid origins.
+ if (origin.startsWith("file://")) {
+ return true;
+ }
+ URI originURI;
try {
originURI = new URI(origin);
} catch (URISyntaxException e) {
diff -Nru tomcat7-7.0.70/java/org/apache/catalina/filters/LocalStrings.properties tomcat7-7.0.72/java/org/apache/catalina/filters/LocalStrings.properties
--- tomcat7-7.0.70/java/org/apache/catalina/filters/LocalStrings.properties 2015-11-30 16:29:01.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/catalina/filters/LocalStrings.properties 2016-06-16 13:02:31.000000000 +0000
@@ -47,4 +47,6 @@
httpHeaderSecurityFilter.committed=Unable to add HTTP headers since response is already committed on entry to the HTTP header security Filter
httpHeaderSecurityFilter.clickjack.invalid=An invalid value [{0}] was specified for the anti click-jacking header
+requestFilter.deny=Denied request for [{0}] based on property [{1}]
+
restCsrfPreventionFilter.invalidNonce=CSRF nonce validation failed
\ No newline at end of file
diff -Nru tomcat7-7.0.70/java/org/apache/catalina/filters/RequestFilter.java tomcat7-7.0.72/java/org/apache/catalina/filters/RequestFilter.java
--- tomcat7-7.0.70/java/org/apache/catalina/filters/RequestFilter.java 2014-01-27 14:53:14.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/catalina/filters/RequestFilter.java 2016-06-16 13:02:31.000000000 +0000
@@ -24,6 +24,7 @@
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.comet.CometEvent;
@@ -205,6 +206,10 @@
chain.doFilter(request, response);
} else {
if (response instanceof HttpServletResponse) {
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug(sm.getString("requestFilter.deny",
+ ((HttpServletRequest) request).getRequestURI(), property));
+ }
((HttpServletResponse) response).sendError(denyStatus);
} else {
sendErrorWhenNotHttp(response);
diff -Nru tomcat7-7.0.70/java/org/apache/catalina/ha/authenticator/mbeans-descriptors.xml tomcat7-7.0.72/java/org/apache/catalina/ha/authenticator/mbeans-descriptors.xml
--- tomcat7-7.0.70/java/org/apache/catalina/ha/authenticator/mbeans-descriptors.xml 2015-04-22 10:32:06.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/catalina/ha/authenticator/mbeans-descriptors.xml 2016-08-10 07:25:25.000000000 +0000
@@ -38,7 +38,7 @@
type="boolean"/>
null
is
+ * returned for any user that is currently locked out.
+ */
+ private Principal filterLockedAccounts(String username, Principal authenticatedUser) {
+ // Register all failed authentications
+ if (authenticatedUser == null) {
+ registerAuthFailure(username);
+ }
+
+ if (isLocked(username)) {
+ // If the user is currently locked, authentication will always fail
+ log.warn(sm.getString("lockOutRealm.authLockedUser", username));
+ return null;
+ }
+
+ if (authenticatedUser != null) {
+ registerAuthSuccess(username);
+ }
+
+ return authenticatedUser;
+ }
+
+
/**
* Unlock the specified username. This will remove all records of
* authentication failures for this user.
diff -Nru tomcat7-7.0.70/java/org/apache/catalina/realm/mbeans-descriptors.xml tomcat7-7.0.72/java/org/apache/catalina/realm/mbeans-descriptors.xml
--- tomcat7-7.0.70/java/org/apache/catalina/realm/mbeans-descriptors.xml 2014-12-14 13:10:32.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/catalina/realm/mbeans-descriptors.xml 2016-08-10 07:25:25.000000000 +0000
@@ -91,7 +91,7 @@
true
if this constraint is satisfied and processing
@@ -953,7 +976,7 @@
denyfromall = true;
break;
}
-
+
if(log.isDebugEnabled())
log.debug("Passing all access");
status = true;
@@ -991,7 +1014,7 @@
status = true;
break;
}
-
+
// For AllRolesMode.STRICT_AUTH_ONLY_MODE there must be zero roles
roles = request.getContext().findSecurityRoles();
if (roles.length == 0 && allRolesMode == AllRolesMode.STRICT_AUTH_ONLY_MODE) {
@@ -1004,7 +1027,7 @@
}
}
}
-
+
// Return a "Forbidden" message denying access to this resource
if(!status) {
response.sendError
@@ -1014,8 +1037,8 @@
return status;
}
-
-
+
+
/**
* Return true
if the specified Principal has the specified
* security role, within the context of this Realm; otherwise return
@@ -1054,7 +1077,7 @@
}
-
+
/**
* Enforce any user data constraint required by the security constraint
* guarding this request URI. Return true
if this constraint
@@ -1145,8 +1168,8 @@
return (false);
}
-
-
+
+
/**
* Remove a property change listener from this component.
*
@@ -1172,7 +1195,7 @@
x509UsernameRetriever = createUsernameRetriever(x509UsernameRetrieverClassName);
}
-
+
/**
* Prepare for the beginning of active use of the public methods of this
* component and implement the requirements of
@@ -1210,12 +1233,12 @@
protected void stopInternal() throws LifecycleException {
setState(LifecycleState.STOPPING);
-
+
// Clean up allocated resources
md = null;
}
-
-
+
+
/**
* Return a String representation of this component.
*/
@@ -1226,8 +1249,8 @@
sb.append(']');
return sb.toString();
}
-
-
+
+
// ------------------------------------------------------ Protected Methods
@@ -1249,7 +1272,7 @@
synchronized (this) {
try {
md.reset();
-
+
byte[] bytes = null;
try {
bytes = credentials.getBytes(getDigestCharset());
@@ -1289,7 +1312,7 @@
// Use pre-generated digest
return getPassword(username);
}
-
+
String digestValue = username + ":" + realmName + ":"
+ getPassword(username);
@@ -1335,7 +1358,7 @@
return(getPrincipal(username));
}
-
+
/**
* Return the Principal associated with the given user name.
@@ -1346,11 +1369,11 @@
protected Principal getPrincipal(String username,
GSSCredential gssCredential) {
Principal p = getPrincipal(username);
-
+
if (p instanceof GenericPrincipal) {
((GenericPrincipal) p).setGssCredential(gssCredential);
}
-
+
return p;
}
@@ -1377,7 +1400,7 @@
return null;
}
-
+
// --------------------------------------------------------- Static Methods
@@ -1404,7 +1427,7 @@
if (encoding == null) {
md.update(credentials.getBytes());
} else {
- md.update(credentials.getBytes(encoding));
+ md.update(credentials.getBytes(encoding));
}
// Digest the credentials and return as hexadecimal
@@ -1426,12 +1449,12 @@
String encoding = null;
int firstCredentialArg = 2;
-
+
if (args.length > 4 && args[2].equalsIgnoreCase("-e")) {
encoding = args[3];
firstCredentialArg = 4;
}
-
+
if(args.length > firstCredentialArg && args[0].equalsIgnoreCase("-a")) {
for(int i=firstCredentialArg; i < args.length ; i++){
System.out.print(args[i]+":");
@@ -1449,7 +1472,7 @@
@Override
public String getObjectNameKeyProperties() {
-
+
StringBuilder keyProperties = new StringBuilder("type=Realm");
keyProperties.append(getRealmSuffix());
keyProperties.append(MBeanUtils.getContainerKeyProperties(container));
@@ -1467,7 +1490,7 @@
public String getRealmPath() {
return realmPath;
}
-
+
public void setRealmPath(String theRealmPath) {
realmPath = theRealmPath;
}
@@ -1478,10 +1501,10 @@
protected static class AllRolesMode {
-
+
private String name;
/** Use the strict servlet spec interpretation which requires that the user
- * have one of the web-app/security-role/role-name
+ * have one of the web-app/security-role/role-name
*/
public static final AllRolesMode STRICT_MODE = new AllRolesMode("strict");
/** Allow any authenticated user
@@ -1490,7 +1513,7 @@
/** Allow any authenticated user only if there are no web-app/security-roles
*/
public static final AllRolesMode STRICT_AUTH_ONLY_MODE = new AllRolesMode("strictAuthOnly");
-
+
static AllRolesMode toMode(String name)
{
AllRolesMode mode;
@@ -1504,12 +1527,12 @@
throw new IllegalStateException("Unknown mode, must be one of: strict, authOnly, strictAuthOnly");
return mode;
}
-
+
private AllRolesMode(String name)
{
this.name = name;
}
-
+
@Override
public boolean equals(Object o)
{
diff -Nru tomcat7-7.0.70/java/org/apache/catalina/servlets/CGIServlet.java tomcat7-7.0.72/java/org/apache/catalina/servlets/CGIServlet.java
--- tomcat7-7.0.70/java/org/apache/catalina/servlets/CGIServlet.java 2016-01-01 21:11:52.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/catalina/servlets/CGIServlet.java 2016-09-07 09:03:59.000000000 +0000
@@ -14,8 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-
package org.apache.catalina.servlets;
import java.io.BufferedOutputStream;
@@ -34,8 +32,10 @@
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
+import java.util.Map.Entry;
import java.util.StringTokenizer;
import java.util.Vector;
+import java.util.regex.Pattern;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
@@ -49,6 +49,9 @@
import javax.servlet.http.HttpSession;
import org.apache.catalina.util.IOTools;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.res.StringManager;
/**
@@ -117,7 +120,7 @@
*
* CGI Specification:
derived from
* http://cgi-spec.golux.com.
- * A work-in-progress & expired Internet Draft. Note no actual RFC describing
+ * A work-in-progress & expired Internet Draft. Note no actual RFC describing
* the CGI specification exists. Where the behavior of this servlet differs
* from the specification cited above, it is either documented here, a bug,
* or an instance where the specification cited differs from Best
@@ -160,7 +163,6 @@
*
*
@@ -174,8 +176,8 @@
* and stderr (which should not be too hard).
*
* If you find your cgi scripts are timing out receiving input, you can set
- * the init parameter of your webapps' cgi-handling servlet
- * to be
+ * the init parameter
stderrTimeout
of your webapps' cgi-handling
+ * servlet.
*
* @@ -212,7 +214,6 @@ * http://cgi-spec.golux.com. * *
- **
HTTP_
and with all -
characters
+ * converted to _
.
+ */
+ private Pattern envHttpHeadersPattern = Pattern.compile(
+ "ACCEPT[-0-9A-Z]*|CACHE-CONTROL|COOKIE|HOST|IF-[-0-9A-Z]*|REFERER|USER-AGENT");
+
/** object used to ensure multiple threads don't try to expand same file */
- static Object expandFileLock = new Object();
+ private static final Object expandFileLock = new Object();
/** the shell environment variables to be passed to the CGI script */
- Hashtable* Copied from SnoopAllServlet by Craig R. McClanahan *
* - * @param out ServletOutputStream as target of the information + * @param out Unused * @param req HttpServletRequest object used as source of information - * @param res HttpServletResponse object currently not used but could - * provide future information + * @param res Unused * * @exception IOException if a write operation exception occurs * + * @deprecated Use {@link #printServletEnvironment(HttpServletRequest)}. + * This will be removed in Tomcat 8.5.X onwards */ + @Deprecated protected void printServletEnvironment(ServletOutputStream out, - HttpServletRequest req, HttpServletResponse res) - throws IOException { + HttpServletRequest req, HttpServletResponse res) throws IOException { + printServletEnvironment(req); + } + + /** + * Logs important Servlet API and container information. + * + *+ * Based on SnoopAllServlet by Craig R. McClanahan + *
+ * + * @param req HttpServletRequest object used as source of information + * + * @exception IOException if a write operation exception occurs + */ + private void printServletEnvironment(HttpServletRequest req) throws IOException { // Document the properties from ServletRequest - out.println("doGet
+ * Provides CGI Gateway service -- delegates to
+ * {@link #doGet(HttpServletRequest, HttpServletResponse)}.
*
* @param req HttpServletRequest passed in by servlet container
* @param res HttpServletResponse passed in by servlet container
*
* @exception ServletException if a servlet-specific exception occurs
* @exception IOException if a read/write exception occurs
- *
- * @see javax.servlet.http.HttpServlet
- *
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res)
@@ -568,16 +517,13 @@
/**
- * Provides CGI Gateway service
+ * Provides CGI Gateway service.
*
* @param req HttpServletRequest passed in by servlet container
* @param res HttpServletResponse passed in by servlet container
*
* @exception ServletException if a servlet-specific exception occurs
* @exception IOException if a read/write exception occurs
- *
- * @see javax.servlet.http.HttpServlet
- *
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res)
@@ -590,75 +536,37 @@
cgiEnv.getEnvironment(),
cgiEnv.getWorkingDirectory(),
cgiEnv.getParameters());
- //if POST, we need to cgi.setInput
- //REMIND: how does this interact with Servlet API 2.3's Filters?!
+
if ("POST".equals(req.getMethod())) {
cgi.setInput(req.getInputStream());
}
cgi.setResponse(res);
cgi.run();
+ } else {
+ res.sendError(404);
}
- if (!cgiEnv.isValid()) {
- if (setStatus(res, 404)) {
- return;
- }
- }
-
- if (debug >= 10) {
-
- ServletOutputStream out = res.getOutputStream();
- out.println(""); - - if (cgiEnv.isValid()) { - out.println(cgiEnv.toString()); - } else { - out.println("
- *
- * - * @since Tomcat 4.0 */ protected class CGIEnvironment { @@ -705,13 +608,13 @@ private String command = null; /** cgi command's desired working directory */ - private File workingDirectory = null; + private final File workingDirectory; /** cgi command's command line parameters */ - private ArrayList* Example URI: + *
*/servlet/cgigateway/dir1/realCGIscript/pathinfo1*
* CGI search algorithm: search the real path below
* <my-webapp-root> and find the first non-directory in
@@ -874,8 +779,6 @@
* name
- simple name (no directories) of the
* cgi script, or null if no cgi was found
*
- *
- * @since Tomcat 4.0
*/
protected String[] findCGI(String pathInfo, String webAppRootDir,
String contextPath, String servletPath,
@@ -884,46 +787,41 @@
String name = null;
String scriptname = null;
- if ((webAppRootDir != null)
- && (webAppRootDir.lastIndexOf(File.separator) ==
- (webAppRootDir.length() - 1))) {
- //strip the trailing "/" from the webAppRootDir
- webAppRootDir =
- webAppRootDir.substring(0, (webAppRootDir.length() - 1));
+ if (webAppRootDir != null &&
+ webAppRootDir.lastIndexOf(File.separator) == (webAppRootDir.length() - 1)) {
+ //strip the trailing "/" from the webAppRootDir
+ webAppRootDir = webAppRootDir.substring(0, (webAppRootDir.length() - 1));
}
if (cgiPathPrefix != null) {
- webAppRootDir = webAppRootDir + File.separator
- + cgiPathPrefix;
+ webAppRootDir = webAppRootDir + File.separator + cgiPathPrefix;
}
- if (debug >= 2) {
- log("findCGI: path=" + pathInfo + ", " + webAppRootDir);
+ if (log.isDebugEnabled()) {
+ log.debug(sm.getString("cgiServlet.find.path", pathInfo, webAppRootDir));
}
File currentLocation = new File(webAppRootDir);
- StringTokenizer dirWalker =
- new StringTokenizer(pathInfo, "/");
- if (debug >= 3) {
- log("findCGI: currentLoc=" + currentLocation);
+ StringTokenizer dirWalker = new StringTokenizer(pathInfo, "/");
+ if (log.isDebugEnabled()) {
+ log.debug(sm.getString("cgiServlet.find.location",
+ currentLocation.getAbsolutePath()));
}
StringBuilder cginameBuilder = new StringBuilder();
while (!currentLocation.isFile() && dirWalker.hasMoreElements()) {
- if (debug >= 3) {
- log("findCGI: currentLoc=" + currentLocation);
- }
String nextElement = (String) dirWalker.nextElement();
currentLocation = new File(currentLocation, nextElement);
cginameBuilder.append('/').append(nextElement);
+ if (log.isDebugEnabled()) {
+ log.debug(sm.getString("cgiServlet.find.location",
+ currentLocation.getAbsolutePath()));
+ }
}
String cginame = cginameBuilder.toString();
if (!currentLocation.isFile()) {
return new String[] { null, null, null, null };
}
- if (debug >= 2) {
- log("findCGI: FOUND cgi at " + currentLocation);
- }
path = currentLocation.getAbsolutePath();
name = currentLocation.getName();
@@ -936,9 +834,8 @@
scriptname = scriptname + cginame;
}
- if (debug >= 1) {
- log("findCGI calc: name=" + name + ", path=" + path
- + ", scriptname=" + scriptname + ", cginame=" + cginame);
+ if (log.isDebugEnabled()) {
+ log.debug(sm.getString("cgiServlet.find.found", name, path, scriptname, cginame));
}
return new String[] { path, scriptname, cginame, name };
}
@@ -952,6 +849,7 @@
*
* @return true if environment was set OK, false if there
* was a problem and no environment was set
+ * @throws IOException an IO error occurred
*/
protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException {
@@ -1106,12 +1004,8 @@
//REMIND: rewrite multiple headers as if received as single
//REMIND: change character set
//REMIND: I forgot what the previous REMIND means
- if ("AUTHORIZATION".equalsIgnoreCase(header) ||
- "PROXY_AUTHORIZATION".equalsIgnoreCase(header)) {
- //NOOP per CGI specification section 11.2
- } else {
- envp.put("HTTP_" + header.replace('-', '_'),
- req.getHeader(header));
+ if (envHttpHeadersPattern.matcher(header).matches()) {
+ envp.put("HTTP_" + header.replace('-', '_'), req.getHeader(header));
}
}
@@ -1161,10 +1055,8 @@
if (is == null) {
// didn't find anything, give up now
- if (debug >= 2) {
- log("expandCGIScript: source '" + srcPath + "' not found");
- }
- return;
+ log.warn(sm.getString("cgiServlet.expandNotFound", srcPath));
+ return;
}
File f = new File(destPath.toString());
@@ -1172,21 +1064,16 @@
try {
is.close();
} catch (IOException e) {
- log("Could not close is", e);
+ log.warn(sm.getString("cgiServlet.expandCloseFail", srcPath), e);
}
// Don't need to expand if it already exists
return;
}
// create directories
- String dirPath = destPath.toString().substring(
- 0,destPath.toString().lastIndexOf('/'));
- File dir = new File(dirPath);
+ File dir = f.getParentFile();
if (!dir.mkdirs() && !dir.isDirectory()) {
- if (debug >= 2) {
- log("expandCGIScript: failed to create directories for '" +
- dir.getAbsolutePath() + "'");
- }
+ log.warn(sm.getString("cgiServlet.expandCreateDirFail", dir.getAbsolutePath()));
return;
}
@@ -1210,20 +1097,20 @@
try {
is.close();
} catch (IOException e) {
- log("Could not close is.", e);
+ log.warn(sm.getString("cgiServlet.expandError"), e);
}
fos.close();
}
- if (debug >= 2) {
- log("expandCGIScript: expanded '" + srcPath + "' to '" + destPath + "'");
+ if (log.isDebugEnabled()) {
+ log.debug(sm.getString("cgiServlet.expandOk", srcPath, destPath));
}
}
} catch (IOException ioe) {
+ log.warn(sm.getString("cgiServlet.expandFail", srcPath, destPath), ioe);
// delete in case file is corrupted
if (f.exists()) {
- if (!f.delete() && debug >= 2) {
- log("expandCGIScript: failed to delete '" +
- f.getAbsolutePath() + "'");
+ if (!f.delete()) {
+ log.warn(sm.getString("cgiServlet.expandDeleteFail", f.getAbsolutePath()));
}
}
}
@@ -1231,65 +1118,67 @@
/**
- * Print important CGI environment information in a easy-to-read HTML
- * table
- *
- * @return HTML string containing CGI environment info
+ * Returns important CGI environment information in a multi-line text
+ * format.
*
+ * @return CGI environment info
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("
"); - sb.append("CGIEnvironment Info | |
---|---|
Debug Level | "); - sb.append(debug); - sb.append(" |
Validity: | "); - sb.append(isValid()); - sb.append(" |
"); - sb.append(s); - sb.append(" | "); - sb.append(blanksToString(env.get(s), - "[will be set to blank]")); - sb.append(" |
Derived Command | "); - sb.append(nullsToBlanks(command)); - sb.append(" |
Working Directory | "); - if (workingDirectory != null) { - sb.append(workingDirectory.toString()); - } - sb.append(" |
Command Line Params | ");
- for (int i=0; i < cmdLineParameters.size(); i++) {
- String param = cmdLineParameters.get(i);
- sb.append(" "); - sb.append(param); - sb.append(" "); + sb.append("Command Line Params:"); + sb.append(LINE_SEP); + for (String param : cmdLineParameters) { + sb.append(" ["); + sb.append(param); + sb.append("]"); + sb.append(LINE_SEP); + } + } else { + sb.append("Validity: [false]"); + sb.append(LINE_SEP); + sb.append("CGI script not found or not specified."); + sb.append(LINE_SEP); + sb.append("Check the HttpServletRequest pathInfo property to see if it is what "); + sb.append(LINE_SEP); + sb.append("you meant it to be. You must specify an existant and executable file "); + sb.append(LINE_SEP); + sb.append("as part of the path-info."); + sb.append(LINE_SEP); } - sb.append(" |
end.");
return sb.toString();
}
@@ -1421,16 +1310,16 @@
protected class CGIRunner {
/** script/command to be executed */
- private String command = null;
+ private final String command;
/** environment used when invoking the cgi script */
- private Hashtable
* This implements the following CGI specification recommedations:
+ *
*
*
- * query
" component of
* the script-URI as command-line arguments to scripts if it
@@ -1589,7 +1479,6 @@
* container's implementation of the Servlet API methods.
*
RequestFilterValve
that filters
@@ -32,14 +32,13 @@
*
* @author Craig R. McClanahan
*/
+public final class RemoteHostValve extends RequestFilterValve {
-public final class RemoteHostValve
- extends RequestFilterValve {
+ private static final Log log = LogFactory.getLog(RemoteHostValve.class);
// ----------------------------------------------------- Instance Variables
-
/**
* The descriptive information related to this implementation.
*/
@@ -93,23 +92,8 @@
// --------------------------------------------------------- Public Methods
-
- /**
- * Extract the desired request property, and pass it (along with the
- * specified request and response objects) to the protected
- * process()
method to perform the actual filtering.
- * This method must be implemented by a concrete subclass.
- *
- * @param request The servlet request to be processed
- * @param response The servlet response to be created
- *
- * @exception IOException if an input/output error occurs
- * @exception ServletException if a servlet error occurs
- */
@Override
- public void invoke(Request request, Response response)
- throws IOException, ServletException {
-
+ public void invoke(Request request, Response response) throws IOException, ServletException {
String property;
if (addConnectorPort) {
property = request.getRequest().getRemoteHost() + ";" + request.getConnector().getPort();
@@ -117,8 +101,11 @@
property = request.getRequest().getRemoteHost();
}
process(property, request, response);
-
}
+ @Override
+ protected Log getLog() {
+ return log;
+ }
}
diff -Nru tomcat7-7.0.70/java/org/apache/catalina/valves/RequestFilterValve.java tomcat7-7.0.72/java/org/apache/catalina/valves/RequestFilterValve.java
--- tomcat7-7.0.70/java/org/apache/catalina/valves/RequestFilterValve.java 2014-12-06 10:29:23.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/catalina/valves/RequestFilterValve.java 2016-06-16 13:02:31.000000000 +0000
@@ -27,6 +27,7 @@
import org.apache.catalina.LifecycleException;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
+import org.apache.juli.logging.Log;
/**
* Implementation of a Valve that performs filtering based on comparing the
@@ -335,12 +336,19 @@
return;
}
+ if (getLog().isDebugEnabled()) {
+ getLog().debug(sm.getString("requestFilterValve.deny",
+ request.getRequestURI(), property));
+ }
+
// Deny this request
denyRequest(request, response);
-
}
+ protected abstract Log getLog();
+
+
/**
* Reject the request that was denied by this valve.
* If Object factory for resource links.
+ *
* The data can be retrieved using
@@ -60,16 +60,16 @@
private int count;
/**
- * Creates a new byte array output stream. The buffer capacity is
- * initially 1024 bytes, though its size increases if necessary.
+ * Creates a new byte array output stream. The buffer capacity is
+ * initially 1024 bytes, though its size increases if necessary.
*/
public ByteArrayOutputStream() {
this(1024);
}
/**
- * Creates a new byte array output stream, with a buffer capacity of
- * the specified size, in bytes.
+ * Creates a new byte array output stream, with a buffer capacity of
+ * the specified size, in bytes.
*
* @param size the initial size
* @throws IllegalArgumentException if size is negative
@@ -94,7 +94,7 @@
if (currentBufferIndex < buffers.size() - 1) {
//Recycling old buffer
filledBufferSum += currentBuffer.length;
-
+
currentBufferIndex++;
currentBuffer = buffers.get(currentBufferIndex);
} else {
@@ -105,11 +105,11 @@
filledBufferSum = 0;
} else {
newBufferSize = Math.max(
- currentBuffer.length << 1,
+ currentBuffer.length << 1,
newcount - filledBufferSum);
filledBufferSum += currentBuffer.length;
}
-
+
currentBufferIndex++;
currentBuffer = new byte[newBufferSize];
buffers.add(currentBuffer);
@@ -124,10 +124,10 @@
*/
@Override
public void write(byte[] b, int off, int len) {
- if ((off < 0)
- || (off > b.length)
- || (len < 0)
- || ((off + len) > b.length)
+ if ((off < 0)
+ || (off > b.length)
+ || (len < 0)
+ || ((off + len) > b.length)
|| ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
@@ -236,7 +236,7 @@
public synchronized byte[] toByteArray() {
int remaining = count;
if (remaining == 0) {
- return EMPTY_BYTE_ARRAY;
+ return EMPTY_BYTE_ARRAY;
}
byte newbuf[] = new byte[remaining];
int pos = 0;
diff -Nru tomcat7-7.0.70/java/org/apache/tomcat/util/http/fileupload/DeferredFileOutputStream.java tomcat7-7.0.72/java/org/apache/tomcat/util/http/fileupload/DeferredFileOutputStream.java
--- tomcat7-7.0.70/java/org/apache/tomcat/util/http/fileupload/DeferredFileOutputStream.java 2014-01-27 12:17:29.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/tomcat/util/http/fileupload/DeferredFileOutputStream.java 2016-08-22 15:38:48.000000000 +0000
@@ -5,9 +5,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -204,8 +204,8 @@
{
return outputFile;
}
-
-
+
+
/**
* Closes underlying output stream, and mark this as closed
*
diff -Nru tomcat7-7.0.70/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java tomcat7-7.0.72/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java
--- tomcat7-7.0.70/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java 2014-01-27 12:17:29.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java 2016-08-22 15:38:48.000000000 +0000
@@ -18,7 +18,6 @@
import java.io.File;
-import org.apache.tomcat.util.http.fileupload.FileCleaningTracker;
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileItemFactory;
@@ -78,13 +77,6 @@
*/
private int sizeThreshold = DEFAULT_SIZE_THRESHOLD;
- /**
- * The instance of {@link FileCleaningTracker}, which is responsible
- * for deleting temporary files. May be null, if tracking files is not required.
+ * Note: Subclasses that override this method must ensure that they return the
+ * same File each time.
*
* @return The {@link java.io.File File} to be used for temporary storage.
*/
diff -Nru tomcat7-7.0.70/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java tomcat7-7.0.72/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java
--- tomcat7-7.0.70/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java 2014-01-27 12:17:29.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java 1970-01-01 00:00:00.000000000 +0000
@@ -1,198 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-import java.io.File;
-import java.lang.ref.PhantomReference;
-import java.lang.ref.ReferenceQueue;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-
-/**
- * Keeps track of files awaiting deletion, and deletes them when an associated
- * marker object is reclaimed by the garbage collector.
- *
- * This utility creates a background thread to handle file deletion.
- * Each file to be deleted is registered with a handler object.
- * When the handler object is garbage collected, the file is deleted.
- *
- * In an environment with multiple class loaders (a servlet container, for
- * example), you should consider stopping the background thread if it is no
- * longer needed. This is done by invoking the method
- * {@link #exitWhenFinished}, typically in
- * {@link javax.servlet.ServletContextListener#contextDestroyed} or similar.
- */
-public class FileCleaningTracker {
- /**
- * Queue of invalidAuthenticationWhenDeny
is true
diff -Nru tomcat7-7.0.70/java/org/apache/coyote/AbstractProcessor.java tomcat7-7.0.72/java/org/apache/coyote/AbstractProcessor.java
--- tomcat7-7.0.70/java/org/apache/coyote/AbstractProcessor.java 2015-04-01 12:57:59.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/coyote/AbstractProcessor.java 2016-08-11 18:57:23.000000000 +0000
@@ -40,6 +40,8 @@
protected Request request;
protected Response response;
protected SocketWrapper socketWrapper = null;
+ private int maxCookieCount = 200;
+
/**
* Error state for the request/response currently being processed.
@@ -207,7 +209,18 @@
@Override
public abstract SocketState upgradeDispatch() throws IOException;
- /**
+
+ public int getMaxCookieCount() {
+ return maxCookieCount;
+ }
+
+
+ public void setMaxCookieCount(int maxCookieCount) {
+ this.maxCookieCount = maxCookieCount;
+ }
+
+
+ /**
* @deprecated Will be removed in Tomcat 8.0.x.
*/
@Deprecated
diff -Nru tomcat7-7.0.70/java/org/apache/coyote/AbstractProtocol.java tomcat7-7.0.72/java/org/apache/coyote/AbstractProtocol.java
--- tomcat7-7.0.70/java/org/apache/coyote/AbstractProtocol.java 2016-06-03 15:41:38.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/coyote/AbstractProtocol.java 2016-08-11 18:57:23.000000000 +0000
@@ -86,6 +86,13 @@
protected AbstractEndpoint endpoint = null;
+ /**
+ * The maximum number of cookies permitted for a request. Use a value less
+ * than zero for no limit. Defaults to 200.
+ */
+ private int maxCookieCount = 200;
+
+
// ----------------------------------------------- Generic property handling
/**
@@ -156,6 +163,16 @@
}
+ public int getMaxCookieCount() {
+ return maxCookieCount;
+ }
+
+
+ public void setMaxCookieCount(int maxCookieCount) {
+ this.maxCookieCount = maxCookieCount;
+ }
+
+
// ---------------------- Properties that are passed through to the EndPoint
@Override
diff -Nru tomcat7-7.0.70/java/org/apache/coyote/ajp/AbstractAjpProcessor.java tomcat7-7.0.72/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
--- tomcat7-7.0.70/java/org/apache/coyote/ajp/AbstractAjpProcessor.java 2016-05-13 14:34:03.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/coyote/ajp/AbstractAjpProcessor.java 2016-08-11 18:57:23.000000000 +0000
@@ -766,6 +766,7 @@
// Set this every time in case limit has been changed via JMX
headers.setLimit(endpoint.getMaxHeaderCount());
+ request.getCookies().setLimit(getMaxCookieCount());
boolean contentLengthSet = false;
int hCount = requestHeaderMessage.getInt();
diff -Nru tomcat7-7.0.70/java/org/apache/coyote/ajp/AjpAprProtocol.java tomcat7-7.0.72/java/org/apache/coyote/ajp/AjpAprProtocol.java
--- tomcat7-7.0.70/java/org/apache/coyote/ajp/AjpAprProtocol.java 2016-01-27 11:42:26.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/coyote/ajp/AjpAprProtocol.java 2016-08-11 18:57:23.000000000 +0000
@@ -151,6 +151,7 @@
processor.setRequiredSecret(proto.requiredSecret);
processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
processor.setClientCertProvider(proto.getClientCertProvider());
+ processor.setMaxCookieCount(proto.getMaxCookieCount());
register(processor);
return processor;
}
diff -Nru tomcat7-7.0.70/java/org/apache/coyote/ajp/AjpNioProtocol.java tomcat7-7.0.72/java/org/apache/coyote/ajp/AjpNioProtocol.java
--- tomcat7-7.0.70/java/org/apache/coyote/ajp/AjpNioProtocol.java 2016-01-27 11:42:26.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/coyote/ajp/AjpNioProtocol.java 2016-08-11 18:57:23.000000000 +0000
@@ -181,6 +181,7 @@
processor.setRequiredSecret(proto.requiredSecret);
processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
processor.setClientCertProvider(proto.getClientCertProvider());
+ processor.setMaxCookieCount(proto.getMaxCookieCount());
register(processor);
return processor;
}
diff -Nru tomcat7-7.0.70/java/org/apache/coyote/ajp/AjpProtocol.java tomcat7-7.0.72/java/org/apache/coyote/ajp/AjpProtocol.java
--- tomcat7-7.0.70/java/org/apache/coyote/ajp/AjpProtocol.java 2016-01-27 11:42:26.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/coyote/ajp/AjpProtocol.java 2016-08-11 18:57:23.000000000 +0000
@@ -139,6 +139,7 @@
processor.setRequiredSecret(proto.requiredSecret);
processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
processor.setClientCertProvider(proto.getClientCertProvider());
+ processor.setMaxCookieCount(proto.getMaxCookieCount());
register(processor);
return processor;
}
diff -Nru tomcat7-7.0.70/java/org/apache/coyote/AsyncStateMachine.java tomcat7-7.0.72/java/org/apache/coyote/AsyncStateMachine.java
--- tomcat7-7.0.70/java/org/apache/coyote/AsyncStateMachine.java 2016-04-24 18:56:17.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/coyote/AsyncStateMachine.java 2016-09-05 14:33:45.000000000 +0000
@@ -26,32 +26,46 @@
/**
* Manages the state transitions for async requests.
- *
+ *
*
* The internal states that are used are:
- * DISPATCHED - Standard request. Not in Async mode.
- * STARTING - ServletRequest.startAsync() has been called but the
- * request in which that call was made has not finished
- * processing.
- * STARTED - ServletRequest.startAsync() has been called and the
- * request in which that call was made has finished
- * processing.
- * MUST_COMPLETE - complete() has been called before the request in which
- * ServletRequest.startAsync() has finished. As soon as that
- * request finishes, the complete() will be processed.
- * COMPLETING - The call to complete() was made once the request was in
- * the STARTED state. May or may not be triggered by a
- * container thread - depends if start(Runnable) was used
- * TIMING_OUT - The async request has timed out and is waiting for a call
- * to complete(). If that isn't made, the error state will
- * entered.
- * MUST_DISPATCH - dispatch() has been called from a container thread. The
- * dispatch will be processed once processing control returns to
- * the container.
- * DISPATCHING - dispatch() has been called from a non-container thread. The
- * dispatch will be processed as soon as a container thread is
- * available.
- * ERROR - Something went wrong.
+ * DISPATCHED - Standard request. Not in Async mode.
+ * STARTING - ServletRequest.startAsync() has been called but the
+ * request in which that call was made has not finished
+ * processing.
+ * STARTED - ServletRequest.startAsync() has been called and the
+ * request in which that call was made has finished
+ * processing.
+ * MUST_COMPLETE - ServletRequest.startAsync() followed by complete() have
+ * been called during a single Servlet.service() method. The
+ * complete() will be processed as soon as the request
+ * finishes.
+ * COMPLETE_PENDING - ServletRequest.startAsync() has been called and before the
+ * request in which that call was had finished processing,
+ * complete() was called for a non-container thread. The
+ * complete() will be processed as soon as the request
+ * finishes. This is different to MUST_COMPLETE because of
+ * differences required to avoid race conditions during error
+ * handling.
+ * COMPLETING - The call to complete() was made once the request was in
+ * the STARTED state. May or may not be triggered by a
+ * container thread - depends if start(Runnable) was used.
+ * TIMING_OUT - The async request has timed out and is waiting for a call
+ * to complete(). If that isn't made, the error state will
+ * entered.
+ * MUST_DISPATCH - ServletRequest.startAsync() followed by dispatch() have
+ * been called during a single Servlet.service() method. The
+ * dispatch() will be processed as soon as the request
+ * finishes.
+ * DISPATCH_PENDING - ServletRequest.startAsync() has been called and before the
+ * request in which that call was had finished processing,
+ * dispatch() was called for a non-container thread. The
+ * dispatch() will be processed as soon as the request
+ * finishes. This is different to MUST_DISPATCH because of
+ * differences required to avoid race conditions during error
+ * handling.
+ * DISPATCHING - The dispatch is being processed.
+ * ERROR - Something went wrong.
*
* |----------------->------|
* | \|/
@@ -62,39 +76,48 @@
* | | | | |dispatch()
* | | | | \|/
* | | | | |--|timeout() |
- * | | | postProcess() | | \|/ | auto
+ * | | | post() | | \|/ | post()
* | | | |---------- | -->DISPATCHED<---------- | --------------COMPLETING<-----|
- * | | | | | /|\ | | | /|\ |
- * | | | | |--->- | ---| | | |--| |
- * | | ^ ^ | | |startAsync() | timeout() |
- * | | | | | \ | | |
- * | | | | | \ | | |
- * | | | | | \ | | |
- * | | | | | \ | | |
- * | \|/ | | | \ \|/ postProcess() | |
- * | MUST_COMPLETE-<- | ----<------STARTING-->--------- | ------------| ^
- * | /|\ | | | | complete() |
- * | | | | | | /-----------|
- * | | ^ |dispatch() | | /
- * | | | | | | /
- * | | | \|/ | \|/ /
- * | | |----<----MUST_DISPATCH----<------| STARTED
- * | | | auto \ /|
- * | | | \ / |
- * ^ ^ ^ \ dispatch()/ |
- * | | | \ / |
- * | | | |-------- \ -------------/ |auto
- * | | | | \ |
- * | | | | \ |
- * | | | auto \|/ \ \|/
- * | | |---<------DISPATCHING \---------TIMING_OUT
- * | | dispatch() | |
+ * | | | | | /|\/|\ | | | /|\ /|\ |
+ * | | | | |--->- | ---| | |startAsync() | timeout()|--| | |
+ * | | ^ ^ | | | | | | |
+ * | | | | | |-- \ -----| | complete() | |post() |
+ * | | | | | | \ | /-->----- | ---COMPLETE_PENDING->-| |
+ * | | | | | | \ | / | |
+ * | | | | | ^ \ | / | |
+ * | \|/ | | | | \ \|/ / post() | |
+ * | MUST_COMPLETE-<- | - | --<----STARTING-->--------- | -------------| ^
+ * | /|\ | | complete() | \ | | complete() |
+ * | | | | | \ | post() | /----------|
+ * | | ^ | dispatch()| \ | |-----| | /
+ * | | | | | \ | | | | /
+ * | | | | \|/ \ | | \|/ \|/ /
+ * | | | |--<--MUST_DISPATCH-----<-----| |--<--STARTED
+ * | | | dispatched() /|\ | \ / |
+ * | | | | | \ / |
+ * | | | | | \ / |
+ * | | | | |post() \ | |
+ * ^ ^ | | | \|/ | |
+ * | | ^ | | DISPATCH_PENDING | |
+ * | | | | | |post() | |
+ * | | | | | | |----------| |
+ * | | | | | | | dispatch() |
+ * | | | | | | | |
+ * | | |post() | | | | timeout()|
+ * | | |dispatched() | \|/\|/ \|/ |
+ * | | |---<---------- | ---DISPATCHING |
+ * | | | | ^ |
+ * | | | |----| |
+ * | | | timeout() |
+ * | | | |
+ * | | | dispatch() \|/
+ * | | |-----------<-----------TIMING_OUT
* | | | |
* | |-------<----------------------------------<------| |
- * | complete() |
- * | |
- * |<--------<-------------------<-------------------------------<--|
- * error()
+ * | complete() |
+ * | |
+ * |<--------<-------------------<-------------------------------<--|
+ * error()
*
*/
public class AsyncStateMachine {
@@ -106,39 +129,39 @@
StringManager.getManager(Constants.Package);
private static enum AsyncState {
- DISPATCHED (false, false, false, false, false),
- STARTING (true, true, false, false, true),
- STARTED (true, true, false, false, false),
- MUST_COMPLETE(true, true, true, false, false),
- COMPLETING (true, false, true, false, false),
- TIMING_OUT (true, true, false, false, false),
- MUST_DISPATCH(true, true, false, true, true),
- DISPATCHING (true, false, false, true, false),
- ERROR (true, true, false, false, false);
-
+ DISPATCHED (false, false, false, false),
+ STARTING (true, true, false, false),
+ STARTED (true, true, false, false),
+ MUST_COMPLETE (true, true, true, false),
+ COMPLETE_PENDING(true, true, false, false),
+ COMPLETING (true, false, true, false),
+ TIMING_OUT (true, true, false, false),
+ MUST_DISPATCH (true, true, false, true),
+ DISPATCH_PENDING(true, true, false, false),
+ DISPATCHING (true, false, false, true),
+ ERROR (true, true, false, false);
+
private final boolean isAsync;
private final boolean isStarted;
private final boolean isCompleting;
private final boolean isDispatching;
- private final boolean pauseNonContainerThread;
private AsyncState(boolean isAsync, boolean isStarted, boolean isCompleting,
- boolean isDispatching, boolean pauseNonContainerThread) {
+ boolean isDispatching) {
this.isAsync = isAsync;
this.isStarted = isStarted;
this.isCompleting = isCompleting;
this.isDispatching = isDispatching;
- this.pauseNonContainerThread = pauseNonContainerThread;
}
-
+
public boolean isAsync() {
return isAsync;
}
-
+
public boolean isStarted() {
return isStarted;
}
-
+
public boolean isDispatching() {
return isDispatching;
}
@@ -146,19 +169,15 @@
public boolean isCompleting() {
return isCompleting;
}
-
- public boolean getPauseNonContainerThread() {
- return pauseNonContainerThread;
- }
}
-
+
private volatile AsyncState state = AsyncState.DISPATCHED;
// Need this to fire listener on complete
private AsyncContextCallback asyncCtxt = null;
private Processor processor;
-
-
+
+
public AsyncStateMachine(Processor processor) {
this.processor = processor;
}
@@ -198,21 +217,20 @@
"asyncStart()", state));
}
}
-
+
/*
* Async has been processed. Whether or not to enter a long poll depends on
* current state. For example, as per SRV.2.3.3.3 can now process calls to
* complete() or dispatch().
*/
public synchronized SocketState asyncPostProcess() {
-
- // Unpause any non-container threads that may be waiting for this
- // container thread to complete this method. Note because of the syncs
- // those non-container threads won't start back up until until this
- // method exits.
- notifyAll();
-
- if (state == AsyncState.STARTING) {
+ if (state == AsyncState.COMPLETE_PENDING) {
+ doComplete();
+ return SocketState.ASYNC_END;
+ } else if (state == AsyncState.DISPATCH_PENDING) {
+ doDispatch();
+ return SocketState.ASYNC_END;
+ } else if (state == AsyncState.STARTING) {
state = AsyncState.STARTED;
return SocketState.LONG;
} else if (state == AsyncState.MUST_COMPLETE) {
@@ -239,14 +257,23 @@
"asyncPostProcess()", state));
}
}
-
+
public synchronized boolean asyncComplete() {
- pauseNonContainerThread();
+ if (!ContainerThreadMarker.isContainerThread() && state == AsyncState.STARTING) {
+ state = AsyncState.COMPLETE_PENDING;
+ return false;
+ } else {
+ return doComplete();
+ }
+ }
+
+
+ private synchronized boolean doComplete() {
boolean doComplete = false;
if (state == AsyncState.STARTING) {
state = AsyncState.MUST_COMPLETE;
- } else if (state == AsyncState.STARTED) {
+ } else if (state == AsyncState.STARTED || state == AsyncState.COMPLETE_PENDING) {
state = AsyncState.COMPLETING;
doComplete = true;
} else if (state == AsyncState.TIMING_OUT ||
@@ -256,12 +283,12 @@
throw new IllegalStateException(
sm.getString("asyncStateMachine.invalidAsyncState",
"asyncComplete()", state));
-
+
}
return doComplete;
}
-
-
+
+
public synchronized boolean asyncTimeout() {
if (state == AsyncState.STARTED) {
state = AsyncState.TIMING_OUT;
@@ -278,10 +305,19 @@
"asyncTimeout()", state));
}
}
-
-
+
+
public synchronized boolean asyncDispatch() {
- pauseNonContainerThread();
+ if (!ContainerThreadMarker.isContainerThread() && state == AsyncState.STARTING) {
+ state = AsyncState.DISPATCH_PENDING;
+ return false;
+ } else {
+ return doDispatch();
+ }
+ }
+
+
+ private synchronized boolean doDispatch() {
boolean doDispatch = false;
if (state == AsyncState.STARTING ||
state == AsyncState.TIMING_OUT ||
@@ -289,7 +325,7 @@
// In these three cases processing is on a container thread so no
// need to transfer processing to a new container thread
state = AsyncState.MUST_DISPATCH;
- } else if (state == AsyncState.STARTED) {
+ } else if (state == AsyncState.STARTED || state == AsyncState.DISPATCH_PENDING) {
// A dispatch is always required.
// If on a non-container thread, need to get back onto a container
// thread to complete the processing.
@@ -305,8 +341,8 @@
}
return doDispatch;
}
-
-
+
+
public synchronized void asyncDispatched() {
if (state == AsyncState.DISPATCHING ||
state == AsyncState.MUST_DISPATCH) {
@@ -317,8 +353,8 @@
"asyncDispatched()", state));
}
}
-
-
+
+
public synchronized boolean asyncError() {
boolean doDispatch = false;
if (state == AsyncState.STARTING ||
@@ -333,7 +369,7 @@
}
return doDispatch;
}
-
+
public synchronized void asyncRun(Runnable runnable) {
if (state == AsyncState.STARTING || state == AsyncState.STARTED) {
// Execute the runnable using a container thread from the
@@ -354,7 +390,7 @@
Thread.currentThread().setContextClassLoader(
this.getClass().getClassLoader());
}
-
+
processor.getExecutor().execute(runnable);
} finally {
if (Constants.IS_SECURITY_ENABLED) {
@@ -372,8 +408,8 @@
}
}
-
-
+
+
public synchronized void recycle() {
// Ensure in case of error that any non-container threads that have been
// paused are unpaused.
@@ -381,24 +417,4 @@
asyncCtxt = null;
state = AsyncState.DISPATCHED;
}
-
-
- /*
- * startAsync() has been called but the container thread where this was
- * called has not completed processing. To avoid various race conditions -
- * including several related to error page handling - pause this
- * non-container thread until the container thread has finished processing.
- * The non-container thread will be paused until the container thread
- * completes asyncPostProcess().
- */
- private synchronized void pauseNonContainerThread() {
- while (!ContainerThreadMarker.isContainerThread() &&
- state.getPauseNonContainerThread()) {
- try {
- wait();
- } catch (InterruptedException e) {
- // TODO Log this?
- }
- }
- }
}
diff -Nru tomcat7-7.0.70/java/org/apache/coyote/http11/AbstractHttp11Processor.java tomcat7-7.0.72/java/org/apache/coyote/http11/AbstractHttp11Processor.java
--- tomcat7-7.0.70/java/org/apache/coyote/http11/AbstractHttp11Processor.java 2016-06-05 18:53:35.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/coyote/http11/AbstractHttp11Processor.java 2016-08-11 18:57:23.000000000 +0000
@@ -1007,6 +1007,7 @@
keptAlive = true;
// Set this every time in case limit has been changed via JMX
request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount());
+ request.getCookies().setLimit(getMaxCookieCount());
// Currently only NIO will ever return false here
if (!getInputBuffer().parseHeaders()) {
// We've read part of the request, don't recycle it
diff -Nru tomcat7-7.0.70/java/org/apache/coyote/http11/Http11AprProtocol.java tomcat7-7.0.72/java/org/apache/coyote/http11/Http11AprProtocol.java
--- tomcat7-7.0.70/java/org/apache/coyote/http11/Http11AprProtocol.java 2015-03-13 11:11:26.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/coyote/http11/Http11AprProtocol.java 2016-08-11 18:57:23.000000000 +0000
@@ -317,6 +317,7 @@
processor.setMaxSavePostSize(proto.getMaxSavePostSize());
processor.setServer(proto.getServer());
processor.setClientCertProvider(proto.getClientCertProvider());
+ processor.setMaxCookieCount(proto.getMaxCookieCount());
register(processor);
return processor;
}
diff -Nru tomcat7-7.0.70/java/org/apache/coyote/http11/Http11NioProtocol.java tomcat7-7.0.72/java/org/apache/coyote/http11/Http11NioProtocol.java
--- tomcat7-7.0.70/java/org/apache/coyote/http11/Http11NioProtocol.java 2016-04-11 16:12:04.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/coyote/http11/Http11NioProtocol.java 2016-08-11 18:57:23.000000000 +0000
@@ -281,6 +281,7 @@
processor.setSocketBuffer(proto.getSocketBuffer());
processor.setMaxSavePostSize(proto.getMaxSavePostSize());
processor.setServer(proto.getServer());
+ processor.setMaxCookieCount(proto.getMaxCookieCount());
register(processor);
return processor;
}
diff -Nru tomcat7-7.0.70/java/org/apache/coyote/http11/Http11Protocol.java tomcat7-7.0.72/java/org/apache/coyote/http11/Http11Protocol.java
--- tomcat7-7.0.70/java/org/apache/coyote/http11/Http11Protocol.java 2015-03-13 11:11:26.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/coyote/http11/Http11Protocol.java 2016-08-11 18:57:23.000000000 +0000
@@ -182,6 +182,7 @@
processor.setServer(proto.getServer());
processor.setDisableKeepAlivePercentage(
proto.getDisableKeepAlivePercentage());
+ processor.setMaxCookieCount(proto.getMaxCookieCount());
register(processor);
return processor;
}
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/compiler/Generator.java tomcat7-7.0.72/java/org/apache/jasper/compiler/Generator.java
--- tomcat7-7.0.70/java/org/apache/jasper/compiler/Generator.java 2015-11-02 13:23:54.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/compiler/Generator.java 2016-07-26 11:53:12.000000000 +0000
@@ -2335,6 +2335,10 @@
writeNewInstance(tagHandlerVar, tagHandlerClassName);
}
+ // Wrap use of tag in try/finally to ensure clean-up takes place
+ out.printil("try {");
+ out.pushIndent();
+
// includes setting the context
generateSetters(n, tagHandlerVar, handlerInfo, false);
@@ -2495,18 +2499,6 @@
out.print(tagHandlerVar);
out.println(".doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {");
out.pushIndent();
- if (!n.implementsTryCatchFinally()) {
- if (isPoolingEnabled && !(n.implementsJspIdConsumer())) {
- out.printin(n.getTagHandlerPoolName());
- out.print(".reuse(");
- out.print(tagHandlerVar);
- out.println(");");
- } else {
- out.printin(tagHandlerVar);
- out.println(".release();");
- writeDestroyInstance(tagHandlerVar);
- }
- }
if (isTagFile || isFragment) {
out.printil("throw new javax.servlet.jsp.SkipPageException();");
} else {
@@ -2539,6 +2531,15 @@
out.println(".doFinally();");
}
+ if (n.implementsTryCatchFinally()) {
+ out.popIndent();
+ out.printil("}");
+ }
+
+ // Ensure clean-up takes place
+ out.popIndent();
+ out.printil("} finally {");
+ out.pushIndent();
if (isPoolingEnabled && !(n.implementsJspIdConsumer())) {
out.printin(n.getTagHandlerPoolName());
out.print(".reuse(");
@@ -2549,11 +2550,8 @@
out.println(".release();");
writeDestroyInstance(tagHandlerVar);
}
-
- if (n.implementsTryCatchFinally()) {
- out.popIndent();
- out.printil("}");
- }
+ out.popIndent();
+ out.printil("}");
// Declare and synchronize AT_END scripting variables (must do this
// outside the try/catch/finally block)
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java tomcat7-7.0.72/java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java
--- tomcat7-7.0.70/java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java 2015-11-06 23:18:22.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java 2016-08-02 12:31:19.000000000 +0000
@@ -32,7 +32,7 @@
import org.apache.jasper.Constants;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
-import org.apache.jasper.util.ExceptionUtils;
+import org.apache.jasper.runtime.ExceptionUtils;
import org.apache.jasper.xmlparser.ParserUtils;
import org.apache.jasper.xmlparser.TreeNode;
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/compiler/JspReader.java tomcat7-7.0.72/java/org/apache/jasper/compiler/JspReader.java
--- tomcat7-7.0.70/java/org/apache/jasper/compiler/JspReader.java 2015-12-18 14:10:56.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/compiler/JspReader.java 2016-08-02 12:31:19.000000000 +0000
@@ -27,7 +27,7 @@
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
-import org.apache.jasper.util.ExceptionUtils;
+import org.apache.jasper.runtime.ExceptionUtils;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/compiler/JspRuntimeContext.java tomcat7-7.0.72/java/org/apache/jasper/compiler/JspRuntimeContext.java
--- tomcat7-7.0.70/java/org/apache/jasper/compiler/JspRuntimeContext.java 2016-04-27 11:14:52.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/compiler/JspRuntimeContext.java 2016-09-12 08:27:56.000000000 +0000
@@ -37,10 +37,10 @@
import org.apache.jasper.Constants;
import org.apache.jasper.JspCompilationContext;
import org.apache.jasper.Options;
+import org.apache.jasper.runtime.ExceptionUtils;
import org.apache.jasper.runtime.JspFactoryImpl;
import org.apache.jasper.security.SecurityClassLoad;
import org.apache.jasper.servlet.JspServletWrapper;
-import org.apache.jasper.util.ExceptionUtils;
import org.apache.jasper.util.FastRemovalDequeue;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
@@ -90,8 +90,6 @@
factory.getClass().getClassLoader().loadClass( basePackage +
"runtime.JspRuntimeLibrary");
factory.getClass().getClassLoader().loadClass( basePackage +
- "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper");
- factory.getClass().getClassLoader().loadClass( basePackage +
"runtime.ServletResponseWrapperInclude");
factory.getClass().getClassLoader().loadClass( basePackage +
"servlet.JspServletWrapper");
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/compiler/Localizer.java tomcat7-7.0.72/java/org/apache/jasper/compiler/Localizer.java
--- tomcat7-7.0.70/java/org/apache/jasper/compiler/Localizer.java 2014-01-27 13:35:02.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/compiler/Localizer.java 2016-08-02 12:31:19.000000000 +0000
@@ -21,7 +21,7 @@
import java.util.MissingResourceException;
import java.util.ResourceBundle;
-import org.apache.jasper.util.ExceptionUtils;
+import org.apache.jasper.runtime.ExceptionUtils;
/**
* Class responsible for converting error codes to corresponding localized
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/compiler/ParserController.java tomcat7-7.0.72/java/org/apache/jasper/compiler/ParserController.java
--- tomcat7-7.0.70/java/org/apache/jasper/compiler/ParserController.java 2015-11-06 23:18:22.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/compiler/ParserController.java 2016-08-02 12:31:19.000000000 +0000
@@ -25,7 +25,7 @@
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
-import org.apache.jasper.util.ExceptionUtils;
+import org.apache.jasper.runtime.ExceptionUtils;
import org.apache.jasper.xmlparser.XMLEncodingDetector;
import org.xml.sax.Attributes;
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java tomcat7-7.0.72/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java
--- tomcat7-7.0.70/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java 2016-06-06 13:34:45.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java 2016-08-02 12:31:19.000000000 +0000
@@ -47,7 +47,7 @@
import org.apache.jasper.Constants;
import org.apache.jasper.JasperException;
import org.apache.jasper.JspCompilationContext;
-import org.apache.jasper.util.ExceptionUtils;
+import org.apache.jasper.runtime.ExceptionUtils;
import org.apache.jasper.xmlparser.ParserUtils;
import org.apache.jasper.xmlparser.TreeNode;
import org.apache.juli.logging.Log;
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/compiler/TldLocationsCache.java tomcat7-7.0.72/java/org/apache/jasper/compiler/TldLocationsCache.java
--- tomcat7-7.0.70/java/org/apache/jasper/compiler/TldLocationsCache.java 2016-01-02 17:37:54.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/compiler/TldLocationsCache.java 2016-08-02 12:31:19.000000000 +0000
@@ -32,7 +32,7 @@
import org.apache.jasper.Constants;
import org.apache.jasper.JasperException;
-import org.apache.jasper.util.ExceptionUtils;
+import org.apache.jasper.runtime.ExceptionUtils;
import org.apache.jasper.xmlparser.ParserUtils;
import org.apache.jasper.xmlparser.TreeNode;
import org.apache.juli.logging.Log;
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/EmbeddedServletOptions.java tomcat7-7.0.72/java/org/apache/jasper/EmbeddedServletOptions.java
--- tomcat7-7.0.70/java/org/apache/jasper/EmbeddedServletOptions.java 2015-11-25 13:47:58.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/EmbeddedServletOptions.java 2016-08-30 22:45:07.000000000 +0000
@@ -650,6 +650,10 @@
* scratchdir
*/
String dir = config.getInitParameter("scratchdir");
+ if (dir != null && Constants.IS_SECURITY_ENABLED) {
+ log.info(Localizer.getMessage("jsp.info.ignoreSetting", "scratchdir", dir));
+ dir = null;
+ }
if (dir != null) {
scratchDir = new File(dir);
} else {
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/JspCompilationContext.java tomcat7-7.0.72/java/org/apache/jasper/JspCompilationContext.java
--- tomcat7-7.0.70/java/org/apache/jasper/JspCompilationContext.java 2015-04-23 12:59:53.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/JspCompilationContext.java 2016-08-31 11:29:27.000000000 +0000
@@ -111,7 +111,7 @@
this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1);
// hack fix for resolveRelativeURI
- if (baseURI == null) {
+ if (baseURI.isEmpty()) {
baseURI = "/";
} else if (baseURI.charAt(0) != '/') {
// strip the base slash since it will be combined with the
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/resources/LocalStrings.properties tomcat7-7.0.72/java/org/apache/jasper/resources/LocalStrings.properties
--- tomcat7-7.0.70/java/org/apache/jasper/resources/LocalStrings.properties 2016-06-06 13:34:45.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/resources/LocalStrings.properties 2016-08-30 22:45:07.000000000 +0000
@@ -457,6 +457,7 @@
jsp.error.invalid.bean=The value for the useBean class attribute {0} is invalid.
jsp.error.prefix.use_before_dcl=The prefix {0} specified in this tag directive has been previously used by an action in file {1} line {2}.
jsp.error.lastModified=Unable to determine last modified date for file [{0}]
+jsp.info.ignoreSetting=Ignored setting for [{0}] of [{1}] because a SecurityManager was enabled
jsp.exception=An exception occurred processing JSP page {0} at line {1}
@@ -473,6 +474,9 @@
jsp.error.page.conflict.trimdirectivewhitespaces=Page directive: illegal to have multiple occurrences of 'trimDirectiveWhitespaces' with different values (old: {0}, new: {1})
jsp.error.tag.conflict.trimdirectivewhitespaces=Tag directive: illegal to have multiple occurrences of 'trimDirectiveWhitespaces' with different values (old: {0}, new: {1})
+# JSP Servlet
+jsp.error.servlet.destroy.failed=Exception during Servlet.destroy() for JSP page
+
# JarScanner
jsp.warning.noJarScanner=Warning: No org.apache.tomcat.JarScanner set in ServletContext. Falling back to default JarScanner implementation.
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/runtime/ExceptionUtils.java tomcat7-7.0.72/java/org/apache/jasper/runtime/ExceptionUtils.java
--- tomcat7-7.0.70/java/org/apache/jasper/runtime/ExceptionUtils.java 1970-01-01 00:00:00.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/runtime/ExceptionUtils.java 2016-08-02 12:31:19.000000000 +0000
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jasper.runtime;
+
+import java.lang.reflect.InvocationTargetException;
+
+
+/**
+ * Utilities for handling Throwables and Exceptions.
+ */
+public class ExceptionUtils {
+
+ /**
+ * Checks whether the supplied Throwable is one that needs to be
+ * rethrown and swallows all others.
+ * @param t the Throwable to check
+ */
+ public static void handleThrowable(Throwable t) {
+ if (t instanceof ThreadDeath) {
+ throw (ThreadDeath) t;
+ }
+ if (t instanceof StackOverflowError) {
+ // Swallow silently - it should be recoverable
+ return;
+ }
+ if (t instanceof VirtualMachineError) {
+ throw (VirtualMachineError) t;
+ }
+ // All other instances of Throwable will be silently swallowed
+ }
+
+ /**
+ * Checks whether the supplied Throwable is an instance of
+ * InvocationTargetException
and returns the throwable that is
+ * wrapped by it, if there is any.
+ *
+ * @param t the Throwable to check
+ * @return t
or t.getCause()
+ */
+ public static Throwable unwrapInvocationTargetException(Throwable t) {
+ if (t instanceof InvocationTargetException && t.getCause() != null) {
+ return t.getCause();
+ }
+ return t;
+ }
+}
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/runtime/JspFactoryImpl.java tomcat7-7.0.72/java/org/apache/jasper/runtime/JspFactoryImpl.java
--- tomcat7-7.0.70/java/org/apache/jasper/runtime/JspFactoryImpl.java 2015-11-02 13:32:14.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/runtime/JspFactoryImpl.java 2016-08-02 12:31:19.000000000 +0000
@@ -29,7 +29,6 @@
import javax.servlet.jsp.PageContext;
import org.apache.jasper.Constants;
-import org.apache.jasper.util.ExceptionUtils;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
diff -Nru tomcat7-7.0.70/java/org/apache/jasper/runtime/JspRuntimeLibrary.java tomcat7-7.0.72/java/org/apache/jasper/runtime/JspRuntimeLibrary.java
--- tomcat7-7.0.70/java/org/apache/jasper/runtime/JspRuntimeLibrary.java 2015-12-28 01:12:43.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/jasper/runtime/JspRuntimeLibrary.java 2016-08-02 12:31:19.000000000 +0000
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.jasper.runtime;
import java.beans.PropertyEditor;
@@ -23,9 +22,6 @@
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
import java.util.Enumeration;
import javax.servlet.RequestDispatcher;
@@ -37,10 +33,8 @@
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyContent;
-import org.apache.jasper.Constants;
import org.apache.jasper.JasperException;
import org.apache.jasper.compiler.Localizer;
-import org.apache.jasper.util.ExceptionUtils;
/**
* Bunch of util methods that are used by code generated for useBean,
@@ -56,36 +50,6 @@
*/
public class JspRuntimeLibrary {
- protected static class PrivilegedIntrospectHelper
- implements PrivilegedExceptionActionInvocationTargetException
and returns the throwable that is
- * wrapped by it, if there is any.
- *
- * @param t the Throwable to check
- * @return t
or t.getCause()
- */
- public static Throwable unwrapInvocationTargetException(Throwable t) {
- if (t instanceof InvocationTargetException && t.getCause() != null) {
- return t.getCause();
- }
- return t;
- }
-}
diff -Nru tomcat7-7.0.70/java/org/apache/naming/ContextAccessController.java tomcat7-7.0.72/java/org/apache/naming/ContextAccessController.java
--- tomcat7-7.0.70/java/org/apache/naming/ContextAccessController.java 2014-05-13 14:15:06.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/naming/ContextAccessController.java 2016-08-02 12:20:10.000000000 +0000
@@ -49,9 +49,9 @@
/**
- * Set a security token for a context. Can be set only once.
+ * Set a security token for a Catalina context. Can be set only once.
*
- * @param name Name of the context
+ * @param name Name of the Catalina context
* @param token Security token
*/
public static void setSecurityToken(Object name, Object token) {
@@ -70,7 +70,7 @@
/**
* Remove a security token for a context.
*
- * @param name Name of the context
+ * @param name Name of the Catalina context
* @param token Security token
*/
public static void unsetSecurityToken(Object name, Object token) {
@@ -85,7 +85,7 @@
* the token present in the repository. If no token is present for the
* context, then returns true.
*
- * @param name Name of the context
+ * @param name Name of the Catalina context
* @param token Submitted security token
*/
public static boolean checkSecurityToken
@@ -98,7 +98,7 @@
/**
* Allow writing to a context.
*
- * @param name Name of the context
+ * @param name Name of the Catalina context
* @param token Security token
*/
public static void setWritable(Object name, Object token) {
@@ -108,9 +108,9 @@
/**
- * Set whether or not a context is writable.
+ * Set whether or not a Catalina context is writable.
*
- * @param name Name of the context
+ * @param name Name of the Catalina context
*/
public static void setReadOnly(Object name) {
readOnlyContexts.put(name, name);
@@ -120,7 +120,7 @@
/**
* Returns if a context is writable.
*
- * @param name Name of the context
+ * @param name Name of the Catalina context
*/
public static boolean isWritable(Object name) {
return !(readOnlyContexts.containsKey(name));
diff -Nru tomcat7-7.0.70/java/org/apache/naming/factory/ResourceLinkFactory.java tomcat7-7.0.72/java/org/apache/naming/factory/ResourceLinkFactory.java
--- tomcat7-7.0.70/java/org/apache/naming/factory/ResourceLinkFactory.java 2016-01-21 12:56:13.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/naming/factory/ResourceLinkFactory.java 2016-08-22 21:28:40.000000000 +0000
@@ -5,20 +5,21 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- */
-
-
+ */
package org.apache.naming.factory;
+import java.util.HashMap;
import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import javax.naming.Context;
import javax.naming.Name;
@@ -29,34 +30,28 @@
import org.apache.naming.ResourceLinkRef;
-
/**
* false
, otherwise
*/
public boolean isInAlphabet(final byte[] arrayOctet, final boolean allowWSPad) {
- for (int i = 0; i < arrayOctet.length; i++) {
- if (!isInAlphabet(arrayOctet[i]) &&
- (!allowWSPad || (arrayOctet[i] != PAD) && !isWhiteSpace(arrayOctet[i]))) {
+ for (byte octet : arrayOctet) {
+ if (!isInAlphabet(octet) &&
+ (!allowWSPad || (octet != PAD) && !isWhiteSpace(octet))) {
return false;
}
}
diff -Nru tomcat7-7.0.70/java/org/apache/tomcat/util/descriptor/InputSourceUtil.java tomcat7-7.0.72/java/org/apache/tomcat/util/descriptor/InputSourceUtil.java
--- tomcat7-7.0.70/java/org/apache/tomcat/util/descriptor/InputSourceUtil.java 1970-01-01 00:00:00.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/tomcat/util/descriptor/InputSourceUtil.java 2016-08-24 14:57:11.000000000 +0000
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.descriptor;
+
+import java.io.InputStream;
+
+import org.apache.tomcat.util.ExceptionUtils;
+import org.xml.sax.InputSource;
+
+public final class InputSourceUtil {
+
+ private InputSourceUtil() {
+ // Utility class. Hide default constructor.
+ }
+
+
+ public static void close(InputSource inputSource) {
+ if (inputSource == null) {
+ // Nothing to do
+ return;
+ }
+
+ InputStream is = inputSource.getByteStream();
+ if (is != null) {
+ try {
+ is.close();
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ }
+ }
+
+ }
+}
diff -Nru tomcat7-7.0.70/java/org/apache/tomcat/util/digester/Digester.java tomcat7-7.0.72/java/org/apache/tomcat/util/digester/Digester.java
--- tomcat7-7.0.70/java/org/apache/tomcat/util/digester/Digester.java 2015-04-01 11:10:53.000000000 +0000
+++ tomcat7-7.0.72/java/org/apache/tomcat/util/digester/Digester.java 2016-09-14 09:02:05.000000000 +0000
@@ -26,11 +26,13 @@
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.security.Permission;
import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.PropertyPermission;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
@@ -40,6 +42,7 @@
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.IntrospectionUtils;
+import org.apache.tomcat.util.security.PermissionCheck;
import org.xml.sax.Attributes;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
@@ -75,39 +78,26 @@
*/
public class Digester extends DefaultHandler2 {
-
- // ---------------------------------------------------------- Static Fields
- private static class SystemPropertySource
- implements IntrospectionUtils.PropertySource {
- @Override
- public String getProperty( String key ) {
- return System.getProperty(key);
- }
- }
- protected static IntrospectionUtils.PropertySource source[] =
- new IntrospectionUtils.PropertySource[] { new SystemPropertySource() };
-
+ // ---------------------------------------------------------- Static Fields
+
+ protected static IntrospectionUtils.PropertySource propertySource = null;
+
static {
String className = System.getProperty("org.apache.tomcat.util.digester.PROPERTY_SOURCE");
if (className!=null) {
- IntrospectionUtils.PropertySource[] sources = new IntrospectionUtils.PropertySource[2];
- sources[1] = source[0];
ClassLoader[] cls = new ClassLoader[] {Digester.class.getClassLoader(),Thread.currentThread().getContextClassLoader()};
- boolean initialized = false;
- for (int i=0; itoByteArray()
and
* toString()
.
* FileItem
instance;
* the file will be deleted when the instance is garbage collected.
+ * Tracker
instances being watched.
- */
- private final ReferenceQueue
The maximum number of cookies that are permitted for a request. A value + of less than zero means no limit. If not specified, a default value of 200 + will be used.
+The maximum number of request processing threads to be created by this Connector, which therefore determines the diff -Nru tomcat7-7.0.70/webapps/docs/config/context.xml tomcat7-7.0.72/webapps/docs/config/context.xml --- tomcat7-7.0.70/webapps/docs/config/context.xml 2016-05-20 11:10:18.000000000 +0000 +++ tomcat7-7.0.72/webapps/docs/config/context.xml 2016-07-27 15:58:11.000000000 +0000 @@ -334,6 +334,14 @@ sufficient.
Controls whether paths used in calls to obtain a request dispatcher
+ ares expected to be encoded. This affects both how Tomcat handles calls
+ to obtain a request dispatcher as well as how Tomcat generates paths
+ used to obtain request dispatchers internally. If not specified, the
+ default value of true
is used.
Set to true
to have the context fail its startup if any
servlet that has load-on-startup >=0 fails its own startup.
Some browsers, such as IE, will send a session cookie for a context
- with a path of /foo with a request to /foobar. To prevent this, Tomcat
- will add a trailing slash to the path associated with the session cookie
- so, in the above example, the cookie path becomes /foo/. However, with a
- cookie path of /foo/, IE will no longer send the cookie with a request
- to /foo. This should not be a problem unless there is a servlet mapped
- to /*. In this case this feature will need to be disabled. The default
- value for this attribute is true.
To disable this feature,
- set the attribute to false
.
Some browsers, such as Internet Explorer, Safari and Edge, will send
+ a session cookie for a context with a path of /foo
with a
+ request to /foobar
in violation of RFC6265. This could
+ expose a session ID from an application deployed at /foo
to
+ an application deployed at /foobar
. If the application
+ deployed at /foobar
is untrusted, this could create a
+ security risk. However, it should be noted that RFC 6265, section 8.5
+ makes clear that path alone should not be view as sufficient to prevent
+ untrusted applications accessing cookies from other applications. To
+ mitigate this risk, this attribute may bet ste to true
and
+ Tomcat will add a trailing slash to the path associated with the session
+ cookie so, in the above example, the cookie path becomes /foo/. However,
+ with a cookie path of /foo/, browsers will no longer send the cookie
+ with a request to /foo. This should not be a problem unless there is a
+ servlet mapped to /*. In this case this attribute will need to be set to
+ false
to disable this feature. The default value for this
+ attribute is false
.
The maximum number of cookies that are permitted for a request. A value + of less than zero means no limit. If not specified, a default value of 200 + will be used.
+Limits the total length of chunk extensions in chunked HTTP requests.
If the value is (bool)Boolean value, whether to use direct ByteBuffers or java mapped
- ByteBuffers. Default is Name of the file that contains the server certificate. The format is
PEM-encoded. In addition to the certificate, the file can also contain as optional
+ elements DH parameters and/or an EC curve name for ephemeral keys, as
+ generated by -1
, no limit will be imposed. If not
@@ -706,7 +712,11 @@
false
.
+ ByteBuffers. If true
then
+ java.nio.ByteBuffer.allocateDirect()
is used to allocate
+ the buffers, if false
then
+ java.nio.ByteBuffer.allocate()
is used. The default value
+ is false
.
When you are using direct buffers, make sure you allocate the
appropriate amount of memory for the direct memory space. On Sun's JDK
that would be something like -XX:MaxDirectMemorySize=256m
.
@@ -1248,6 +1258,12 @@
openssl dhparam
and openssl ecparam
,
+ respectively. The output of the respective OpenSSL command can simply
+ be concatenated to the certificate file. This feature needs APR/native
+ version 1.1.34 or later.
For more in-depth information about container managed security in web
applications, as well as more information on configuring and using the
@@ -172,7 +173,7 @@
The HTTP status code to use when the container needs to issue an HTTP
redirect to meet the requirements of a configured transport
- guarantee. The prpvoded status code is not validated. If not
+ guarantee. The provided status code is not validated. If not
specified, the default value of 302
is used.
The HTTP status code to use when the container needs to issue an HTTP
+ redirect to meet the requirements of a configured transport
+ guarantee. The provided status code is not validated. If not
+ specified, the default value of 302
is used.
When processing users authenticated via the GSS-API, this attribute controls if any "@..." is removed from the end of the user @@ -618,6 +626,13 @@ limit.
The HTTP status code to use when the container needs to issue an HTTP
+ redirect to meet the requirements of a configured transport
+ guarantee. The provided status code is not validated. If not
+ specified, the default value of 302
is used.
When the JNDIRealm is used with the SPNEGO authenticator, delegated credentials for the user may be available. If such credentials are @@ -762,6 +777,13 @@ that this realm will use for user, password and role information.
The HTTP status code to use when the container needs to issue an HTTP
+ redirect to meet the requirements of a configured transport
+ guarantee. The provided status code is not validated. If not
+ specified, the default value of 302
is used.
When using X509 client certificates, this specifies the class name
that will be used to retrieve the user name from the certificate.
@@ -830,6 +852,13 @@
name. If not specified, the default is true
.
The HTTP status code to use when the container needs to issue an HTTP
+ redirect to meet the requirements of a configured transport
+ guarantee. The provided status code is not validated. If not
+ specified, the default value of 302
is used.
When using X509 client certificates, this specifies the class name
that will be used to retrieve the user name from the certificate.
@@ -939,6 +968,13 @@
name. If not specified, the default is true
.
The HTTP status code to use when the container needs to issue an HTTP
+ redirect to meet the requirements of a configured transport
+ guarantee. The provided status code is not validated. If not
+ specified, the default value of 302
is used.
Instructs JAASRealm to use the context class loader for loading the
user-specified LoginModule
class and associated
@@ -1004,6 +1040,13 @@
one of those roles.
The HTTP status code to use when the container needs to issue an HTTP
+ redirect to meet the requirements of a configured transport
+ guarantee. The provided status code is not validated. If not
+ specified, the default value of 302
is used.
The time (in seconds) a user is locked out for after too many - authentication failures. Defaults to 300 (5 minutes).
+ authentication failures. Defaults to 300 (5 minutes). Further + authentication failures during the lock out time will cause the lock out + timer to reset to zero, effectively extending the lock out time. Valid + authentication attempts during the lock out period will not succeed but + will also not reset the lock out time. +The HTTP status code to use when the container needs to issue an HTTP
+ redirect to meet the requirements of a configured transport
+ guarantee. The provided status code is not validated. If not
+ specified, the default value of 302
is used.
NullRealm is a minimal implementation of the Tomcat
+ Realm
interface that always returns null when an attempt is
+ made to validate a user name and associated credentials. It is intended to
+ be used as a default Realm implementation when no other Realm is
+ specified.
The NullRealm implementation supports the following additional + attributes.
+ +The HTTP status code to use when the container needs to issue an HTTP
+ redirect to meet the requirements of a configured transport
+ guarantee. The provided status code is not validated. If not
+ specified, the default value of 302
is used.
This section displays information about Tomcat, the operating system of -the server Tomcat is hosted on, and the Java Virtual Machine Tomcat is -running in.
+This section displays information about Tomcat, the operating system of the +server Tomcat is hosted on, the Java Virtual Machine Tomcat is running in, the +primary host name of the server (may not be the host name used to access Tomcat) +and the primary IP address of the server (may not be the IP address used to +access Tomcat).
true
or false
, default
diff -Nru tomcat7-7.0.70/webapps/docs/manager-howto.xml tomcat7-7.0.72/webapps/docs/manager-howto.xml
--- tomcat7-7.0.70/webapps/docs/manager-howto.xml 2016-02-04 11:59:55.000000000 +0000
+++ tomcat7-7.0.72/webapps/docs/manager-howto.xml 2016-08-24 11:40:51.000000000 +0000
@@ -974,7 +974,7 @@
The JMX Proxy Servlet is a lightweight proxy to get and set the
tomcat internals. (Or any class that has been exposed via an MBean)
Its usage is not very user friendly but the UI is
- extremely help for integrating command line scripts for monitoring
+ extremely helpful for integrating command line scripts for monitoring
and changing the internals of tomcat. You can do two things with the proxy:
get information and set information. For you to really understand the
JMX Proxy Servlet, you should have a general understanding of JMX.
diff -Nru tomcat7-7.0.70/webapps/docs/mbeans-descriptor-howto.xml tomcat7-7.0.72/webapps/docs/mbeans-descriptor-howto.xml
--- tomcat7-7.0.70/webapps/docs/mbeans-descriptor-howto.xml 2014-01-26 22:13:11.000000000 +0000
+++ tomcat7-7.0.72/webapps/docs/mbeans-descriptor-howto.xml 1970-01-01 00:00:00.000000000 +0000
@@ -1,83 +0,0 @@
-
-
-
-]>
-Tomcat uses JMX MBeans as the technology for implementing -manageability of Tomcat.
- -The descriptions of JMX MBeans for Catalina are in the mbeans-descriptor.xml -file in each package.
- -You will need to add MBean descriptions for your custom components -in order to avoid a "ManagedBean is not found" exception.
- -You may also add MBean descriptions for custom components in -a mbeans-descriptor.xml file, located in the same package as the class files -it describes.
- - - - -Tomcat uses JMX MBeans as the technology for implementing +manageability of Tomcat.
+ +The descriptions of JMX MBeans for Catalina are in the mbeans-descriptors.xml +file in each package.
+ +You will need to add MBean descriptions for your custom components +in order to avoid a "ManagedBean is not found" exception.
+ +You may also add MBean descriptions for custom components in +a mbeans-descriptors.xml file, located in the same package as the class files +it describes.
+ + + + +org.apache.catalina.Realm
,Realm
's localDataSource
+ attribute appropriately, depending on where the JNDI DataSource is
+ defined.
<Realm>
element, as described below, in your
$CATALINA_BASE/conf/server.xml
file.The sessionCookiePathUsesTrailingSlash can be used to
+ work around a bug in a number of browsers (Internet Explorer, Safari and
+ Edge) to prevent session cookies being exposed across applications when
+ applications share a common path prefix. However, enabling this option
+ can create problems for applications with Servlets mapped to
+ /*
. It should also be noted the RFC6265 section 8.5 makes it
+ clear that different paths should not be considered sufficient to isolate
+ cookies from other applications.
If you are using the APR/native connector, starting with version 1.1.34
+ it will determine the strength of ephemeral DH keys from the key size of
+ your RSA certificate. For example a 2048 bit RSA key will result in
+ using a 2048 bit primefor the DH keys. Unfortunately Java 6 only supports
+ 768 bit and Java 7 only supports 1024 bit. So if your certificate has a
+ stronger key, old Java clients might produce such handshake failures.
+ As a mitigation you can either try to force them to use another cipher by
+ configuring an appropriate SSLCipherSuite
and activate
+ SSLHonorCipherOrder
, or embed weak DH params in your
+ certificate file. The latter approach is not recommended because it weakens
+ the SSL security (logjam attack).
If you are still having problems, a good source of information is the diff -Nru tomcat7-7.0.70/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java tomcat7-7.0.72/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java --- tomcat7-7.0.70/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java 2013-10-22 23:32:26.000000000 +0000 +++ tomcat7-7.0.72/webapps/examples/WEB-INF/classes/websocket/drawboard/DrawboardEndpoint.java 2016-06-22 12:57:30.000000000 +0000 @@ -17,6 +17,7 @@ package websocket.drawboard; import java.io.EOFException; +import java.io.IOException; import javax.websocket.CloseReason; import javax.websocket.Endpoint; @@ -153,6 +154,9 @@ if (root instanceof EOFException) { // Assume this is triggered by the user closing their browser and // ignore it. + } else if (!session.isOpen() && root instanceof IOException) { + // IOException after close. Assume this is a variation of the user + // closing their browser (or refreshing very quickly) and ignore it. } else { log.error("onError: " + t.toString(), t); } diff -Nru tomcat7-7.0.70/webapps/examples/websocket/drawboard.xhtml tomcat7-7.0.72/webapps/examples/websocket/drawboard.xhtml --- tomcat7-7.0.70/webapps/examples/websocket/drawboard.xhtml 2013-10-30 13:07:32.000000000 +0000 +++ tomcat7-7.0.72/webapps/examples/websocket/drawboard.xhtml 2016-06-22 12:55:30.000000000 +0000 @@ -864,7 +864,7 @@
This drawboard is a page where you can draw with your mouse or touch input