Compare commits
10 Commits
3cc5783c92
...
665dcc13f8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
665dcc13f8 | ||
|
|
f1986b1f50 | ||
|
|
443db40922 | ||
|
|
3b62a74c8f | ||
|
|
bed19cdd54 | ||
|
|
83ef3afbd3 | ||
|
|
3d18fb8a4f | ||
|
|
b63424bbab | ||
|
|
740390ce3e | ||
|
|
9ea4787224 |
127
CVE-2022-42252.patch
Normal file
127
CVE-2022-42252.patch
Normal file
@ -0,0 +1,127 @@
|
||||
diff -upr tomcat-9.0.10_back/java/org/apache/coyote/http11/Http11InputBuffer.java tomcat-9.0.10/java/org/apache/coyote/http11/Http11InputBuffer.java
|
||||
--- tomcat-9.0.10_back/java/org/apache/coyote/http11/Http11InputBuffer.java 2022-12-14 10:39:12.917000000 +0800
|
||||
+++ tomcat-9.0.10/java/org/apache/coyote/http11/Http11InputBuffer.java 2022-12-14 10:48:31.180863424 +0800
|
||||
@@ -821,7 +821,7 @@ public class Http11InputBuffer implement
|
||||
headerData.lastSignificantChar = pos;
|
||||
byteBuffer.position(byteBuffer.position() - 1);
|
||||
// skipLine() will handle the error
|
||||
- return skipLine();
|
||||
+ return skipLine(false);
|
||||
}
|
||||
|
||||
// chr is next byte of header name. Convert to lowercase.
|
||||
@@ -832,7 +832,7 @@ public class Http11InputBuffer implement
|
||||
|
||||
// Skip the line and ignore the header
|
||||
if (headerParsePos == HeaderParsePosition.HEADER_SKIPLINE) {
|
||||
- return skipLine();
|
||||
+ return skipLine(false);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -883,15 +883,11 @@ public class Http11InputBuffer implement
|
||||
} else if (prevChr == Constants.CR && chr == Constants.LF) {
|
||||
eol = true;
|
||||
} else if (prevChr == Constants.CR) {
|
||||
- // Invalid value
|
||||
- // Delete the header (it will be the most recent one)
|
||||
- headers.removeHeader(headers.size() - 1);
|
||||
- return skipLine();
|
||||
+ // Invalid value - also need to delete header
|
||||
+ return skipLine(true);
|
||||
} else if (chr != Constants.HT && HttpParser.isControl(chr)) {
|
||||
- // Invalid value
|
||||
- // Delete the header (it will be the most recent one)
|
||||
- headers.removeHeader(headers.size() - 1);
|
||||
- return skipLine();
|
||||
+ // Invalid value - also need to delete header
|
||||
+ return skipLine(true);
|
||||
} else if (chr == Constants.SP || chr == Constants.HT) {
|
||||
byteBuffer.put(headerData.realPos, chr);
|
||||
headerData.realPos++;
|
||||
@@ -939,7 +935,27 @@ public class Http11InputBuffer implement
|
||||
}
|
||||
|
||||
|
||||
- private HeaderParseStatus skipLine() throws IOException {
|
||||
+ private HeaderParseStatus skipLine(boolean deleteHeader) throws IOException {
|
||||
+ boolean rejectThisHeader = rejectIllegalHeader;
|
||||
+ // Check if rejectIllegalHeader is disabled and needs to be overridden
|
||||
+ // for this header. The header name is required to determine if this
|
||||
+ // override is required. The header name is only available once the
|
||||
+ // header has been created. If the header has been created then
|
||||
+ // deleteHeader will be true.
|
||||
+ if (!rejectThisHeader && deleteHeader) {
|
||||
+ if (headers.getName(headers.size() - 1).equalsIgnoreCase("content-length")) {
|
||||
+ // Malformed content-length headers must always be rejected
|
||||
+ // RFC 9112, section 6.3, bullet 5.
|
||||
+ rejectThisHeader = true;
|
||||
+ } else {
|
||||
+ // Only need to delete the header if the request isn't going to
|
||||
+ // be rejected (it will be the most recent one)
|
||||
+ headers.removeHeader(headers.size() - 1);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Parse the rest of the invalid header so we can construct a useful
|
||||
+ // exception and/or debug message.
|
||||
headerParsePos = HeaderParsePosition.HEADER_SKIPLINE;
|
||||
boolean eol = false;
|
||||
|
||||
@@ -967,12 +983,12 @@ public class Http11InputBuffer implement
|
||||
headerData.lastSignificantChar = pos;
|
||||
}
|
||||
}
|
||||
- if (rejectIllegalHeader || log.isDebugEnabled()) {
|
||||
+ if (rejectThisHeader || log.isDebugEnabled()) {
|
||||
String message = sm.getString("iib.invalidheader",
|
||||
new String(byteBuffer.array(), headerData.start,
|
||||
headerData.lastSignificantChar - headerData.start + 1,
|
||||
StandardCharsets.ISO_8859_1));
|
||||
- if (rejectIllegalHeader) {
|
||||
+ if (rejectThisHeader) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
log.debug(message);
|
||||
diff -upr tomcat-9.0.10_back/test/org/apache/coyote/http11/TestHttp11InputBuffer.java tomcat-9.0.10/test/org/apache/coyote/http11/TestHttp11InputBuffer.java
|
||||
--- tomcat-9.0.10_back/test/org/apache/coyote/http11/TestHttp11InputBuffer.java 2022-12-14 10:39:12.971000000 +0800
|
||||
+++ tomcat-9.0.10/test/org/apache/coyote/http11/TestHttp11InputBuffer.java 2022-12-14 10:51:16.845501479 +0800
|
||||
@@ -643,6 +643,38 @@ public class TestHttp11InputBuffer exten
|
||||
Assert.assertTrue(client.isResponseBodyOK());
|
||||
}
|
||||
|
||||
+ @Test
|
||||
+ public void testInvalidContentLength01() {
|
||||
+ doTestInvalidContentLength(false);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ @Test
|
||||
+ public void testInvalidContentLength02() {
|
||||
+ doTestInvalidContentLength(true);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ private void doTestInvalidContentLength(boolean rejectIllegalHeader) {
|
||||
+ getTomcatInstance().getConnector().setProperty("rejectIllegalHeader", Boolean.toString(rejectIllegalHeader));
|
||||
+
|
||||
+ String[] request = new String[1];
|
||||
+ request[0] =
|
||||
+ "POST /test HTTP/1.1" + CRLF +
|
||||
+ "Host: localhost:8080" + CRLF +
|
||||
+ "Content-Length: 12\u000734" + CRLF +
|
||||
+ "Connection: close" + CRLF +
|
||||
+ CRLF;
|
||||
+
|
||||
+ InvalidClient client = new InvalidClient(request);
|
||||
+
|
||||
+ client.doRequest();
|
||||
+ Assert.assertTrue(client.getResponseLine(), client.isResponse400());
|
||||
+ Assert.assertTrue(client.isResponseBodyOK());
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+
|
||||
|
||||
/**
|
||||
* Bug 48839 test client.
|
||||
253
CVE-2023-24998.patch
Normal file
253
CVE-2023-24998.patch
Normal file
@ -0,0 +1,253 @@
|
||||
From cf77cc545de0488fb89e24294151504a7432df74 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Thomas <markt@apache.org>
|
||||
Date: Tue, 13 Dec 2022 17:55:34 +0000
|
||||
Subject: [PATCH] Update packaged renamed fork of Commons File Upload
|
||||
|
||||
Origin: https://github.com/apache/tomcat/commit/cf77cc545de0488fb89e24294151504a7432df74
|
||||
|
||||
---
|
||||
.../apache/catalina/connector/Request.java | 12 ++++-
|
||||
.../apache/tomcat/util/http/Parameters.java | 4 ++
|
||||
.../util/http/fileupload/FileUploadBase.java | 29 +++++++++++
|
||||
.../impl/FileCountLimitExceededException.java | 50 +++++++++++++++++++
|
||||
webapps/docs/changelog.xml | 8 +++
|
||||
webapps/docs/config/ajp.xml | 15 +++---
|
||||
webapps/docs/config/http.xml | 15 +++---
|
||||
7 files changed, 119 insertions(+), 14 deletions(-)
|
||||
create mode 100644 java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java
|
||||
|
||||
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
|
||||
index 889d5e7..87ab732 100644
|
||||
--- a/java/org/apache/catalina/connector/Request.java
|
||||
+++ b/java/org/apache/catalina/connector/Request.java
|
||||
@@ -2769,8 +2769,9 @@ public class Request implements HttpServletRequest {
|
||||
}
|
||||
}
|
||||
|
||||
- Parameters parameters = coyoteRequest.getParameters();
|
||||
- parameters.setLimit(getConnector().getMaxParameterCount());
|
||||
+ int maxParameterCount = getConnector().getMaxParameterCount();
|
||||
+ Parameters parameters = coyoteRequest.getParameters();
|
||||
+ parameters.setLimit(maxParameterCount);
|
||||
|
||||
boolean success = false;
|
||||
try {
|
||||
@@ -2814,6 +2815,13 @@ public class Request implements HttpServletRequest {
|
||||
upload.setFileItemFactory(factory);
|
||||
upload.setFileSizeMax(mce.getMaxFileSize());
|
||||
upload.setSizeMax(mce.getMaxRequestSize());
|
||||
+ if (maxParameterCount > -1) {
|
||||
+ // There is a limit. The limit for parts needs to be reduced by
|
||||
+ // the number of parameters we have already parsed.
|
||||
+ // Must be under the limit else parsing parameters would have
|
||||
+ // triggered an exception.
|
||||
+ upload.setFileCountMax(maxParameterCount - parameters.size());
|
||||
+ }
|
||||
|
||||
parts = new ArrayList<>();
|
||||
try {
|
||||
diff --git a/java/org/apache/tomcat/util/http/Parameters.java b/java/org/apache/tomcat/util/http/Parameters.java
|
||||
index 5bd9ba7..08c6ffd 100644
|
||||
--- a/java/org/apache/tomcat/util/http/Parameters.java
|
||||
+++ b/java/org/apache/tomcat/util/http/Parameters.java
|
||||
@@ -124,6 +124,10 @@ public final class Parameters {
|
||||
}
|
||||
}
|
||||
|
||||
+ public int size() {
|
||||
+ return parameterCount;
|
||||
+ }
|
||||
+
|
||||
|
||||
public void recycle() {
|
||||
parameterCount = 0;
|
||||
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
|
||||
index eb5a487..5506754 100644
|
||||
--- a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
|
||||
+++ b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
|
||||
@@ -26,6 +26,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
+import org.apache.tomcat.util.http.fileupload.impl.FileCountLimitExceededException;
|
||||
import org.apache.tomcat.util.http.fileupload.MultipartStream.ItemInputStream;
|
||||
import org.apache.tomcat.util.http.fileupload.util.Closeable;
|
||||
import org.apache.tomcat.util.http.fileupload.util.FileItemHeadersImpl;
|
||||
@@ -131,6 +132,12 @@ public abstract class FileUploadBase {
|
||||
* to {@link #sizeMax}. A value of -1 indicates no maximum.
|
||||
*/
|
||||
private long fileSizeMax = -1;
|
||||
+
|
||||
+ /**
|
||||
+ * The maximum permitted number of files that may be uploaded in a single
|
||||
+ * request. A value of -1 indicates no maximum.
|
||||
+ */
|
||||
+ private long fileCountMax = -1;
|
||||
|
||||
/**
|
||||
* The content encoding to use when reading part headers.
|
||||
@@ -208,6 +215,24 @@ public abstract class FileUploadBase {
|
||||
this.fileSizeMax = fileSizeMax;
|
||||
}
|
||||
|
||||
+ /**
|
||||
+ * Returns the maximum number of files allowed in a single request.
|
||||
+ *
|
||||
+ * @return The maximum number of files allowed in a single request.
|
||||
+ */
|
||||
+ public long getFileCountMax() {
|
||||
+ return fileCountMax;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Sets the maximum number of files allowed per request/
|
||||
+ *
|
||||
+ * @param fileCountMax The new limit. {@code -1} means no limit.
|
||||
+ */
|
||||
+ public void setFileCountMax(long fileCountMax) {
|
||||
+ this.fileCountMax = fileCountMax;
|
||||
+ }
|
||||
+
|
||||
/**
|
||||
* Retrieves the character encoding used when reading the headers of an
|
||||
* individual part. When not specified, or <code>null</code>, the request
|
||||
@@ -283,6 +308,10 @@ public abstract class FileUploadBase {
|
||||
throw new NullPointerException("No FileItemFactory has been set.");
|
||||
}
|
||||
while (iter.hasNext()) {
|
||||
+ if (items.size() == fileCountMax) {
|
||||
+ // The next item will exceed the limit.
|
||||
+ throw new FileCountLimitExceededException(ATTACHMENT, getFileCountMax());
|
||||
+ }
|
||||
final FileItemStream item = iter.next();
|
||||
// Don't use getName() here to prevent an InvalidFileNameException.
|
||||
final String fileName = ((FileItemIteratorImpl.FileItemStreamImpl) item).name;
|
||||
diff --git a/java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java b/java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java
|
||||
new file mode 100644
|
||||
index 0000000..958f681
|
||||
--- /dev/null
|
||||
+++ b/java/org/apache/tomcat/util/http/fileupload/impl/FileCountLimitExceededException.java
|
||||
@@ -0,0 +1,50 @@
|
||||
+/*
|
||||
+ * 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.impl;
|
||||
+
|
||||
+import org.apache.tomcat.util.http.fileupload.FileUploadException;
|
||||
+
|
||||
+/**
|
||||
+ * This exception is thrown if a request contains more files than the specified
|
||||
+ * limit.
|
||||
+ */
|
||||
+public class FileCountLimitExceededException extends FileUploadException {
|
||||
+
|
||||
+ private static final long serialVersionUID = 2408766352570556046L;
|
||||
+
|
||||
+ private final long limit;
|
||||
+
|
||||
+ /**
|
||||
+ * Creates a new instance.
|
||||
+ *
|
||||
+ * @param message The detail message
|
||||
+ * @param limit The limit that was exceeded
|
||||
+ */
|
||||
+ public FileCountLimitExceededException(final String message, final long limit) {
|
||||
+ super(message);
|
||||
+ this.limit = limit;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Retrieves the limit that was exceeded.
|
||||
+ *
|
||||
+ * @return The limit that was exceeded by the request
|
||||
+ */
|
||||
+ public long getLimit() {
|
||||
+ return limit;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
|
||||
index 835b0d0..0268d87 100644
|
||||
--- a/webapps/docs/changelog.xml
|
||||
+++ b/webapps/docs/changelog.xml
|
||||
@@ -44,6 +44,14 @@
|
||||
They eventually become mixed with the numbered issues. (I.e., numbered
|
||||
issues do not "pop up" wrt. others).
|
||||
-->
|
||||
+ <subsection name="Other">
|
||||
+ <changelog>
|
||||
+ <update>
|
||||
+ Update the internal fork of Apache Commons FileUpload to 34eb241
|
||||
+ (2023-01-03, 2.0-SNAPSHOT). (markt)
|
||||
+ </update>
|
||||
+ </changelog>
|
||||
+ </subsection>
|
||||
<section name="Tomcat 9.0.10 (markt)">
|
||||
<subsection name="Catalina">
|
||||
<changelog>
|
||||
diff --git a/webapps/docs/config/ajp.xml b/webapps/docs/config/ajp.xml
|
||||
index 622e7ca..38c5269 100644
|
||||
--- a/webapps/docs/config/ajp.xml
|
||||
+++ b/webapps/docs/config/ajp.xml
|
||||
@@ -114,12 +114,15 @@
|
||||
</attribute>
|
||||
|
||||
<attribute name="maxParameterCount" required="false">
|
||||
- <p>The maximum number of parameter and value pairs (GET plus POST) which
|
||||
- will be automatically parsed by the container. Parameter and value pairs
|
||||
- beyond this limit will be ignored. A value of less than 0 means no limit.
|
||||
- If not specified, a default of 10000 is used. Note that
|
||||
- <code>FailedRequestFilter</code> <a href="filter.html">filter</a> can be
|
||||
- used to reject requests that hit the limit.</p>
|
||||
+ <p>The maximum total number of request parameters (including uploaded
|
||||
+ files) obtained from the query string and, for POST requests, the request
|
||||
+ body if the content type is
|
||||
+ <code>application/x-www-form-urlencoded</code> or
|
||||
+ <code>multipart/form-data</code>. Request parameters beyond this limit
|
||||
+ will be ignored. A value of less than 0 means no limit. If not specified,
|
||||
+ a default of 10000 is used. Note that <code>FailedRequestFilter</code>
|
||||
+ <a href="filter.html">filter</a> can be used to reject requests that
|
||||
+ exceed the limit.</p>
|
||||
</attribute>
|
||||
|
||||
<attribute name="maxPostSize" required="false">
|
||||
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
|
||||
index 3902c9a..52ad063 100644
|
||||
--- a/webapps/docs/config/http.xml
|
||||
+++ b/webapps/docs/config/http.xml
|
||||
@@ -111,12 +111,15 @@
|
||||
</attribute>
|
||||
|
||||
<attribute name="maxParameterCount" required="false">
|
||||
- <p>The maximum number of parameter and value pairs (GET plus POST) which
|
||||
- will be automatically parsed by the container. Parameter and value pairs
|
||||
- beyond this limit will be ignored. A value of less than 0 means no limit.
|
||||
- If not specified, a default of 10000 is used. Note that
|
||||
- <code>FailedRequestFilter</code> <a href="filter.html">filter</a> can be
|
||||
- used to reject requests that hit the limit.</p>
|
||||
+ <p>The maximum total number of request parameters (including uploaded
|
||||
+ files) obtained from the query string and, for POST requests, the request
|
||||
+ body if the content type is
|
||||
+ <code>application/x-www-form-urlencoded</code> or
|
||||
+ <code>multipart/form-data</code>. Request parameters beyond this limit
|
||||
+ will be ignored. A value of less than 0 means no limit. If not specified,
|
||||
+ a default of 10000 is used. Note that <code>FailedRequestFilter</code>
|
||||
+ <a href="filter.html">filter</a> can be used to reject requests that
|
||||
+ exceed the limit.</p>
|
||||
</attribute>
|
||||
|
||||
<attribute name="maxPostSize" required="false">
|
||||
--
|
||||
2.33.0
|
||||
238
CVE-2023-28708-pre.patch
Normal file
238
CVE-2023-28708-pre.patch
Normal file
@ -0,0 +1,238 @@
|
||||
From 09e214c09c78a48ea96b0137555b3c2a98a1bfab Mon Sep 17 00:00:00 2001
|
||||
From: Mark Thomas <markt@apache.org>
|
||||
Date: Tue, 31 Mar 2020 14:03:17 +0100
|
||||
Subject: [PATCH] Make the HTTP/2 connection ID and stream Id available to
|
||||
applications
|
||||
Origin: https://github.com/apache/tomcat/commit/09e214c09c78a48ea96b0137555b3c2a98a1bfab
|
||||
|
||||
---
|
||||
java/org/apache/catalina/Globals.java | 16 ++++++++
|
||||
.../apache/catalina/connector/Request.java | 27 +++++++++++++
|
||||
java/org/apache/coyote/AbstractProcessor.java | 39 +++++++++++++++++++
|
||||
java/org/apache/coyote/ActionCode.java | 14 ++++++-
|
||||
.../apache/coyote/http2/StreamProcessor.java | 12 ++++++
|
||||
webapps/docs/changelog.xml | 5 +++
|
||||
webapps/docs/config/http2.xml | 9 +++++
|
||||
7 files changed, 121 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/java/org/apache/catalina/Globals.java b/java/org/apache/catalina/Globals.java
|
||||
index 994902b..c19d69c 100644
|
||||
--- a/java/org/apache/catalina/Globals.java
|
||||
+++ b/java/org/apache/catalina/Globals.java
|
||||
@@ -112,6 +112,22 @@ public final class Globals {
|
||||
"org.apache.catalina.NAMED";
|
||||
|
||||
|
||||
+ /**
|
||||
+ * The request attribute used to expose the current connection ID associated
|
||||
+ * with the request, if any. Used with multiplexing protocols such as
|
||||
+ * HTTTP/2.
|
||||
+ */
|
||||
+ public static final String CONNECTION_ID = "org.apache.coyote.connectionID";
|
||||
+
|
||||
+
|
||||
+ /**
|
||||
+ * The request attribute used to expose the current stream ID associated
|
||||
+ * with the request, if any. Used with multiplexing protocols such as
|
||||
+ * HTTTP/2.
|
||||
+ */
|
||||
+ public static final String STREAM_ID = "org.apache.coyote.streamID";
|
||||
+
|
||||
+
|
||||
/**
|
||||
* The servlet context attribute under which we store a flag used
|
||||
* to mark this request as having been processed by the SSIServlet.
|
||||
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
|
||||
index c4cc26a..94065ef 100644
|
||||
--- a/java/org/apache/catalina/connector/Request.java
|
||||
+++ b/java/org/apache/catalina/connector/Request.java
|
||||
@@ -40,6 +40,7 @@ import java.util.TimeZone;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
+import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.security.auth.Subject;
|
||||
@@ -3487,6 +3488,32 @@ public class Request implements HttpServletRequest {
|
||||
// NO-OP
|
||||
}
|
||||
});
|
||||
+ specialAttributes.put(Globals.CONNECTION_ID,
|
||||
+ new SpecialAttributeAdapter() {
|
||||
+ @Override
|
||||
+ public Object get(Request request, String name) {
|
||||
+ AtomicReference<Object> result = new AtomicReference<>();
|
||||
+ request.getCoyoteRequest().action(ActionCode.CONNECTION_ID, result);
|
||||
+ return result.get();
|
||||
+ }
|
||||
+ @Override
|
||||
+ public void set(Request request, String name, Object value) {
|
||||
+ // NO-OP
|
||||
+ }
|
||||
+ });
|
||||
+ specialAttributes.put(Globals.STREAM_ID,
|
||||
+ new SpecialAttributeAdapter() {
|
||||
+ @Override
|
||||
+ public Object get(Request request, String name) {
|
||||
+ AtomicReference<Object> result = new AtomicReference<>();
|
||||
+ request.getCoyoteRequest().action(ActionCode.STREAM_ID, result);
|
||||
+ return result.get();
|
||||
+ }
|
||||
+ @Override
|
||||
+ public void set(Request request, String name, Object value) {
|
||||
+ // NO-OP
|
||||
+ }
|
||||
+ });
|
||||
|
||||
for (SimpleDateFormat sdf : formatsTemplate) {
|
||||
sdf.setTimeZone(GMT_ZONE);
|
||||
diff --git a/java/org/apache/coyote/AbstractProcessor.java b/java/org/apache/coyote/AbstractProcessor.java
|
||||
index 5be2cb8..b351cb7 100644
|
||||
--- a/java/org/apache/coyote/AbstractProcessor.java
|
||||
+++ b/java/org/apache/coyote/AbstractProcessor.java
|
||||
@@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
+import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
|
||||
@@ -589,6 +590,20 @@ public abstract class AbstractProcessor extends AbstractProcessorLight implement
|
||||
result.set(isTrailerFieldsSupported());
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ // Identifiers associated with multiplexing protocols like HTTP/2
|
||||
+ case CONNECTION_ID: {
|
||||
+ @SuppressWarnings("unchecked")
|
||||
+ AtomicReference<Object> result = (AtomicReference<Object>) param;
|
||||
+ result.set(getConnectionID());
|
||||
+ break;
|
||||
+ }
|
||||
+ case STREAM_ID: {
|
||||
+ @SuppressWarnings("unchecked")
|
||||
+ AtomicReference<Object> result = (AtomicReference<Object>) param;
|
||||
+ result.set(getStreamID());
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -889,6 +904,30 @@ public abstract class AbstractProcessor extends AbstractProcessorLight implement
|
||||
}
|
||||
|
||||
|
||||
+ /**
|
||||
+ * Protocols that support multiplexing (e.g. HTTP/2) should override this
|
||||
+ * method and return the appropriate ID.
|
||||
+ *
|
||||
+ * @return The stream ID associated with this request or {@code null} if a
|
||||
+ * multiplexing protocol is not being used
|
||||
+ */
|
||||
+ protected Object getConnectionID() {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ /**
|
||||
+ * Protocols that support multiplexing (e.g. HTTP/2) should override this
|
||||
+ * method and return the appropriate ID.
|
||||
+ *
|
||||
+ * @return The stream ID associated with this request or {@code null} if a
|
||||
+ * multiplexing protocol is not being used
|
||||
+ */
|
||||
+ protected Object getStreamID() {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
/**
|
||||
* Flush any pending writes. Used during non-blocking writes to flush any
|
||||
* remaining data from a previous incomplete write.
|
||||
diff --git a/java/org/apache/coyote/ActionCode.java b/java/org/apache/coyote/ActionCode.java
|
||||
index 3ff4c21..5c5af4f 100644
|
||||
--- a/java/org/apache/coyote/ActionCode.java
|
||||
+++ b/java/org/apache/coyote/ActionCode.java
|
||||
@@ -265,5 +265,17 @@ public enum ActionCode {
|
||||
* once an HTTP/1.1 response has been committed, it will no longer support
|
||||
* trailer fields.
|
||||
*/
|
||||
- IS_TRAILER_FIELDS_SUPPORTED
|
||||
+ IS_TRAILER_FIELDS_SUPPORTED,
|
||||
+
|
||||
+ /**
|
||||
+ * Obtain the connection identifier for the request. Used with multiplexing
|
||||
+ * protocols such as HTTP/2.
|
||||
+ */
|
||||
+ CONNECTION_ID,
|
||||
+
|
||||
+ /**
|
||||
+ * Obtain the stream identifier for the request. Used with multiplexing
|
||||
+ * protocols such as HTTP/2.
|
||||
+ */
|
||||
+ STREAM_ID
|
||||
}
|
||||
diff --git a/java/org/apache/coyote/http2/StreamProcessor.java b/java/org/apache/coyote/http2/StreamProcessor.java
|
||||
index d9c1c82..fd833ec 100644
|
||||
--- a/java/org/apache/coyote/http2/StreamProcessor.java
|
||||
+++ b/java/org/apache/coyote/http2/StreamProcessor.java
|
||||
@@ -300,6 +300,18 @@ class StreamProcessor extends AbstractProcessor {
|
||||
}
|
||||
|
||||
|
||||
+ @Override
|
||||
+ protected Object getConnectionID() {
|
||||
+ return stream.getConnectionId();
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ @Override
|
||||
+ protected Object getStreamID() {
|
||||
+ return stream.getIdentifier().toString();
|
||||
+ }
|
||||
+
|
||||
+
|
||||
@Override
|
||||
public final void recycle() {
|
||||
// StreamProcessor instances are not re-used.
|
||||
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
|
||||
index a97e15d..8837628 100644
|
||||
--- a/webapps/docs/changelog.xml
|
||||
+++ b/webapps/docs/changelog.xml
|
||||
@@ -247,6 +247,11 @@
|
||||
Ensure that the HTTP/1.1 processor is correctly recycled when a direct
|
||||
connection to h2c is made. (markt)
|
||||
</fix>
|
||||
+ <add>
|
||||
+ Expose the HTTP/2 connection ID and stream ID to applications via the
|
||||
+ request attributes <code>org.apache.coyote.connectionID</code> and
|
||||
+ <code>org.apache.coyote.streamID</code> respectively. (markt)
|
||||
+ </add>
|
||||
</changelog>
|
||||
</subsection>
|
||||
<subsection name="Jasper">
|
||||
diff --git a/webapps/docs/config/http2.xml b/webapps/docs/config/http2.xml
|
||||
index 83b8acd..145a184 100644
|
||||
--- a/webapps/docs/config/http2.xml
|
||||
+++ b/webapps/docs/config/http2.xml
|
||||
@@ -44,6 +44,15 @@
|
||||
the Servlet API is fundamentally blocking, each HTTP/2 stream requires a
|
||||
dedicated container thread for the duration of that stream.</p>
|
||||
|
||||
+ <p>Requests processed using HTTP/2 will have the following additional request
|
||||
+ attributes available:</p>
|
||||
+ <ul>
|
||||
+ <li><code>org.apache.coyote.connectionID</code> will return the HTTP/2
|
||||
+ connection ID</li>
|
||||
+ <li><code>org.apache.coyote.streamID</code> will return the HTTP/2 stream
|
||||
+ ID</li>
|
||||
+ </ul>
|
||||
+
|
||||
</section>
|
||||
|
||||
|
||||
--
|
||||
2.33.0
|
||||
|
||||
232
CVE-2023-28708.patch
Normal file
232
CVE-2023-28708.patch
Normal file
@ -0,0 +1,232 @@
|
||||
From 3b51230764da595bb19e8d0962dd8c69ab40dfab Mon Sep 17 00:00:00 2001
|
||||
From: lihan <lihan@apache.org>
|
||||
Date: Fri, 10 Feb 2023 10:01:27 +0800
|
||||
Subject: [PATCH] Fix BZ 66471 - JSessionId secure attribute missing with
|
||||
RemoteIpFilter and X-Forwarded-Proto set to https
|
||||
|
||||
https://bz.apache.org/bugzilla/show_bug.cgi?id=66471
|
||||
|
||||
Origin: https://github.com/apache/tomcat/commit/3b51230764da595bb19e8d0962dd8c69ab40dfab
|
||||
---
|
||||
java/org/apache/catalina/Globals.java | 8 ++
|
||||
.../apache/catalina/connector/Request.java | 14 +++
|
||||
.../catalina/filters/RemoteIpFilter.java | 7 +-
|
||||
.../catalina/filters/TestRemoteIpFilter.java | 96 ++++++++++++++-----
|
||||
webapps/docs/changelog.xml | 5 +
|
||||
5 files changed, 101 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/java/org/apache/catalina/Globals.java b/java/org/apache/catalina/Globals.java
|
||||
index c19d69c..2e9a377 100644
|
||||
--- a/java/org/apache/catalina/Globals.java
|
||||
+++ b/java/org/apache/catalina/Globals.java
|
||||
@@ -160,6 +160,14 @@ public final class Globals {
|
||||
org.apache.coyote.Constants.SENDFILE_SUPPORTED_ATTR;
|
||||
|
||||
|
||||
+ /**
|
||||
+ * The request attribute that is set to the value of {@code Boolean.TRUE}
|
||||
+ * if {@link org.apache.catalina.filters.RemoteIpFilter} determines
|
||||
+ * that this request was submitted via a secure channel.
|
||||
+ */
|
||||
+ public static final String REMOTE_IP_FILTER_SECURE = "org.apache.catalina.filters.RemoteIpFilter.secure";
|
||||
+
|
||||
+
|
||||
/**
|
||||
* The request attribute that can be used by a servlet to pass
|
||||
* to the connector the name of the file that is to be served
|
||||
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
|
||||
index 94065ef..889d5e7 100644
|
||||
--- a/java/org/apache/catalina/connector/Request.java
|
||||
+++ b/java/org/apache/catalina/connector/Request.java
|
||||
@@ -3501,6 +3501,20 @@ public class Request implements HttpServletRequest {
|
||||
// NO-OP
|
||||
}
|
||||
});
|
||||
+ specialAttributes.put(Globals.REMOTE_IP_FILTER_SECURE,
|
||||
+ new SpecialAttributeAdapter() {
|
||||
+ @Override
|
||||
+ public Object get(Request request, String name) {
|
||||
+ return Boolean.valueOf(request.isSecure());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void set(Request request, String name, Object value) {
|
||||
+ if (value instanceof Boolean) {
|
||||
+ request.setSecure(((Boolean) value).booleanValue());
|
||||
+ }
|
||||
+ }
|
||||
+ });
|
||||
specialAttributes.put(Globals.STREAM_ID,
|
||||
new SpecialAttributeAdapter() {
|
||||
@Override
|
||||
diff --git a/java/org/apache/catalina/filters/RemoteIpFilter.java b/java/org/apache/catalina/filters/RemoteIpFilter.java
|
||||
index b9f6655..e978cfb 100644
|
||||
--- a/java/org/apache/catalina/filters/RemoteIpFilter.java
|
||||
+++ b/java/org/apache/catalina/filters/RemoteIpFilter.java
|
||||
@@ -577,11 +577,6 @@ public class RemoteIpFilter extends GenericFilter {
|
||||
return serverPort;
|
||||
}
|
||||
|
||||
- @Override
|
||||
- public boolean isSecure() {
|
||||
- return secure;
|
||||
- }
|
||||
-
|
||||
public void removeHeader(String name) {
|
||||
Map.Entry<String, List<String>> header = getHeaderEntry(name);
|
||||
if (header != null) {
|
||||
@@ -617,7 +612,7 @@ public class RemoteIpFilter extends GenericFilter {
|
||||
}
|
||||
|
||||
public void setSecure(boolean secure) {
|
||||
- this.secure = secure;
|
||||
+ super.getRequest().setAttribute(Globals.REMOTE_IP_FILTER_SECURE, Boolean.valueOf(secure));
|
||||
}
|
||||
|
||||
public void setServerPort(int serverPort) {
|
||||
diff --git a/test/org/apache/catalina/filters/TestRemoteIpFilter.java b/test/org/apache/catalina/filters/TestRemoteIpFilter.java
|
||||
index f7f2093..109fdd2 100644
|
||||
--- a/test/org/apache/catalina/filters/TestRemoteIpFilter.java
|
||||
+++ b/test/org/apache/catalina/filters/TestRemoteIpFilter.java
|
||||
@@ -81,15 +81,21 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
- private transient HttpServletRequest request;
|
||||
-
|
||||
- public HttpServletRequest getRequest() {
|
||||
- return request;
|
||||
- }
|
||||
+ public String remoteAddr;
|
||||
+ public String remoteHost;
|
||||
+ public String scheme;
|
||||
+ public String serverName;
|
||||
+ public int serverPort;
|
||||
+ public boolean isSecure;
|
||||
|
||||
@Override
|
||||
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
- this.request = request;
|
||||
+ this.isSecure = request.isSecure();
|
||||
+ this.remoteAddr = request.getRemoteAddr();
|
||||
+ this.remoteHost = request.getRemoteHost();
|
||||
+ this.scheme = request.getScheme();
|
||||
+ this.serverName = request.getServerName();
|
||||
+ this.serverPort = request.getServerPort();
|
||||
PrintWriter writer = response.getWriter();
|
||||
|
||||
writer.println("request.remoteAddr=" + request.getRemoteAddr());
|
||||
@@ -127,16 +133,6 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
|
||||
getCoyoteRequest().scheme().setString(scheme);
|
||||
}
|
||||
|
||||
- @Override
|
||||
- public void setAttribute(String name, Object value) {
|
||||
- getCoyoteRequest().getAttributes().put(name, value);
|
||||
- }
|
||||
-
|
||||
- @Override
|
||||
- public Object getAttribute(String name) {
|
||||
- return getCoyoteRequest().getAttributes().get(name);
|
||||
- }
|
||||
-
|
||||
@Override
|
||||
public String getServerName() {
|
||||
return "localhost";
|
||||
@@ -667,16 +663,70 @@ public class TestRemoteIpFilter extends TomcatBaseTest {
|
||||
|
||||
// VALIDATE
|
||||
Assert.assertEquals(HttpURLConnection.HTTP_OK, httpURLConnection.getResponseCode());
|
||||
- HttpServletRequest request = mockServlet.getRequest();
|
||||
- Assert.assertNotNull(request);
|
||||
|
||||
// VALIDATE X-FORWARDED-FOR
|
||||
- Assert.assertEquals(expectedRemoteAddr, request.getRemoteAddr());
|
||||
- Assert.assertEquals(expectedRemoteAddr, request.getRemoteHost());
|
||||
+ Assert.assertEquals(expectedRemoteAddr, mockServlet.remoteAddr);
|
||||
+ Assert.assertEquals(expectedRemoteAddr, mockServlet.remoteHost);
|
||||
|
||||
// VALIDATE X-FORWARDED-PROTO
|
||||
- Assert.assertTrue(request.isSecure());
|
||||
- Assert.assertEquals("https", request.getScheme());
|
||||
- Assert.assertEquals(443, request.getServerPort());
|
||||
+ Assert.assertTrue(mockServlet.isSecure);
|
||||
+ Assert.assertEquals("https", mockServlet.scheme);
|
||||
+ Assert.assertEquals(443, mockServlet.serverPort);
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void testJSessionIdSecureAttributeMissing() throws Exception {
|
||||
+
|
||||
+ // mostly default configuration : enable "x-forwarded-proto"
|
||||
+ Map<String, String> remoteIpFilterParameter = new HashMap<>();
|
||||
+ remoteIpFilterParameter.put("protocolHeader", "x-forwarded-proto");
|
||||
+
|
||||
+ // SETUP
|
||||
+ Tomcat tomcat = getTomcatInstance();
|
||||
+ Context root = tomcat.addContext("", TEMP_DIR);
|
||||
+
|
||||
+ FilterDef filterDef = new FilterDef();
|
||||
+ filterDef.getParameterMap().putAll(remoteIpFilterParameter);
|
||||
+ filterDef.setFilterClass(RemoteIpFilter.class.getName());
|
||||
+ filterDef.setFilterName(RemoteIpFilter.class.getName());
|
||||
+
|
||||
+ root.addFilterDef(filterDef);
|
||||
+
|
||||
+ FilterMap filterMap = new FilterMap();
|
||||
+ filterMap.setFilterName(RemoteIpFilter.class.getName());
|
||||
+ filterMap.addURLPatternDecoded("*");
|
||||
+ root.addFilterMap(filterMap);
|
||||
+
|
||||
+ Bug66471Servlet bug66471Servlet = new Bug66471Servlet();
|
||||
+
|
||||
+ Tomcat.addServlet(root, bug66471Servlet.getClass().getName(), bug66471Servlet);
|
||||
+ root.addServletMappingDecoded("/test", bug66471Servlet.getClass().getName());
|
||||
+
|
||||
+ getTomcatInstance().start();
|
||||
+
|
||||
+ Map<String, List<String>> resHeaders = new HashMap<>();
|
||||
+ Map<String, List<String>> reqHeaders = new HashMap<>();
|
||||
+ String expectedRemoteAddr = "my-remote-addr";
|
||||
+ List<String> forwardedFor = new ArrayList<>(1);
|
||||
+ forwardedFor.add(expectedRemoteAddr);
|
||||
+ List<String> forwardedProto = new ArrayList<>(1);
|
||||
+ forwardedProto.add("https");
|
||||
+ reqHeaders.put("x-forwarded-for", forwardedFor);
|
||||
+ reqHeaders.put("x-forwarded-proto", forwardedProto);
|
||||
+
|
||||
+ getUrl("http://localhost:" + tomcat.getConnector().getLocalPort() +
|
||||
+ "/test", null, reqHeaders, resHeaders);
|
||||
+ String setCookie = resHeaders.get("Set-Cookie").get(0);
|
||||
+ Assert.assertTrue(setCookie.contains("Secure"));
|
||||
+ Assert.assertTrue(bug66471Servlet.isSecure.booleanValue());
|
||||
+ }
|
||||
+ public static class Bug66471Servlet extends HttpServlet {
|
||||
+ private static final long serialVersionUID = 1L;
|
||||
+ public Boolean isSecure;
|
||||
+ @Override
|
||||
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
+ req.getSession();
|
||||
+ isSecure = (Boolean) req.getAttribute(Globals.REMOTE_IP_FILTER_SECURE);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
|
||||
index 8837628..15be3ed 100644
|
||||
--- a/webapps/docs/changelog.xml
|
||||
+++ b/webapps/docs/changelog.xml
|
||||
@@ -478,6 +478,11 @@
|
||||
Improve handling of overflow in the UTF-8 decoder with supplementary
|
||||
characters. (markt)
|
||||
</fix>
|
||||
+ <fix>
|
||||
+ <bug>66471</bug>: Fix JSessionId secure attribute missing When
|
||||
+ <code>RemoteIpFilter</code> determines that this request was submitted
|
||||
+ via a secure channel. (lihan)
|
||||
+ </fix>
|
||||
</changelog>
|
||||
</subsection>
|
||||
<subsection name="Coyote">
|
||||
--
|
||||
2.33.0
|
||||
|
||||
35
CVE-2023-28709.patch
Normal file
35
CVE-2023-28709.patch
Normal file
@ -0,0 +1,35 @@
|
||||
From fbd81421629afe8b8a3922d59020cde81caea861 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Thomas <markt@apache.org>
|
||||
Date: Tue, 11 Apr 2023 16:41:44 +0100
|
||||
Subject: [PATCH] Fix parameter counting logic
|
||||
|
||||
Origin: https://github.com/apache/tomcat/commit/fbd81421629afe8b8a3922d59020cde81caea861
|
||||
|
||||
---
|
||||
java/org/apache/tomcat/util/http/Parameters.java | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/java/org/apache/tomcat/util/http/Parameters.java b/java/org/apache/tomcat/util/http/Parameters.java
|
||||
index 08c6ffd..a19453d 100644
|
||||
--- a/java/org/apache/tomcat/util/http/Parameters.java
|
||||
+++ b/java/org/apache/tomcat/util/http/Parameters.java
|
||||
@@ -205,14 +205,14 @@ public final class Parameters {
|
||||
return;
|
||||
}
|
||||
|
||||
- parameterCount ++;
|
||||
- if (limit > -1 && parameterCount > limit) {
|
||||
+ if (limit > -1 && parameterCount >= limit) {
|
||||
// Processing this parameter will push us over the limit. ISE is
|
||||
// what Request.parseParts() uses for requests that are too big
|
||||
setParseFailedReason(FailReason.TOO_MANY_PARAMETERS);
|
||||
throw new IllegalStateException(sm.getString(
|
||||
"parameters.maxCountFail", Integer.valueOf(limit)));
|
||||
}
|
||||
+ parameterCount ++;
|
||||
|
||||
ArrayList<String> values = paramHashValues.get(key);
|
||||
if (values == null) {
|
||||
--
|
||||
2.33.0
|
||||
|
||||
29
CVE-2023-41080.patch
Normal file
29
CVE-2023-41080.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From 77c0ce2d169efa248b64b992e547aad549ec906b Mon Sep 17 00:00:00 2001
|
||||
From: Mark Thomas <markt@apache.org>
|
||||
Date: Tue, 22 Aug 2023 11:31:23 -0700
|
||||
Subject: [PATCH] Avoid protocol relative redirects
|
||||
|
||||
Origin: https://github.com/apache/tomcat/commit/77c0ce2d169efa248b64b992e547aad549ec906b
|
||||
|
||||
---
|
||||
.../apache/catalina/authenticator/FormAuthenticator.java | 6 ++++++
|
||||
webapps/docs/changelog.xml | 3 +++
|
||||
2 files changed, 9 insertions(+)
|
||||
|
||||
diff --git a/java/org/apache/catalina/authenticator/FormAuthenticator.java b/java/org/apache/catalina/authenticator/FormAuthenticator.java
|
||||
index a57db51776b..d54cc62182e 100644
|
||||
--- a/java/org/apache/catalina/authenticator/FormAuthenticator.java
|
||||
+++ b/java/org/apache/catalina/authenticator/FormAuthenticator.java
|
||||
@@ -747,6 +747,12 @@ protected String savedRequestURL(Session session) {
|
||||
sb.append('?');
|
||||
sb.append(saved.getQueryString());
|
||||
}
|
||||
+
|
||||
+ // Avoid protocol relative redirects
|
||||
+ while (sb.length() > 1 && sb.charAt(1) == '/') {
|
||||
+ sb.deleteCharAt(0);
|
||||
+ }
|
||||
+
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
251
CVE-2023-42795.patch
Normal file
251
CVE-2023-42795.patch
Normal file
@ -0,0 +1,251 @@
|
||||
From 44d05d75d696ca10ce251e4e370511e38f20ae75 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Thomas <markt@apache.org>
|
||||
Date: Thu, 5 Oct 2023 20:52:46 +0100
|
||||
Subject: [PATCH] Improve handling of failures during recycle() methods
|
||||
|
||||
Origin: https://github.com/apache/tomcat/commit/44d05d75d696ca10ce251e4e370511e38f20ae75
|
||||
|
||||
---
|
||||
.../catalina/connector/LocalStrings.properties | 1 +
|
||||
java/org/apache/catalina/connector/Request.java | 7 ++++---
|
||||
.../catalina/core/ApplicationHttpRequest.java | 16 ++++++++++++----
|
||||
.../apache/catalina/core/LocalStrings.properties | 1 +
|
||||
.../catalina/core/LocalStrings_es.properties | 2 ++
|
||||
.../catalina/core/LocalStrings_fr.properties | 1 +
|
||||
.../catalina/core/LocalStrings_ja.properties | 1 +
|
||||
.../org/apache/tomcat/util/buf/B2CConverter.java | 11 ++++++++++-
|
||||
.../org/apache/tomcat/util/buf/C2BConverter.java | 15 ++++++++++++++-
|
||||
.../tomcat/util/buf/LocalStrings.properties | 3 +++
|
||||
10 files changed, 49 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/java/org/apache/catalina/connector/LocalStrings.properties b/java/org/apache/catalina/connector/LocalStrings.properties
|
||||
index 86c6487..596805b 100644
|
||||
--- a/java/org/apache/catalina/connector/LocalStrings.properties
|
||||
+++ b/java/org/apache/catalina/connector/LocalStrings.properties
|
||||
@@ -47,6 +47,7 @@ coyoteRequest.setAttribute.namenull=Cannot call setAttribute with a null name
|
||||
coyoteRequest.attributeEvent=Exception thrown by attributes event listener
|
||||
coyoteRequest.parseParameters=Exception thrown whilst processing POSTed parameters
|
||||
coyoteRequest.postTooLarge=Parameters were not parsed because the size of the posted data was too big. Use the maxPostSize attribute of the connector to resolve this if the application should accept large POSTs.
|
||||
+coyoteRequest.deletePartFailed=Failed to deleted temporary file used for part [{0}]
|
||||
coyoteRequest.chunkedPostTooLarge=Parameters were not parsed because the size of the posted data was too big. Because this request was a chunked request, it could not be processed further. Use the maxPostSize attribute of the connector to resolve this if the application should accept large POSTs.
|
||||
coyoteRequest.alreadyAuthenticated=This request has already been authenticated
|
||||
coyoteRequest.authenticate.ise=Cannot call authenticate() after the response has been committed
|
||||
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
|
||||
index 889d5e7..de53769 100644
|
||||
--- a/java/org/apache/catalina/connector/Request.java
|
||||
+++ b/java/org/apache/catalina/connector/Request.java
|
||||
@@ -465,8 +465,9 @@ public class Request implements HttpServletRequest {
|
||||
for (Part part: parts) {
|
||||
try {
|
||||
part.delete();
|
||||
- } catch (IOException ignored) {
|
||||
- // ApplicationPart.delete() never throws an IOEx
|
||||
+ } catch (Throwable t) {
|
||||
+ ExceptionUtils.handleThrowable(t);
|
||||
+ log.warn(sm.getString("coyoteRequest.deletePartFailed", part.getName()), t);
|
||||
}
|
||||
}
|
||||
parts = null;
|
||||
@@ -518,8 +519,8 @@ public class Request implements HttpServletRequest {
|
||||
asyncSupported = null;
|
||||
if (asyncContext!=null) {
|
||||
asyncContext.recycle();
|
||||
+ asyncContext = null;
|
||||
}
|
||||
- asyncContext = null;
|
||||
}
|
||||
|
||||
|
||||
diff --git a/java/org/apache/catalina/core/ApplicationHttpRequest.java b/java/org/apache/catalina/core/ApplicationHttpRequest.java
|
||||
index fc3a1d6..0b5b4f5 100644
|
||||
--- a/java/org/apache/catalina/core/ApplicationHttpRequest.java
|
||||
+++ b/java/org/apache/catalina/core/ApplicationHttpRequest.java
|
||||
@@ -29,6 +29,8 @@ import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
+import java.util.Arrays;
|
||||
+import java.util.HashMap;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
@@ -48,9 +50,12 @@ import org.apache.catalina.Session;
|
||||
import org.apache.catalina.connector.RequestFacade;
|
||||
import org.apache.catalina.util.ParameterMap;
|
||||
import org.apache.catalina.util.RequestUtil;
|
||||
+import org.apache.catalina.util.URLEncoder;
|
||||
+import org.apache.tomcat.util.ExceptionUtils;
|
||||
import org.apache.tomcat.util.buf.B2CConverter;
|
||||
import org.apache.tomcat.util.buf.MessageBytes;
|
||||
import org.apache.tomcat.util.http.Parameters;
|
||||
+import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
|
||||
/**
|
||||
@@ -70,9 +75,7 @@ import org.apache.tomcat.util.http.Parameters;
|
||||
*/
|
||||
class ApplicationHttpRequest extends HttpServletRequestWrapper {
|
||||
|
||||
-
|
||||
- // ------------------------------------------------------- Static Variables
|
||||
-
|
||||
+ private static final StringManager sm = StringManager.getManager(ApplicationHttpRequest.class);
|
||||
|
||||
/**
|
||||
* The set of attribute names that are special for request dispatchers.
|
||||
@@ -626,7 +629,12 @@ class ApplicationHttpRequest extends HttpServletRequestWrapper {
|
||||
*/
|
||||
public void recycle() {
|
||||
if (session != null) {
|
||||
- session.endAccess();
|
||||
+ try {
|
||||
+ session.endAccess();
|
||||
+ } catch (Throwable t) {
|
||||
+ ExceptionUtils.handleThrowable(t);
|
||||
+ context.getLogger().warn(sm.getString("applicationHttpRequest.sessionEndAccessFail"), t);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/java/org/apache/catalina/core/LocalStrings.properties b/java/org/apache/catalina/core/LocalStrings.properties
|
||||
index c5b55b1..0e17e3c 100644
|
||||
--- a/java/org/apache/catalina/core/LocalStrings.properties
|
||||
+++ b/java/org/apache/catalina/core/LocalStrings.properties
|
||||
@@ -55,6 +55,7 @@ applicationFilterConfig.release=Failed to destroy the filter named [{0}] of type
|
||||
applicationFilterRegistration.nullInitParam=Unable to set initialisation parameter for filter due to null name and/or value. Name [{0}], Value [{1}]
|
||||
applicationFilterRegistration.nullInitParams=Unable to set initialisation parameters for filter due to null name and/or value. Name [{0}], Value [{1}]
|
||||
|
||||
+applicationHttpRequest.sessionEndAccessFail=Exception triggered ending access to session while recycling request
|
||||
applicationPushBuilder.methodInvalid=The HTTP method for a push request must be both cacheable and safe but [{0}] is not
|
||||
applicationPushBuilder.methodNotToken=HTTP methods must be tokens but [{0}] contains a non-token character
|
||||
applicationPushBuilder.noCoyoteRequest=Unable to find the underlying Coyote request object (which is required to create a push request) from the request of type [{0}]
|
||||
diff --git a/java/org/apache/catalina/core/LocalStrings_es.properties b/java/org/apache/catalina/core/LocalStrings_es.properties
|
||||
index f138d17..e6a9ab2 100644
|
||||
--- a/java/org/apache/catalina/core/LocalStrings_es.properties
|
||||
+++ b/java/org/apache/catalina/core/LocalStrings_es.properties
|
||||
@@ -43,6 +43,8 @@ applicationFilterConfig.jmxUnregister = Se ha completado el desregistro JMX para
|
||||
applicationFilterConfig.jmxUnregisterFail = Ha fallado el desregistro JMX para el filtro del tipo [{0}] y nombre [{1}]
|
||||
applicationFilterRegistration.nullInitParam = No puedo poner el par\u00E1metro de inicializaci\u00F3n para el filtro debido a un nombre nulo y/o valor. Nombre [{0}], Valor [{1}]
|
||||
applicationFilterRegistration.nullInitParams = No puedo poner los par\u00E1metros de inicializaci\u00F3n para el filtro debido a un nombre nulo y/o valor. Nombre [{0}], Valor [{1}]
|
||||
+applicationHttpRequest.sessionEndAccessFail=Excepción disparada acabando acceso a sesión mientras se reciclaba el requerimiento
|
||||
+
|
||||
applicationServletRegistration.setServletSecurity.iae = Se ha especificado restricci\u00F3n Null para el servlet [{0}] desplegado en el contexto con el nombre [{1}]
|
||||
applicationServletRegistration.setServletSecurity.ise = No se pueden a\u00F1adir restricciones de seguridad al servlet [{0}] desplegado en el contexto con el nombre [{1}] ya que el contexto ya ha sido inicializado.
|
||||
aprListener.aprInit = La biblioteca nativa de Apache Tomcat basada en ARP que permite un rendimiento \u00F3ptimo en entornos de desarrollo no ha sido hallada en java.library.path: [{0}]
|
||||
diff --git a/java/org/apache/catalina/core/LocalStrings_fr.properties b/java/org/apache/catalina/core/LocalStrings_fr.properties
|
||||
index dfc1cf7..91ead47 100644
|
||||
--- a/java/org/apache/catalina/core/LocalStrings_fr.properties
|
||||
+++ b/java/org/apache/catalina/core/LocalStrings_fr.properties
|
||||
@@ -59,6 +59,7 @@ standardContext.startFailed=Erreur de d\u00e9marrage du contexte [{0}] suite aux
|
||||
standardContext.startingContext=Exception lors du d\u00e9marrage du contexte [{0}]
|
||||
standardContext.stoppingContext=Exception \u00e0 l''arr\u00eat du Context [{0}]
|
||||
standardContext.resourcesStart=Erreur lors du d\u00e9marrage des ressources statiques
|
||||
+applicationHttpRequest.sessionEndAccessFail=Exception lancée durant l'arrêt de l'accès à la session durant le recyclage de la requête
|
||||
standardContext.urlPattern.patternWarning=ATTENTION: Le mod\u00e8le (pattern) URL [{0}] doit commencer par un ''/'' dans l''API Servlet 2.4
|
||||
standardEngine.noHost=Aucune h\u00f4te (host) ne correspond au nom de serveur [{0}]
|
||||
standardEngine.notHost=Le fils d''un moteur (child of an Engine) doit \u00eatre un h\u00f4te
|
||||
diff --git a/java/org/apache/catalina/core/LocalStrings_ja.properties b/java/org/apache/catalina/core/LocalStrings_ja.properties
|
||||
index d34d598..ae85dd4 100644
|
||||
--- a/java/org/apache/catalina/core/LocalStrings_ja.properties
|
||||
+++ b/java/org/apache/catalina/core/LocalStrings_ja.properties
|
||||
@@ -66,6 +66,7 @@ standardEngine.notParent=\u30a8\u30f3\u30b8\u30f3\u306f\u89aa\u306e\u30b3\u30f3\
|
||||
standardHost.clientAbort=\u30ea\u30e2\u30fc\u30c8\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u304c\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u4e2d\u6b62\u3057\u307e\u3057\u305f, IOException: [{0}]
|
||||
standardHost.invalidErrorReportValveClass=\u6307\u5b9a\u3055\u308c\u305f\u30a8\u30e9\u30fc\u30ea\u30dd\u30fc\u30c8\u30d0\u30eb\u30d6\u30af\u30e9\u30b9\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093: [{0}]
|
||||
standardHost.noContext=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u305f\u3081\u306b\u8a2d\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u3042\u308a\u307e\u305b\u3093
|
||||
+applicationHttpRequest.sessionEndAccessFail=リクエストの再利用中に行ったセッションへのアクセス終了処理で例外が送出されました。
|
||||
standardHost.notContext=\u30db\u30b9\u30c8\u306e\u5b50\u4f9b\u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093
|
||||
standardHost.nullName=\u30db\u30b9\u30c8\u540d\u304c\u5fc5\u8981\u3067\u3059
|
||||
standardService.start.name=\u30b5\u30fc\u30d3\u30b9 [{0}] \u3092\u8d77\u52d5\u3057\u307e\u3059
|
||||
diff --git a/java/org/apache/tomcat/util/buf/B2CConverter.java b/java/org/apache/tomcat/util/buf/B2CConverter.java
|
||||
index f046ad7..1e3e1f4 100644
|
||||
--- a/java/org/apache/tomcat/util/buf/B2CConverter.java
|
||||
+++ b/java/org/apache/tomcat/util/buf/B2CConverter.java
|
||||
@@ -27,6 +27,9 @@ import java.nio.charset.CodingErrorAction;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
+import org.apache.juli.logging.Log;
|
||||
+import org.apache.juli.logging.LogFactory;
|
||||
+import org.apache.tomcat.util.ExceptionUtils;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
@@ -35,6 +38,7 @@ import org.apache.tomcat.util.res.StringManager;
|
||||
* NIO based character decoder.
|
||||
*/
|
||||
public class B2CConverter {
|
||||
+ private static final Log log = LogFactory.getLog(B2CConverter.class);
|
||||
|
||||
private static final StringManager sm = StringManager.getManager(B2CConverter.class);
|
||||
|
||||
@@ -120,7 +124,12 @@ public class B2CConverter {
|
||||
* Reset the decoder state.
|
||||
*/
|
||||
public void recycle() {
|
||||
- decoder.reset();
|
||||
+ try {
|
||||
+ decoder.reset();
|
||||
+ } catch (Throwable t) {
|
||||
+ ExceptionUtils.handleThrowable(t);
|
||||
+ log.warn(sm.getString("b2cConverter.decoderResetFail", decoder.charset()), t);
|
||||
+ }
|
||||
leftovers.position(0);
|
||||
}
|
||||
|
||||
diff --git a/java/org/apache/tomcat/util/buf/C2BConverter.java b/java/org/apache/tomcat/util/buf/C2BConverter.java
|
||||
index e5062de..f3b4dd7 100644
|
||||
--- a/java/org/apache/tomcat/util/buf/C2BConverter.java
|
||||
+++ b/java/org/apache/tomcat/util/buf/C2BConverter.java
|
||||
@@ -24,11 +24,19 @@ import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CoderResult;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
|
||||
+import org.apache.juli.logging.Log;
|
||||
+import org.apache.juli.logging.LogFactory;
|
||||
+import org.apache.tomcat.util.ExceptionUtils;
|
||||
+import org.apache.tomcat.util.res.StringManager;
|
||||
+
|
||||
/**
|
||||
* NIO based character encoder.
|
||||
*/
|
||||
public final class C2BConverter {
|
||||
|
||||
+ private static final Log log = LogFactory.getLog(C2BConverter.class);
|
||||
+ private static final StringManager sm = StringManager.getManager(C2BConverter.class);
|
||||
+
|
||||
private final CharsetEncoder encoder;
|
||||
private ByteBuffer bb = null;
|
||||
private CharBuffer cb = null;
|
||||
@@ -50,7 +58,12 @@ public final class C2BConverter {
|
||||
* Reset the encoder state.
|
||||
*/
|
||||
public void recycle() {
|
||||
- encoder.reset();
|
||||
+ try {
|
||||
+ encoder.reset();
|
||||
+ } catch (Throwable t) {
|
||||
+ ExceptionUtils.handleThrowable(t);
|
||||
+ log.warn(sm.getString("c2bConverter.decoderResetFail", encoder.charset()), t);
|
||||
+ }
|
||||
leftovers.position(0);
|
||||
}
|
||||
|
||||
diff --git a/java/org/apache/tomcat/util/buf/LocalStrings.properties b/java/org/apache/tomcat/util/buf/LocalStrings.properties
|
||||
index c8a8d3b..574f6c2 100644
|
||||
--- a/java/org/apache/tomcat/util/buf/LocalStrings.properties
|
||||
+++ b/java/org/apache/tomcat/util/buf/LocalStrings.properties
|
||||
@@ -13,9 +13,12 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
+b2cConverter.decoderResetFail=Failed to reset instance of decoder for character set [{0}]
|
||||
b2cConverter.unknownEncoding=The character encoding [{0}] is not supported
|
||||
c2bConverter.recycleFailed=Failed to recycle the C2B Converter. Creating new BufferedWriter, WriteConvertor and IntermediateOutputStream.
|
||||
|
||||
+c2bConverter.encoderResetFail=Failed to reset instance of encoder for character set [{0}]
|
||||
+
|
||||
hexUtils.fromHex.oddDigits=The input must consist of an even number of hex digits
|
||||
hexUtils.fromHex.nonHex=The input must consist only of hex digits
|
||||
|
||||
--
|
||||
2.33.0
|
||||
89
CVE-2023-45648.patch
Normal file
89
CVE-2023-45648.patch
Normal file
@ -0,0 +1,89 @@
|
||||
Description: Align processing of trailer headers with standard processing
|
||||
Origin: upstream, https://github.com/apache/tomcat/commit/59583245639d8c42ae0009f4a4a70464d3ea70a0
|
||||
--- a/java/org/apache/coyote/http11/Http11InputBuffer.java
|
||||
+++ b/java/org/apache/coyote/http11/Http11InputBuffer.java
|
||||
@@ -818,6 +818,12 @@
|
||||
*/
|
||||
private HeaderParseStatus parseHeader() throws IOException {
|
||||
|
||||
+ /*
|
||||
+ * Implementation note: Any changes to this method probably need to be echoed in
|
||||
+ * ChunkedInputFilter.parseHeader(). Why not use a common implementation? In short, this code uses non-blocking
|
||||
+ * reads whereas ChunkedInputFilter using blocking reads. The code is just different enough that a common
|
||||
+ * implementation wasn't viewed as practical.
|
||||
+ */
|
||||
//
|
||||
// Check for blank line
|
||||
//
|
||||
|
||||
byte chr = 0;
|
||||
byte prevChr = 0;
|
||||
|
||||
while (headerParsePos == HeaderParsePosition.HEADER_START) {
|
||||
|
||||
// Read new bytes if needed
|
||||
@@ -950,7 +956,7 @@
|
||||
} else if (prevChr == Constants.CR) {
|
||||
// Invalid value - also need to delete header
|
||||
return skipLine(true);
|
||||
- } else if (chr != Constants.HT && HttpParser.isControl(chr)) {
|
||||
+ } else if (HttpParser.isControl(chr) && chr != Constants.HT) {
|
||||
// Invalid value - also need to delete header
|
||||
return skipLine(true);
|
||||
} else if (chr == Constants.SP || chr == Constants.HT) {
|
||||
--- a/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
|
||||
+++ b/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java
|
||||
@@ -30,6 +30,7 @@
|
||||
import org.apache.coyote.http11.InputFilter;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
import org.apache.tomcat.util.buf.HexUtils;
|
||||
+import org.apache.tomcat.util.http.parser.HttpParser;
|
||||
import org.apache.tomcat.util.net.ApplicationBufferHandler;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
@@ -443,6 +444,13 @@
|
||||
|
||||
private boolean parseHeader() throws IOException {
|
||||
|
||||
+ /*
|
||||
+ * Implementation note: Any changes to this method probably need to be echoed in
|
||||
+ * Http11InputBuffer.parseHeader(). Why not use a common implementation? In short, this code uses blocking
|
||||
+ * reads whereas Http11InputBuffer using non-blocking reads. The code is just different enough that a common
|
||||
+ * implementation wasn't viewed as practical.
|
||||
+ */
|
||||
+
|
||||
Map<String,String> headers = request.getTrailerFields();
|
||||
|
||||
byte chr = 0;
|
||||
@@ -489,6 +497,9 @@
|
||||
|
||||
if (chr == Constants.COLON) {
|
||||
colon = true;
|
||||
+ } else if (!HttpParser.isToken(chr)) {
|
||||
+ // Non-token characters are illegal in header names
|
||||
+ throw new IOException(sm.getString("chunkedInputFilter.invalidTrailerHeaderName"));
|
||||
} else {
|
||||
trailingHeaders.append(chr);
|
||||
}
|
||||
@@ -550,7 +561,9 @@
|
||||
if (chr == Constants.CR || chr == Constants.LF) {
|
||||
parseCRLF(true);
|
||||
eol = true;
|
||||
- } else if (chr == Constants.SP) {
|
||||
+ } else if (HttpParser.isControl(chr) && chr != Constants.HT) {
|
||||
+ throw new IOException(sm.getString("chunkedInputFilter.invalidTrailerHeaderValue"));
|
||||
+ } else if (chr == Constants.SP || chr == Constants.HT) {
|
||||
trailingHeaders.append(chr);
|
||||
} else {
|
||||
trailingHeaders.append(chr);
|
||||
--- a/java/org/apache/coyote/http11/filters/LocalStrings.properties
|
||||
+++ b/java/org/apache/coyote/http11/filters/LocalStrings.properties
|
||||
@@ -21,6 +21,8 @@
|
||||
chunkedInputFilter.invalidCrlfNoCR=Invalid end of line sequence (No CR before LF)
|
||||
chunkedInputFilter.invalidCrlfNoData=Invalid end of line sequence (no data available to read)
|
||||
chunkedInputFilter.invalidHeader=Invalid chunk header
|
||||
+chunkedInputFilter.invalidTrailerHeaderName=Invalid trailer header name (non-token character in name)
|
||||
+chunkedInputFilter.invalidTrailerHeaderValue=Invalid trailer header value (control character in value)
|
||||
chunkedInputFilter.maxExtension=maxExtensionSize exceeded
|
||||
chunkedInputFilter.maxTrailer=maxTrailerSize exceeded
|
||||
|
||||
579
CVE-2024-21733.patch
Normal file
579
CVE-2024-21733.patch
Normal file
@ -0,0 +1,579 @@
|
||||
From ce4b154e7b48f66bd98858626347747cd2514311 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Thomas <markt@apache.org>
|
||||
Date: Thu, 18 Feb 2021 16:41:57 +0000
|
||||
Subject: [PATCH] Ensure ReadListener.onError() is fired if client drops the
|
||||
connection
|
||||
|
||||
Origin:
|
||||
https://github.com/apache/tomcat/commit/659b28c00d94e2a9049e0a8ac1e02bd4d36dd005
|
||||
https://github.com/apache/tomcat/commit/f562edd3302866f34c0ca9fa97f6ff414450f1ae
|
||||
https://github.com/apache/tomcat/commit/918146f9d04af67d904b47c440acaab14380521b
|
||||
https://github.com/apache/tomcat/commit/504445cd2c618fb1edbfeda62e07e1c29b4d285c
|
||||
https://github.com/apache/tomcat/commit/ce4b154e7b48f66bd98858626347747cd2514311
|
||||
|
||||
---
|
||||
.../catalina/core/StandardWrapperValve.java | 2 +
|
||||
.../coyote/http11/Http11InputBuffer.java | 43 +++-
|
||||
.../coyote/http11/Http11OutputBuffer.java | 15 +-
|
||||
.../catalina/core/TestAsyncContextImpl.java | 172 +++++++++++++++-
|
||||
.../nonblocking/TestNonBlockingAPI.java | 192 ++++++++++++++++++
|
||||
5 files changed, 412 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/java/org/apache/catalina/core/StandardWrapperValve.java b/java/org/apache/catalina/core/StandardWrapperValve.java
|
||||
index 27f136a..89f5915 100644
|
||||
--- a/java/org/apache/catalina/core/StandardWrapperValve.java
|
||||
+++ b/java/org/apache/catalina/core/StandardWrapperValve.java
|
||||
@@ -29,6 +29,7 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.UnavailableException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
+import org.apache.catalina.Container;
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.Globals;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
@@ -174,6 +175,7 @@ final class StandardWrapperValve
|
||||
|
||||
// Call the filter chain for this request
|
||||
// NOTE: This also calls the servlet's service() method
|
||||
+ Container container = this.container;
|
||||
try {
|
||||
if ((servlet != null) && (filterChain != null)) {
|
||||
// Swallow output if needed
|
||||
diff --git a/java/org/apache/coyote/http11/Http11InputBuffer.java b/java/org/apache/coyote/http11/Http11InputBuffer.java
|
||||
index 27392d4..db596b4 100644
|
||||
--- a/java/org/apache/coyote/http11/Http11InputBuffer.java
|
||||
+++ b/java/org/apache/coyote/http11/Http11InputBuffer.java
|
||||
@@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
+import org.apache.coyote.CloseNowException;
|
||||
import org.apache.coyote.InputBuffer;
|
||||
import org.apache.coyote.Request;
|
||||
import org.apache.juli.logging.Log;
|
||||
@@ -382,10 +383,6 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
|
||||
|
||||
parsingRequestLineStart = byteBuffer.position();
|
||||
parsingRequestLinePhase = 2;
|
||||
- if (log.isDebugEnabled()) {
|
||||
- log.debug("Received ["
|
||||
- + new String(byteBuffer.array(), byteBuffer.position(), byteBuffer.remaining(), StandardCharsets.ISO_8859_1) + "]");
|
||||
- }
|
||||
}
|
||||
if (parsingRequestLinePhase == 2) {
|
||||
//
|
||||
@@ -709,6 +706,16 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
|
||||
*/
|
||||
private boolean fill(boolean block) throws IOException {
|
||||
|
||||
+ if (log.isDebugEnabled()) {
|
||||
+ log.debug("Before fill(): parsingHeader: [" + parsingHeader +
|
||||
+ "], parsingRequestLine: [" + parsingRequestLine +
|
||||
+ "], parsingRequestLinePhase: [" + parsingRequestLinePhase +
|
||||
+ "], parsingRequestLineStart: [" + parsingRequestLineStart +
|
||||
+ "], byteBuffer.position(): [" + byteBuffer.position() +
|
||||
+ "], byteBuffer.limit(): [" + byteBuffer.limit() +
|
||||
+ "], end: [" + end + "]");
|
||||
+ }
|
||||
+
|
||||
if (parsingHeader) {
|
||||
if (byteBuffer.limit() >= headerBufferSize) {
|
||||
if (parsingRequestLine) {
|
||||
@@ -721,13 +728,31 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
|
||||
byteBuffer.limit(end).position(end);
|
||||
}
|
||||
|
||||
+ int nRead = -1;
|
||||
byteBuffer.mark();
|
||||
- if (byteBuffer.position() < byteBuffer.limit()) {
|
||||
- byteBuffer.position(byteBuffer.limit());
|
||||
+ try {
|
||||
+ if (byteBuffer.position() < byteBuffer.limit()) {
|
||||
+ byteBuffer.position(byteBuffer.limit());
|
||||
+ }
|
||||
+ byteBuffer.limit(byteBuffer.capacity());
|
||||
+ SocketWrapperBase<?> socketWrapper = this.wrapper;
|
||||
+ if (socketWrapper != null) {
|
||||
+ nRead = socketWrapper.read(block, byteBuffer);
|
||||
+ } else {
|
||||
+ throw new CloseNowException(sm.getString("iib.eof.error"));
|
||||
+ }
|
||||
+ } finally {
|
||||
+ // Ensure that the buffer limit and position are returned to a
|
||||
+ // consistent "ready for read" state if an error occurs during in
|
||||
+ // the above code block.
|
||||
+ byteBuffer.limit(byteBuffer.position()).reset();
|
||||
}
|
||||
- byteBuffer.limit(byteBuffer.capacity());
|
||||
- int nRead = wrapper.read(block, byteBuffer);
|
||||
- byteBuffer.limit(byteBuffer.position()).reset();
|
||||
+
|
||||
+ if (log.isDebugEnabled()) {
|
||||
+ log.debug("Received ["
|
||||
+ + new String(byteBuffer.array(), byteBuffer.position(), byteBuffer.remaining(), StandardCharsets.ISO_8859_1) + "]");
|
||||
+ }
|
||||
+
|
||||
if (nRead > 0) {
|
||||
return true;
|
||||
} else if (nRead == -1) {
|
||||
diff --git a/java/org/apache/coyote/http11/Http11OutputBuffer.java b/java/org/apache/coyote/http11/Http11OutputBuffer.java
|
||||
index aa5ad48..c369837 100644
|
||||
--- a/java/org/apache/coyote/http11/Http11OutputBuffer.java
|
||||
+++ b/java/org/apache/coyote/http11/Http11OutputBuffer.java
|
||||
@@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.coyote.ActionCode;
|
||||
+import org.apache.coyote.CloseNowException;
|
||||
import org.apache.coyote.Response;
|
||||
import org.apache.tomcat.util.buf.ByteChunk;
|
||||
import org.apache.tomcat.util.buf.MessageBytes;
|
||||
@@ -303,7 +304,12 @@ public class Http11OutputBuffer implements HttpOutputBuffer {
|
||||
// Sending the response header buffer
|
||||
headerBuffer.flip();
|
||||
try {
|
||||
- socketWrapper.write(isBlocking(), headerBuffer);
|
||||
+ SocketWrapperBase<?> socketWrapper = this.socketWrapper;
|
||||
+ if (socketWrapper != null) {
|
||||
+ socketWrapper.write(isBlocking(), headerBuffer);
|
||||
+ } else {
|
||||
+ throw new CloseNowException(sm.getString("iob.failedwrite"));
|
||||
+ }
|
||||
} finally {
|
||||
headerBuffer.position(0).limit(headerBuffer.capacity());
|
||||
}
|
||||
@@ -527,7 +533,12 @@ public class Http11OutputBuffer implements HttpOutputBuffer {
|
||||
public int doWrite(ByteBuffer chunk) throws IOException {
|
||||
try {
|
||||
int len = chunk.remaining();
|
||||
- socketWrapper.write(isBlocking(), chunk);
|
||||
+ SocketWrapperBase<?> socketWrapper = Http11OutputBuffer.this.socketWrapper;
|
||||
+ if (socketWrapper != null) {
|
||||
+ socketWrapper.write(isBlocking(), chunk);
|
||||
+ } else {
|
||||
+ throw new CloseNowException(sm.getString("iob.failedwrite"));
|
||||
+ }
|
||||
len -= chunk.remaining();
|
||||
byteCount += len;
|
||||
return len;
|
||||
diff --git a/test/org/apache/catalina/core/TestAsyncContextImpl.java b/test/org/apache/catalina/core/TestAsyncContextImpl.java
|
||||
index 3f6524b..4023a74 100644
|
||||
--- a/test/org/apache/catalina/core/TestAsyncContextImpl.java
|
||||
+++ b/test/org/apache/catalina/core/TestAsyncContextImpl.java
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.apache.catalina.core;
|
||||
|
||||
import java.io.IOException;
|
||||
+import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
@@ -819,7 +820,7 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
|
||||
}
|
||||
}
|
||||
|
||||
- private static class TrackingListener implements AsyncListener {
|
||||
+ public static class TrackingListener implements AsyncListener {
|
||||
|
||||
private final boolean completeOnError;
|
||||
private final boolean completeOnTimeout;
|
||||
@@ -2653,4 +2654,173 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
|
||||
}
|
||||
|
||||
}
|
||||
+
|
||||
+
|
||||
+
|
||||
+ /*
|
||||
+ * Tests an error on an async thread when the client closes the connection
|
||||
+ * before fully writing the request body.
|
||||
+ *
|
||||
+ * Required sequence is:
|
||||
+ * - enter Servlet's service() method
|
||||
+ * - startAsync()
|
||||
+ * - start async thread
|
||||
+ * - read partial body
|
||||
+ * - close client connection
|
||||
+ * - read on async thread -> I/O error
|
||||
+ * - exit Servlet's service() method
|
||||
+ *
|
||||
+ * This test makes extensive use of instance fields in the Servlet that
|
||||
+ * would normally be considered very poor practice. It is only safe in this
|
||||
+ * test as the Servlet only processes a single request.
|
||||
+ */
|
||||
+ @Test
|
||||
+ public void testCanceledPost() throws Exception {
|
||||
+ CountDownLatch partialReadLatch = new CountDownLatch(1);
|
||||
+ CountDownLatch clientCloseLatch = new CountDownLatch(1);
|
||||
+ CountDownLatch threadCompleteLatch = new CountDownLatch(1);
|
||||
+
|
||||
+ AtomicBoolean testFailed = new AtomicBoolean(true);
|
||||
+
|
||||
+ // Setup Tomcat instance
|
||||
+ Tomcat tomcat = getTomcatInstance();
|
||||
+
|
||||
+ // No file system docBase required
|
||||
+ Context ctx = tomcat.addContext("", null);
|
||||
+
|
||||
+ PostServlet postServlet = new PostServlet(partialReadLatch, clientCloseLatch, threadCompleteLatch, testFailed);
|
||||
+ Wrapper wrapper = Tomcat.addServlet(ctx, "postServlet", postServlet);
|
||||
+ wrapper.setAsyncSupported(true);
|
||||
+ ctx.addServletMappingDecoded("/*", "postServlet");
|
||||
+
|
||||
+ tomcat.start();
|
||||
+
|
||||
+ PostClient client = new PostClient();
|
||||
+ client.setPort(getPort());
|
||||
+ client.setRequest(new String[] { "POST / HTTP/1.1" + SimpleHttpClient.CRLF +
|
||||
+ "Host: localhost:" + SimpleHttpClient.CRLF +
|
||||
+ "Content-Length: 100" + SimpleHttpClient.CRLF +
|
||||
+ SimpleHttpClient.CRLF +
|
||||
+ "This is 16 bytes"
|
||||
+ });
|
||||
+ client.connect();
|
||||
+ client.sendRequest();
|
||||
+
|
||||
+ // Wait server to read partial request body
|
||||
+ partialReadLatch.await();
|
||||
+
|
||||
+ client.disconnect();
|
||||
+
|
||||
+ clientCloseLatch.countDown();
|
||||
+
|
||||
+ threadCompleteLatch.await();
|
||||
+
|
||||
+ Assert.assertFalse(testFailed.get());
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ private static final class PostClient extends SimpleHttpClient {
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isResponseBodyOK() {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ private static final class PostServlet extends HttpServlet {
|
||||
+
|
||||
+ private static final long serialVersionUID = 1L;
|
||||
+
|
||||
+ private final transient CountDownLatch partialReadLatch;
|
||||
+ private final transient CountDownLatch clientCloseLatch;
|
||||
+ private final transient CountDownLatch threadCompleteLatch;
|
||||
+ private final AtomicBoolean testFailed;
|
||||
+
|
||||
+ public PostServlet(CountDownLatch doPostLatch, CountDownLatch clientCloseLatch,
|
||||
+ CountDownLatch threadCompleteLatch, AtomicBoolean testFailed) {
|
||||
+ this.partialReadLatch = doPostLatch;
|
||||
+ this.clientCloseLatch = clientCloseLatch;
|
||||
+ this.threadCompleteLatch = threadCompleteLatch;
|
||||
+ this.testFailed = testFailed;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
|
||||
+ throws ServletException, IOException {
|
||||
+
|
||||
+ AsyncContext ac = req.startAsync();
|
||||
+ Thread t = new PostServletThread(ac, partialReadLatch, clientCloseLatch, threadCompleteLatch, testFailed);
|
||||
+ t.start();
|
||||
+
|
||||
+ try {
|
||||
+ threadCompleteLatch.await();
|
||||
+ } catch (InterruptedException e) {
|
||||
+ // Ignore
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ private static final class PostServletThread extends Thread {
|
||||
+
|
||||
+ private final AsyncContext ac;
|
||||
+ private final CountDownLatch partialReadLatch;
|
||||
+ private final CountDownLatch clientCloseLatch;
|
||||
+ private final CountDownLatch threadCompleteLatch;
|
||||
+ private final AtomicBoolean testFailed;
|
||||
+
|
||||
+ public PostServletThread(AsyncContext ac, CountDownLatch partialReadLatch, CountDownLatch clientCloseLatch,
|
||||
+ CountDownLatch threadCompleteLatch, AtomicBoolean testFailed) {
|
||||
+ this.ac = ac;
|
||||
+ this.partialReadLatch = partialReadLatch;
|
||||
+ this.clientCloseLatch = clientCloseLatch;
|
||||
+ this.threadCompleteLatch = threadCompleteLatch;
|
||||
+ this.testFailed = testFailed;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void run() {
|
||||
+ try {
|
||||
+ int bytesRead = 0;
|
||||
+ byte[] buffer = new byte[32];
|
||||
+ InputStream is = null;
|
||||
+
|
||||
+ try {
|
||||
+ is = ac.getRequest().getInputStream();
|
||||
+
|
||||
+ // Read the partial request body
|
||||
+ while (bytesRead < 16) {
|
||||
+ int read = is.read(buffer);
|
||||
+ if (read == -1) {
|
||||
+ // Error condition
|
||||
+ return;
|
||||
+ }
|
||||
+ bytesRead += read;
|
||||
+ }
|
||||
+ } catch (IOException ioe) {
|
||||
+ // Error condition
|
||||
+ return;
|
||||
+ } finally {
|
||||
+ partialReadLatch.countDown();
|
||||
+ }
|
||||
+
|
||||
+ // Wait for client to close connection
|
||||
+ clientCloseLatch.await();
|
||||
+
|
||||
+ // Read again
|
||||
+ try {
|
||||
+ is.read();
|
||||
+ } catch (IOException e) {
|
||||
+ e.printStackTrace();
|
||||
+ // Required. Clear the error marker.
|
||||
+ testFailed.set(false);
|
||||
+ }
|
||||
+ } catch (InterruptedException e) {
|
||||
+ // Ignore
|
||||
+ } finally {
|
||||
+ threadCompleteLatch.countDown();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
diff --git a/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java b/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java
|
||||
index 7130b11..6868375 100644
|
||||
--- a/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java
|
||||
+++ b/test/org/apache/catalina/nonblocking/TestNonBlockingAPI.java
|
||||
@@ -32,6 +32,9 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
+import java.util.concurrent.atomic.AtomicBoolean;
|
||||
+import java.util.logging.Level;
|
||||
+import java.util.logging.LogManager;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
import javax.servlet.AsyncContext;
|
||||
@@ -44,6 +47,7 @@ import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.WriteListener;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
+import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -52,7 +56,9 @@ import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
+import org.apache.catalina.Wrapper;
|
||||
import org.apache.catalina.startup.BytesStreamer;
|
||||
+import org.apache.catalina.startup.SimpleHttpClient;
|
||||
import org.apache.catalina.startup.TesterServlet;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.catalina.startup.TomcatBaseTest;
|
||||
@@ -997,4 +1003,190 @@ public class TestNonBlockingAPI extends TomcatBaseTest {
|
||||
|
||||
}
|
||||
}
|
||||
+
|
||||
+
|
||||
+ /*
|
||||
+ * Tests an error on an non-blocking read when the client closes the
|
||||
+ * connection before fully writing the request body.
|
||||
+ *
|
||||
+ * Required sequence is:
|
||||
+ * - enter Servlet's service() method
|
||||
+ * - startAsync()
|
||||
+ * - configure non-blocking read
|
||||
+ * - read partial body
|
||||
+ * - close client connection
|
||||
+ * - error is triggered
|
||||
+ * - exit Servlet's service() method
|
||||
+ *
|
||||
+ * This test makes extensive use of instance fields in the Servlet that
|
||||
+ * would normally be considered very poor practice. It is only safe in this
|
||||
+ * test as the Servlet only processes a single request.
|
||||
+ */
|
||||
+ @Test
|
||||
+ public void testCanceledPost() throws Exception {
|
||||
+
|
||||
+ LogManager.getLogManager().getLogger("org.apache.coyote").setLevel(Level.ALL);
|
||||
+ LogManager.getLogManager().getLogger("org.apache.tomcat.util.net").setLevel(Level.ALL);
|
||||
+
|
||||
+ CountDownLatch partialReadLatch = new CountDownLatch(1);
|
||||
+ CountDownLatch completeLatch = new CountDownLatch(1);
|
||||
+
|
||||
+ AtomicBoolean testFailed = new AtomicBoolean(true);
|
||||
+
|
||||
+ // Setup Tomcat instance
|
||||
+ Tomcat tomcat = getTomcatInstance();
|
||||
+
|
||||
+ // No file system docBase required
|
||||
+ Context ctx = tomcat.addContext("", null);
|
||||
+
|
||||
+ PostServlet postServlet = new PostServlet(partialReadLatch, completeLatch, testFailed);
|
||||
+ Wrapper wrapper = Tomcat.addServlet(ctx, "postServlet", postServlet);
|
||||
+ wrapper.setAsyncSupported(true);
|
||||
+ ctx.addServletMappingDecoded("/*", "postServlet");
|
||||
+
|
||||
+ tomcat.start();
|
||||
+
|
||||
+ PostClient client = new PostClient();
|
||||
+ client.setPort(getPort());
|
||||
+ client.setRequest(new String[] { "POST / HTTP/1.1" + SimpleHttpClient.CRLF +
|
||||
+ "Host: localhost:" + SimpleHttpClient.CRLF +
|
||||
+ "Content-Length: 100" + SimpleHttpClient.CRLF +
|
||||
+ SimpleHttpClient.CRLF +
|
||||
+ "This is 16 bytes"
|
||||
+ });
|
||||
+ client.connect();
|
||||
+ client.sendRequest();
|
||||
+
|
||||
+ // Wait server to read partial request body
|
||||
+ partialReadLatch.await();
|
||||
+
|
||||
+ client.disconnect();
|
||||
+
|
||||
+ completeLatch.await();
|
||||
+
|
||||
+ Assert.assertFalse(testFailed.get());
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ private static final class PostClient extends SimpleHttpClient {
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isResponseBodyOK() {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ private static final class PostServlet extends HttpServlet {
|
||||
+
|
||||
+ private static final long serialVersionUID = 1L;
|
||||
+
|
||||
+ private final transient CountDownLatch partialReadLatch;
|
||||
+ private final transient CountDownLatch completeLatch;
|
||||
+ private final AtomicBoolean testFailed;
|
||||
+
|
||||
+ public PostServlet(CountDownLatch doPostLatch, CountDownLatch completeLatch, AtomicBoolean testFailed) {
|
||||
+ this.partialReadLatch = doPostLatch;
|
||||
+ this.completeLatch = completeLatch;
|
||||
+ this.testFailed = testFailed;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
|
||||
+ throws ServletException, IOException {
|
||||
+
|
||||
+ AsyncContext ac = req.startAsync();
|
||||
+ ac.setTimeout(-1);
|
||||
+ CanceledPostAsyncListener asyncListener = new CanceledPostAsyncListener(completeLatch);
|
||||
+ ac.addListener(asyncListener);
|
||||
+
|
||||
+ CanceledPostReadListener readListener = new CanceledPostReadListener(ac, partialReadLatch, testFailed);
|
||||
+ req.getInputStream().setReadListener(readListener);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ private static final class CanceledPostAsyncListener implements AsyncListener {
|
||||
+
|
||||
+ private final transient CountDownLatch completeLatch;
|
||||
+
|
||||
+ public CanceledPostAsyncListener(CountDownLatch completeLatch) {
|
||||
+ this.completeLatch = completeLatch;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onComplete(AsyncEvent event) throws IOException {
|
||||
+ System.out.println("complete");
|
||||
+ completeLatch.countDown();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onTimeout(AsyncEvent event) throws IOException {
|
||||
+ System.out.println("onTimeout");
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onError(AsyncEvent event) throws IOException {
|
||||
+ System.out.println("onError-async");
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onStartAsync(AsyncEvent event) throws IOException {
|
||||
+ System.out.println("onStartAsync");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static final class CanceledPostReadListener implements ReadListener {
|
||||
+
|
||||
+ private final AsyncContext ac;
|
||||
+ private final CountDownLatch partialReadLatch;
|
||||
+ private final AtomicBoolean testFailed;
|
||||
+ private int totalRead = 0;
|
||||
+
|
||||
+ public CanceledPostReadListener(AsyncContext ac, CountDownLatch partialReadLatch, AtomicBoolean testFailed) {
|
||||
+ this.ac = ac;
|
||||
+ this.partialReadLatch = partialReadLatch;
|
||||
+ this.testFailed = testFailed;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onDataAvailable() throws IOException {
|
||||
+ ServletInputStream sis = ac.getRequest().getInputStream();
|
||||
+ boolean isReady;
|
||||
+
|
||||
+ byte[] buffer = new byte[32];
|
||||
+ do {
|
||||
+ if (partialReadLatch.getCount() == 0) {
|
||||
+ System.out.println("debug");
|
||||
+ }
|
||||
+ int bytesRead = sis.read(buffer);
|
||||
+
|
||||
+ if (bytesRead == -1) {
|
||||
+ return;
|
||||
+ }
|
||||
+ totalRead += bytesRead;
|
||||
+ isReady = sis.isReady();
|
||||
+ System.out.println("Read [" + bytesRead +
|
||||
+ "], buffer [" + new String(buffer, 0, bytesRead, StandardCharsets.UTF_8) +
|
||||
+ "], total read [" + totalRead +
|
||||
+ "], isReady [" + isReady + "]");
|
||||
+ } while (isReady);
|
||||
+ if (totalRead == 16) {
|
||||
+ partialReadLatch.countDown();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onAllDataRead() throws IOException {
|
||||
+ ac.complete();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void onError(Throwable throwable) {
|
||||
+ throwable.printStackTrace();
|
||||
+ // This is the expected behaviour so clear the failed flag.
|
||||
+ testFailed.set(false);
|
||||
+ ac.complete();
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
--
|
||||
2.33.0
|
||||
|
||||
32
tomcat.spec
32
tomcat.spec
@ -13,7 +13,7 @@
|
||||
Name: tomcat
|
||||
Epoch: 1
|
||||
Version: %{major_version}.%{minor_version}.%{micro_version}
|
||||
Release: 28
|
||||
Release: 33
|
||||
Summary: Implementation of the Java Servlet, JavaServer Pages, Java Expression Language and Java WebSocket technologies
|
||||
License: ASL 2.0
|
||||
URL: http://tomcat.apache.org/
|
||||
@ -101,6 +101,15 @@ Patch6056: CVE-2021-30640-8.patch
|
||||
Patch6057: CVE-2021-41079.patch
|
||||
Patch6058: CVE-2021-42340.patch
|
||||
Patch6069: CVE-2022-23181.patch
|
||||
Patch6070: CVE-2022-42252.patch
|
||||
Patch6071: CVE-2023-28708-pre.patch
|
||||
Patch6072: CVE-2023-28708.patch
|
||||
Patch6073: CVE-2023-41080.patch
|
||||
Patch6074: CVE-2023-45648.patch
|
||||
Patch6075: CVE-2024-21733.patch
|
||||
Patch6076: CVE-2023-24998.patch
|
||||
Patch6077: CVE-2023-28709.patch
|
||||
Patch6078: CVE-2023-42795.patch
|
||||
|
||||
BuildRequires: ecj >= 1:4.6.1 findutils apache-commons-collections apache-commons-daemon
|
||||
BuildRequires: apache-commons-dbcp apache-commons-pool tomcat-taglibs-standard ant
|
||||
@ -108,9 +117,8 @@ BuildRequires: jpackage-utils >= 0:1.7.0 java-devel >= 1:1.8.0 junit javapackage
|
||||
BuildRequires: geronimo-saaj aqute-bndlib aqute-bnd systemd-units wsdl4j geronimo-jaxrpc
|
||||
|
||||
Requires: procps jpackage-utils java-headless >= 1:1.8.0 apache-commons-daemon
|
||||
Requires: tomcat-taglibs-standard >= 0:1.1 ecj
|
||||
|
||||
Requires: libtcnative-1-0 >= 1.2.14
|
||||
Requires: tomcat-taglibs-standard >= 0:1.1 ecj libtcnative-1-0 >= 1.2.14
|
||||
Requires: apache-commons-dbcp apache-commons-pool apache-commons-collections
|
||||
|
||||
Requires(pre): shadow-utils
|
||||
Requires(post): chkconfig
|
||||
@ -502,6 +510,22 @@ fi
|
||||
%{_javadocdir}/%{name}
|
||||
|
||||
%changelog
|
||||
* Tue Jan 23 2024 wangkai <13474090681@163.com> - 1:9.0.10-33
|
||||
- Fix CVE-2024-21733,CVE-2023-24998,CVE-2023-28709,CVE-2023-42795
|
||||
|
||||
* Fri Oct 20 2023 wangkai <13474090681@163.com> - 1:9.0.10-32
|
||||
- Fix CVE-2023-45648
|
||||
|
||||
* Thu Sep 07 2023 wangkai <13474090681@163.com> - 1:9.0.10-31
|
||||
- Fix CVE-2023-41080
|
||||
- Add requires apache-commons-dbcp,pool,collections for fix path error
|
||||
|
||||
* Mon Apr 17 2023 wangkai <13474090681@163.com> - 1:9.0.10-30
|
||||
- Fix CVE-2023-28708
|
||||
|
||||
* Wed Dec 21 2022 xulei <xulei@xfusion.com> - 1:9.0.10-29
|
||||
- Fix CVE-2022-42252
|
||||
|
||||
* Fri Aug 12 2022 liyanan <liyanan32@h-partners.com> - 1:9.0.10-28
|
||||
- Update build-classpath calls to ECJ to specify the JAR we want to use
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user