Skip to content
Commits on Source (4)
Apache Tomcat
Copyright 1999-2018 The Apache Software Foundation
Copyright 1999-2019 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (https://www.apache.org/).
......
......@@ -476,7 +476,7 @@ elif [ "$1" = "start" ] ; then
-Dcatalina.home="\"$CATALINA_HOME\"" \
-Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
org.apache.catalina.startup.Bootstrap "$@" start \
2\>\&1 \& echo \$! \>\"$catalina_pid_file\" \; \} $catalina_out_command "&"
2\>\&1 \&\& echo \$! \>\"$catalina_pid_file\" \; \} $catalina_out_command "&"
else
eval \{ $_NOHUP "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
......@@ -486,7 +486,7 @@ elif [ "$1" = "start" ] ; then
-Dcatalina.home="\"$CATALINA_HOME\"" \
-Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
org.apache.catalina.startup.Bootstrap "$@" start \
2\>\&1 \& echo \$! \>\"$catalina_pid_file\" \; \} $catalina_out_command "&"
2\>\&1 \&\& echo \$! \>\"$catalina_pid_file\" \; \} $catalina_out_command "&"
fi
......
......@@ -25,7 +25,7 @@
# ----- Version Control Flags -----
version.major=8
version.minor=5
version.build=37
version.build=38
version.patch=0
version.suffix=
......@@ -140,13 +140,13 @@ jdt.loc.1=http://archive.eclipse.org/eclipse/downloads/drops4/${jdt.release}/ecj
jdt.loc.2=http://download.eclipse.org/eclipse/downloads/drops4/${jdt.release}/ecj-${jdt.version}.jar
# ----- Tomcat native library -----
tomcat-native.version=1.2.19
tomcat-native.version=1.2.21
tomcat-native.src.checksum.enabled=true
tomcat-native.src.checksum.algorithm=SHA-512
tomcat-native.src.checksum.value=7d69acd5dd684eee9a85c08357b7288a9f083c15a12a9524ba6344f1b9dcdc6ccc512a37b64b9f15b0e697609833e6c68591a60976dcfecce124ec29eb532dba
tomcat-native.src.checksum.value=7f43f815785e5bc3e43f5b2e9ad1c90576a3c1528d57230328b7175bf475eb5f4e1f91b66fae74ad32cd76f044d7705f98a79109f6f84e5af75dc32bc8830b29
tomcat-native.win.checksum.enabled=true
tomcat-native.win.checksum.algorithm=SHA-512
tomcat-native.win.checksum.value=0b6349303b84632f4ce053e5ed1390571c17748f3527091936a197dcc9a686f768f913e86a431fe13dc7e0e1c3152fd13a5e501fbf95e82a096b27da6b942239
tomcat-native.win.checksum.value=bd5e7bb6584cba635d780216b87d453ecca5034235f018ba8a7429b82d653aa58cf26b89520c60271e10f242bd8a10fce401f362ecfe0fab597c7b6983ad97ce
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
......@@ -155,10 +155,10 @@ tomcat-native.win.1=${base-tomcat.loc.1}/tomcat-connectors/native/${tomcat-nativ
tomcat-native.win.2=${base-tomcat.loc.2}/tomcat-connectors/native/${tomcat-native.version}/binaries/tomcat-native-${tomcat-native.version}-openssl-1.1.1a-win32-bin.zip
# ----- NSIS, version 3.0 or later -----
nsis.version=3.03
nsis.version=3.04
nsis.checksum.enabled=true
nsis.checksum.algorithm=MD5|SHA-1
nsis.checksum.value=d4919dc089ec256a7264e97ada299b64|ea69aa8d538916c9e8630dfd0106b063f7bb5d46
nsis.checksum.value=434e89380742d415ca9b91676cb92540|ed241f7384f4e59d84b9a62c71d1f6955b6a719a
nsis.home=${base.path}/nsis-${nsis.version}
nsis.exe=${nsis.home}/makensis.exe
nsis.arch.dir=x86-unicode/
......
......@@ -1231,7 +1231,6 @@
<exclude name="security/protected/error.jsp"/>
<exclude name="security/protected/index.jsp"/>
<exclude name="security/protected/login.jsp"/>
<exclude name="source.jsp"/>
</fileset>
</txt2html>
</target>
......
tomcat8 (8.5.38-1) unstable; urgency=medium
* Team upload.
* New upstream release
- Refreshed the patches
-- Emmanuel Bourg <ebourg@apache.org> Fri, 08 Feb 2019 15:27:17 +0100
tomcat8 (8.5.37-2) unstable; urgency=medium
* Team upload.
......
......@@ -3,7 +3,7 @@ Author: Emmanuel Bourg <ebourg@apache.org>
Forwarded: not-needed
--- a/build.xml
+++ b/build.xml
@@ -1398,8 +1398,10 @@
@@ -1397,8 +1397,10 @@
</filterchain>
</concat>
......
......@@ -164,6 +164,7 @@ public class ImportHandler {
javaLangClassNames.add("Compiler");
javaLangClassNames.add("Double");
javaLangClassNames.add("Enum");
javaLangClassNames.add("Enum.EnumDesc");
javaLangClassNames.add("Float");
javaLangClassNames.add("InheritableThreadLocal");
javaLangClassNames.add("Integer");
......
......@@ -55,9 +55,12 @@ public abstract class ServletOutputStream extends OutputStream {
* if an input or output exception occurred
*/
public void print(String s) throws IOException {
if (s == null)
if (s == null) {
s = "null";
}
int len = s.length();
byte[] buffer = new byte[len];
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
......@@ -74,8 +77,9 @@ public abstract class ServletOutputStream extends OutputStream {
errMsg = MessageFormat.format(errMsg, errArgs);
throw new CharConversionException(errMsg);
}
write(c);
buffer[i] = (byte) (c & 0xFF);
}
write(buffer);
}
/**
......@@ -182,8 +186,10 @@ public abstract class ServletOutputStream extends OutputStream {
* if an input or output exception occurred
*/
public void println(String s) throws IOException {
print(s);
println();
StringBuilder sb = new StringBuilder();
sb.append(s);
sb.append("\r\n");
print(sb.toString());
}
/**
......@@ -196,8 +202,14 @@ public abstract class ServletOutputStream extends OutputStream {
* if an input or output exception occurred
*/
public void println(boolean b) throws IOException {
print(b);
println();
StringBuilder sb = new StringBuilder();
if (b) {
sb.append(lStrings.getString("value.true"));
} else {
sb.append(lStrings.getString("value.false"));
}
sb.append("\r\n");
print(sb.toString());
}
/**
......@@ -210,8 +222,7 @@ public abstract class ServletOutputStream extends OutputStream {
* if an input or output exception occurred
*/
public void println(char c) throws IOException {
print(c);
println();
println(String.valueOf(c));
}
/**
......@@ -224,8 +235,7 @@ public abstract class ServletOutputStream extends OutputStream {
* if an input or output exception occurred
*/
public void println(int i) throws IOException {
print(i);
println();
println(String.valueOf(i));
}
/**
......@@ -238,8 +248,7 @@ public abstract class ServletOutputStream extends OutputStream {
* if an input or output exception occurred
*/
public void println(long l) throws IOException {
print(l);
println();
println(String.valueOf(l));
}
/**
......@@ -252,8 +261,7 @@ public abstract class ServletOutputStream extends OutputStream {
* if an input or output exception occurred
*/
public void println(float f) throws IOException {
print(f);
println();
println(String.valueOf(f));
}
/**
......@@ -266,8 +274,7 @@ public abstract class ServletOutputStream extends OutputStream {
* if an input or output exception occurred
*/
public void println(double d) throws IOException {
print(d);
println();
println(String.valueOf(d));
}
/**
......
......@@ -17,6 +17,8 @@
package javax.websocket.server;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
......@@ -150,7 +152,12 @@ public interface ServerEndpointConfig extends EndpointConfig {
if (defaultImpl == null) {
synchronized (defaultImplLock) {
if (defaultImpl == null) {
if (System.getSecurityManager() == null) {
defaultImpl = loadDefault();
} else {
defaultImpl =
AccessController.doPrivileged(new PrivilegedLoadDefault());
}
}
}
}
......@@ -186,6 +193,16 @@ public interface ServerEndpointConfig extends EndpointConfig {
return result;
}
private static class PrivilegedLoadDefault implements PrivilegedAction<Configurator> {
@Override
public Configurator run() {
return Configurator.loadDefault();
}
}
public String getNegotiatedSubprotocol(List<String> supported,
List<String> requested) {
return fetchContainerDefaultConfigurator().getNegotiatedSubprotocol(supported, requested);
......
......@@ -398,14 +398,16 @@ public interface Context extends Container, ContextBind {
/**
* Obtain the document root for this Context.
*
* @return An absolute pathname, a relative pathname, or a URL.
* @return An absolute pathname or a relative (to the Host's appBase)
* pathname.
*/
public String getDocBase();
/**
* Set the document root for this Context. This can be an absolute
* pathname, a relative pathname, or a URL.
* Set the document root for this Context. This can be either an absolute
* pathname or a relative pathname. Relative pathnames are relative to the
* containing Host's appBase.
*
* @param docBase The new document root
*/
......@@ -1868,4 +1870,10 @@ public interface Context extends Container, ContextBind {
* otherwise <code>false</code>
*/
public boolean getAllowMultipleLeadingForwardSlashInPath();
public void incrementInProgressAsyncCount();
public void decrementInProgressAsyncCount();
}
......@@ -44,6 +44,7 @@ public class BasicAuthenticator extends AuthenticatorBase {
private Charset charset = StandardCharsets.ISO_8859_1;
private String charsetString = null;
private boolean trimCredentials = true;
public String getCharset() {
......@@ -64,6 +65,17 @@ public class BasicAuthenticator extends AuthenticatorBase {
}
public boolean getTrimCredentials() {
return trimCredentials;
}
public void setTrimCredentials(boolean trimCredentials) {
this.trimCredentials = trimCredentials;
}
@Override
protected boolean doAuthenticate(Request request, HttpServletResponse response)
throws IOException {
......@@ -82,7 +94,7 @@ public class BasicAuthenticator extends AuthenticatorBase {
ByteChunk authorizationBC = authorization.getByteChunk();
BasicCredentials credentials = null;
try {
credentials = new BasicCredentials(authorizationBC, charset);
credentials = new BasicCredentials(authorizationBC, charset, getTrimCredentials());
String username = credentials.getUsername();
String password = credentials.getPassword();
......@@ -133,6 +145,7 @@ public class BasicAuthenticator extends AuthenticatorBase {
private static final String METHOD = "basic ";
private final Charset charset;
private final boolean trimCredentials;
private final ByteChunk authorization;
private final int initialOffset;
private int base64blobOffset;
......@@ -140,6 +153,7 @@ public class BasicAuthenticator extends AuthenticatorBase {
private String username = null;
private String password = null;
/**
* Parse the HTTP Authorization header for BASIC authentication
* as per RFC 2617 section 2, and the Base64 encoded credentials
......@@ -151,11 +165,33 @@ public class BasicAuthenticator extends AuthenticatorBase {
*
* @throws IllegalArgumentException If the header does not conform
* to RFC 2617
* @deprecated Unused. Will be removed in Tomcat 10. Use 3-arg constructor
*/
@Deprecated
public BasicCredentials(ByteChunk input, Charset charset) throws IllegalArgumentException {
this(input, charset, true);
}
/**
* Parse the HTTP Authorization header for BASIC authentication
* as per RFC 2617 section 2, and the Base64 encoded credentials
* as per RFC 2045 section 6.8.
*
* @param input The header value to parse in-place
* @param charset The character set to use to convert the bytes
* to a string
* @param trimCredentials Should leading and trailing whitespace be
* removed from the parsed credentials
*
* @throws IllegalArgumentException If the header does not conform
* to RFC 2617
*/
public BasicCredentials(ByteChunk input, Charset charset, boolean trimCredentials)
throws IllegalArgumentException {
authorization = input;
initialOffset = input.getOffset();
this.charset = charset;
this.trimCredentials = trimCredentials;
parseMethod();
byte[] decoded = parseBase64();
......@@ -240,12 +276,12 @@ public class BasicAuthenticator extends AuthenticatorBase {
username = new String(decoded, 0, colon, charset);
password = new String(decoded, colon + 1, decoded.length - colon - 1, charset);
// tolerate surplus white space around credentials
if (password.length() > 1) {
if (password.length() > 1 && trimCredentials) {
password = password.trim();
}
}
// tolerate surplus white space around credentials
if (username.length() > 1) {
if (username.length() > 1 && trimCredentials) {
username = username.trim();
}
}
......
......@@ -64,6 +64,10 @@
description="The name of the LifecycleState that this component is currently in"
type="java.lang.String"
writeable="false"/>
<attribute name="trimCredentials"
description="Controls whether leading and/or trailing whitespace is removed from the parsed credentials"
type="boolean"/>
</mbean>
......
......@@ -340,9 +340,13 @@ public class InputBuffer extends Reader
state = BYTE_STATE;
}
int result = coyoteRequest.doRead(this);
return result;
try {
return coyoteRequest.doRead(this);
} catch (IOException ioe) {
// An IOException on a read is almost always due to
// the remote client aborting the request.
throw new ClientAbortException(ioe);
}
}
......
......@@ -33,6 +33,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.Globals;
import org.apache.coyote.ActionCode;
import org.apache.coyote.CloseNowException;
import org.apache.coyote.Response;
import org.apache.tomcat.util.buf.B2CConverter;
import org.apache.tomcat.util.buf.C2BConverter;
......@@ -349,6 +350,13 @@ public class OutputBuffer extends Writer {
// real write to the adapter
try {
coyoteResponse.doWrite(buf);
} catch (CloseNowException e) {
// Catch this sub-class as it requires specific handling.
// Examples where this exception is thrown:
// - HTTP/2 stream timeout
// Prevent further output for this response
closed = true;
throw e;
} catch (IOException e) {
// An IOException on a write is almost always due to
// the remote client aborting the request. Wrap this
......
......@@ -34,7 +34,6 @@ import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
......@@ -183,37 +182,6 @@ public class Response implements HttpServletResponse {
*/
private boolean isCharacterEncodingSet = false;
/**
* With the introduction of async processing and the possibility of
* non-container threads calling sendError() tracking the current error
* state and ensuring that the correct error page is called becomes more
* complicated. This state attribute helps by tracking the current error
* state and informing callers that attempt to change state if the change
* was successful or if another thread got there first.
*
* <pre>
* The state machine is very simple:
*
* 0 - NONE
* 1 - NOT_REPORTED
* 2 - REPORTED
*
*
* -->---->-- >NONE
* | | |
* | | | setError()
* ^ ^ |
* | | \|/
* | |-<-NOT_REPORTED
* | |
* ^ | report()
* | |
* | \|/
* |----<----REPORTED
* </pre>
*/
private final AtomicInteger errorState = new AtomicInteger(0);
/**
* Using output stream flag.
......@@ -262,7 +230,6 @@ public class Response implements HttpServletResponse {
usingWriter = false;
appCommitted = false;
included = false;
errorState.set(0);
isCharacterEncodingSet = false;
applicationResponse = null;
......@@ -442,7 +409,7 @@ public class Response implements HttpServletResponse {
* @return <code>false</code> if the error flag was already set
*/
public boolean setError() {
boolean result = errorState.compareAndSet(0, 1);
boolean result = getCoyoteResponse().setError();
if (result) {
Wrapper wrapper = getRequest().getWrapper();
if (wrapper != null) {
......@@ -459,17 +426,17 @@ public class Response implements HttpServletResponse {
* @return <code>true</code> if the response has encountered an error
*/
public boolean isError() {
return errorState.get() > 0;
return getCoyoteResponse().isError();
}
public boolean isErrorReportRequired() {
return errorState.get() == 1;
return getCoyoteResponse().isErrorReportRequired();
}
public boolean setErrorReported() {
return errorState.compareAndSet(1, 2);
return getCoyoteResponse().setErrorReported();
}
......
......@@ -68,7 +68,7 @@ public class AprLifecycleListener
protected static final int TCN_REQUIRED_MINOR = 2;
protected static final int TCN_REQUIRED_PATCH = 14;
protected static final int TCN_RECOMMENDED_MINOR = 2;
protected static final int TCN_RECOMMENDED_PV = 19;
protected static final int TCN_RECOMMENDED_PV = 21;
// ---------------------------------------------- Properties
......
......@@ -115,6 +115,7 @@ public class AsyncContextImpl implements AsyncContext, AsyncContextCallback {
} finally {
context.fireRequestDestroyEvent(request.getRequest());
clearServletRequestResponse();
this.context.decrementInProgressAsyncCount();
context.unbind(Globals.IS_SECURITY_ENABLED, oldCL);
}
}
......@@ -209,6 +210,7 @@ public class AsyncContextImpl implements AsyncContext, AsyncContextCallback {
request, applicationDispatcher, servletRequest, servletResponse);
this.request.getCoyoteRequest().action(ActionCode.ASYNC_DISPATCH, null);
clearServletRequestResponse();
this.context.decrementInProgressAsyncCount();
}
}
......@@ -317,6 +319,7 @@ public class AsyncContextImpl implements AsyncContext, AsyncContextCallback {
ActionCode.ASYNC_START, this);
this.context = context;
context.incrementInProgressAsyncCount();
this.servletRequest = request;
this.servletResponse = response;
this.hasOriginalRequestAndResponse = originalRequestResponse;
......@@ -383,6 +386,17 @@ public class AsyncContextImpl implements AsyncContext, AsyncContextCallback {
}
@Override
public boolean isAvailable() {
Context context = this.context;
if (context == null) {
return false;
}
return context.getState().isAvailable();
}
public void setErrorState(Throwable t, boolean fireOnError) {
if (t!=null) request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
request.getCoyoteRequest().action(ActionCode.ASYNC_ERROR, null);
......
......@@ -177,6 +177,7 @@ standardContext.servletMap.name=Servlet mapping specifies an unknown servlet nam
standardContext.servletMap.pattern=Invalid <url-pattern> [{0}] in servlet mapping
standardContext.startFailed=Context [{0}] startup failed due to previous errors
standardContext.startingContext=Exception starting Context with name [{0}]
standardContext.stop.asyncWaitInterrupted=Interrupt received while waiting unloadDelay milliseconds for in-flight asynchronous requests to complete. Context stop will continue without further delay.
standardContext.stoppingContext=Exception stopping Context with name [{0}]
standardContext.threadBindingListenerError=An error occurred in the thread binding listener configured for Context [{0}]
standardContext.unknownCookieEncoding=The unknown encoding [{0}] was specified for setCookieEncoding(String) so the default of UTF-8 will be used instead
......
......@@ -829,9 +829,23 @@ public class StandardContext extends ContainerBase
private boolean allowMultipleLeadingForwardSlashInPath = false;
private final AtomicLong inProgressAsyncCount = new AtomicLong(0);
// ----------------------------------------------------- Context Properties
@Override
public void incrementInProgressAsyncCount() {
inProgressAsyncCount.incrementAndGet();
}
@Override
public void decrementInProgressAsyncCount() {
inProgressAsyncCount.decrementAndGet();
}
@Override
public void setAllowMultipleLeadingForwardSlashInPath(
boolean allowMultipleLeadingForwardSlashInPath) {
......@@ -1763,10 +1777,6 @@ public class StandardContext extends ContainerBase
}
/**
* @return the document root for this Context. This can be an absolute
* pathname, a relative pathname, or a URL.
*/
@Override
public String getDocBase() {
......@@ -1775,12 +1785,6 @@ public class StandardContext extends ContainerBase
}
/**
* Set the document root for this Context. This can be an absolute
* pathname, a relative pathname, or a URL.
*
* @param docBase The new document root
*/
@Override
public void setDocBase(String docBase) {
......@@ -1788,6 +1792,7 @@ public class StandardContext extends ContainerBase
}
public String getJ2EEApplication() {
return j2EEApplication;
}
......@@ -5472,6 +5477,22 @@ public class StandardContext extends ContainerBase
broadcaster.sendNotification(notification);
}
// Context has been removed from Mapper at this point (so no new
// requests will be mapped) but is still available.
// Give the in progress async requests a chance to complete
long limit = System.currentTimeMillis() + unloadDelay;
while (inProgressAsyncCount.get() > 0 && System.currentTimeMillis() < limit) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
log.info(sm.getString("standardContext.stop.asyncWaitInterrupted"), e);
break;
}
}
// Once the state is set to STOPPING, the Context will report itself as
// not available and any in progress async requests will timeout
setState(LifecycleState.STOPPING);
// Binding thread
......
......@@ -36,6 +36,7 @@ import org.apache.catalina.connector.ClientAbortException;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
import org.apache.coyote.CloseNowException;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.log.SystemLogHandler;
......@@ -201,7 +202,12 @@ final class StandardWrapperValve
}
}
} catch (ClientAbortException e) {
} catch (ClientAbortException | CloseNowException e) {
if (container.getLogger().isDebugEnabled()) {
container.getLogger().debug(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
}
throwable = e;
exception(request, response, e);
} catch (IOException e) {
......