diff --git a/java/org/apache/catalina/connector/LocalStrings.properties b/java/org/apache/catalina/connector/LocalStrings.properties index 5cfd969f138e..b0b9bba4384b 100644 --- a/java/org/apache/catalina/connector/LocalStrings.properties +++ b/java/org/apache/catalina/connector/LocalStrings.properties @@ -47,6 +47,7 @@ coyoteRequest.attributeEvent=Exception thrown by attributes event listener coyoteRequest.authenticate.ise=Cannot call authenticate() after the response has been committed coyoteRequest.changeSessionId=Cannot change session ID. There is no session associated with this request. 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.deletePartFailed=Failed to deleted temporary file used for part [{0}] coyoteRequest.filterAsyncSupportUnknown=Unable to determine if any filters do not support async processing coyoteRequest.getContextPath.ise=Unable to find match between the canonical context path [{0}] and the URI presented by the user agent [{1}] coyoteRequest.getInputStream.ise=getReader() has already been called for this request diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java index 8bf3c678f822..9253d2b9741c 100644 --- a/java/org/apache/catalina/connector/Request.java +++ b/java/org/apache/catalina/connector/Request.java @@ -449,8 +449,9 @@ public void recycle() { 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; @@ -501,10 +502,10 @@ public void recycle() { } asyncSupported = null; - if (asyncContext!=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 6d6dd6fe38b3..0c36f12a0b71 100644 --- a/java/org/apache/catalina/core/ApplicationHttpRequest.java +++ b/java/org/apache/catalina/core/ApplicationHttpRequest.java @@ -48,6 +48,7 @@ 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; @@ -650,7 +651,12 @@ public PushBuilder newPushBuilder() { */ 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 bc9778aa87f1..07b47be59499 100644 --- a/java/org/apache/catalina/core/LocalStrings.properties +++ b/java/org/apache/catalina/core/LocalStrings.properties @@ -59,6 +59,7 @@ applicationFilterRegistration.nullInitParam=Unable to set initialisation paramet applicationFilterRegistration.nullInitParams=Unable to set initialisation parameters for filter due to null name and/or value. Name [{0}], Value [{1}] applicationHttpRequest.fragmentInDispatchPath=The fragment in dispatch path [{0}] has been removed +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 diff --git a/java/org/apache/catalina/core/LocalStrings_cs.properties b/java/org/apache/catalina/core/LocalStrings_cs.properties index 0128dad5e42f..81c77bba79d8 100644 --- a/java/org/apache/catalina/core/LocalStrings_cs.properties +++ b/java/org/apache/catalina/core/LocalStrings_cs.properties @@ -24,6 +24,8 @@ applicationDispatcher.specViolation.response=Původní ServletResponse nebo zapo applicationFilterRegistration.nullInitParams=Není možné nastavit inicializační parametry pro filtr kvůli hodnotě null ve jménu či hodnotě. Jméno [{0}], Hodnota [{1}] +applicationHttpRequest.sessionEndAccessFail=Výjimka vyvolala ukončení přístupu k session během recykllování dotazu + aprListener.initializingFIPS=Inicializace FIPS módu... containerBase.backgroundProcess.cluster=Výjimka při zpracování procesu na pozadí v clusteru [{0}] diff --git a/java/org/apache/catalina/core/LocalStrings_es.properties b/java/org/apache/catalina/core/LocalStrings_es.properties index 08b22453c44a..6bc44fc26996 100644 --- a/java/org/apache/catalina/core/LocalStrings_es.properties +++ b/java/org/apache/catalina/core/LocalStrings_es.properties @@ -52,6 +52,8 @@ applicationFilterConfig.jmxUnregisterFail=Ha fallado el desregistro JMX para el applicationFilterRegistration.nullInitParam=No puedo poner el parámetro de inicialización para el filtro debido a un nombre nulo y/o valor. Nombre [{0}], Valor [{1}] applicationFilterRegistration.nullInitParams=No puedo poner los parámetros de inicialización 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ón Null para el servlet [{0}] desplegado en el contexto con el nombre [{1}] applicationServletRegistration.setServletSecurity.ise=No se pueden añadir restricciones de seguridad al servlet [{0}] desplegado en el contexto con el nombre [{1}] ya que el contexto ya ha sido inicializado. diff --git a/java/org/apache/catalina/core/LocalStrings_fr.properties b/java/org/apache/catalina/core/LocalStrings_fr.properties index 90003dac4914..d492971538e0 100644 --- a/java/org/apache/catalina/core/LocalStrings_fr.properties +++ b/java/org/apache/catalina/core/LocalStrings_fr.properties @@ -59,6 +59,7 @@ applicationFilterRegistration.nullInitParam=Impossible de fixer le paramètre d' applicationFilterRegistration.nullInitParams=Impossible de fixer les paramètres d''initialisation du filtre, à cause d''un nom ou d''une valeur nulle, nom [{0}], valeur [{1}] applicationHttpRequest.fragmentInDispatchPath=Le fragment dans le chemin de dispatch [{0}] a été enlevé +applicationHttpRequest.sessionEndAccessFail=Exception lancée durant l'arrêt de l'accès à la session durant le recyclage de la requête applicationPushBuilder.methodInvalid=La méthode HTTP pour une requête push doit être à la fois être sans danger et pouvoir être mise en cache, mais [{0}] ne correspond pas applicationPushBuilder.methodNotToken=Les méthodes HTTP doivent être des "token", mais [{0}] contient un caractère invalide dans un token. diff --git a/java/org/apache/catalina/core/LocalStrings_ja.properties b/java/org/apache/catalina/core/LocalStrings_ja.properties index 3385b29b5a33..900a069e24c3 100644 --- a/java/org/apache/catalina/core/LocalStrings_ja.properties +++ b/java/org/apache/catalina/core/LocalStrings_ja.properties @@ -59,6 +59,7 @@ applicationFilterRegistration.nullInitParam=NULLの名前や値のためにフ applicationFilterRegistration.nullInitParams=キー [{0}] または値 [{1}] のいずれかが null のためフィルターの初期化パラメータを設定できませんでした。 applicationHttpRequest.fragmentInDispatchPath=ディスパッチパス [{0}] 中のフラグメントは除去されました +applicationHttpRequest.sessionEndAccessFail=リクエストの再利用中に行ったセッションへのアクセス終了処理で例外が送出されました。 applicationPushBuilder.methodInvalid=プッシュリクエストの HTTP メソッドはキャッシュ可能、かつ、安全でなければなりません。[{0}] は指定できません。 applicationPushBuilder.methodNotToken=HTTP メソッド [{0}] にトークンとして利用できない文字が含まれています。 diff --git a/java/org/apache/catalina/core/LocalStrings_ko.properties b/java/org/apache/catalina/core/LocalStrings_ko.properties index a6d06bdb4828..7f95b55c5a92 100644 --- a/java/org/apache/catalina/core/LocalStrings_ko.properties +++ b/java/org/apache/catalina/core/LocalStrings_ko.properties @@ -59,6 +59,7 @@ applicationFilterRegistration.nullInitParam=이름 또는 값 또는 둘 다 널 applicationFilterRegistration.nullInitParams=널인 이름 또는 값 때문에, 필터의 초기화 파라미터를 설정할 수 없습니다. 이름: [{0}], 값: [{1}] applicationHttpRequest.fragmentInDispatchPath=디스패치 경로 [{0}](으)로부터 URI fragment를 제거했습니다. +applicationHttpRequest.sessionEndAccessFail=요청을 참조 해제하는 과정에서, 세션에 대한 접근을 종료시키려 개시하는 중 예외 발생 applicationPushBuilder.methodInvalid=PUSH 요청을 위한 HTTP 메소드는 반드시 캐시 가능하고 안전해야 하는데, [{0}]은(는) 그렇지 않습니다. applicationPushBuilder.methodNotToken=HTTP 메소드들은 토큰들이어야 하지만, [{0}]은(는) 토큰이 아닌 문자를 포함하고 있습니다. diff --git a/java/org/apache/catalina/core/LocalStrings_zh_CN.properties b/java/org/apache/catalina/core/LocalStrings_zh_CN.properties index b71c7ae34cfd..2e73d09016fe 100644 --- a/java/org/apache/catalina/core/LocalStrings_zh_CN.properties +++ b/java/org/apache/catalina/core/LocalStrings_zh_CN.properties @@ -60,6 +60,7 @@ applicationFilterRegistration.nullInitParam=由于名称和/或值为空,无 applicationFilterRegistration.nullInitParams=由于name和(或)value为null,无法为过滤器设置初始化参数。name为 [{0}],value为 [{1}] applicationHttpRequest.fragmentInDispatchPath=调度路径[{0}]中的片段已被删除 +applicationHttpRequest.sessionEndAccessFail=在回收请求时,异常触发了对会话的结束访问。 applicationPushBuilder.methodInvalid=推送请求的HTTP方法必须既可缓存又安全,但是[{0}]不是 applicationPushBuilder.methodNotToken=HTTP方法必须是令牌(token),但 [{0}] 包含非令牌字符 diff --git a/java/org/apache/coyote/http11/Http11InputBuffer.java b/java/org/apache/coyote/http11/Http11InputBuffer.java index ddd7e2d1e2eb..4b663c2e4df1 100644 --- a/java/org/apache/coyote/http11/Http11InputBuffer.java +++ b/java/org/apache/coyote/http11/Http11InputBuffer.java @@ -851,6 +851,12 @@ private boolean fill(boolean block) throws IOException { */ 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. + */ while (headerParsePos == HeaderParsePosition.HEADER_START) { // Read new bytes if needed @@ -989,7 +995,7 @@ private HeaderParseStatus parseHeader() throws IOException { } 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) { diff --git a/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java b/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java index 586d070f4d15..e2fdb0ae2e63 100644 --- 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; @@ -444,6 +445,13 @@ protected void parseEndChunk() throws IOException { 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 headers = request.getTrailerFields(); byte chr = 0; @@ -490,6 +498,9 @@ private boolean parseHeader() throws IOException { 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); } @@ -551,7 +562,9 @@ private boolean parseHeader() throws IOException { 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); diff --git a/java/org/apache/coyote/http11/filters/LocalStrings.properties b/java/org/apache/coyote/http11/filters/LocalStrings.properties index c0dc9d1b10f7..aa1b19d83922 100644 --- a/java/org/apache/coyote/http11/filters/LocalStrings.properties +++ b/java/org/apache/coyote/http11/filters/LocalStrings.properties @@ -21,6 +21,8 @@ chunkedInputFilter.invalidCrlfCRCR=Invalid end of line sequence (CRCR) 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 diff --git a/java/org/apache/tomcat/util/buf/B2CConverter.java b/java/org/apache/tomcat/util/buf/B2CConverter.java index 532c209ec98f..98f989b0f7d2 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.StandardCharsets; import java.util.Locale; +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; /** @@ -34,6 +37,7 @@ */ public class B2CConverter { + private static final Log log = LogFactory.getLog(B2CConverter.class); private static final StringManager sm = StringManager.getManager(B2CConverter.class); private static final CharsetCache charsetCache = new CharsetCache(); @@ -106,7 +110,12 @@ public B2CConverter(Charset charset, boolean replaceOnError) { * 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 4b27f6c98064..df23d5bb1704 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.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 C2BConverter(Charset charset) { * 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 cd883e6f572f..25cdd8d4f957 100644 --- a/java/org/apache/tomcat/util/buf/LocalStrings.properties +++ b/java/org/apache/tomcat/util/buf/LocalStrings.properties @@ -16,10 +16,13 @@ asn1Parser.lengthInvalid=Invalid length [{0}] bytes reported when the input data length is [{1}] bytes asn1Parser.tagMismatch=Expected to find value [{0}] but found value [{1}] +b2cConverter.decoderResetFail=Failed to reset instance of decoder for character set [{0}] b2cConverter.unknownEncoding=The character encoding [{0}] is not supported byteBufferUtils.cleaner=Cannot use direct ByteBuffer cleaner, memory leaking may occur +c2bConverter.encoderResetFail=Failed to reset instance of encoder for character set [{0}] + chunk.overflow=Buffer overflow and no sink is set, limit [{0}] and buffer length [{1}] encodedSolidusHandling.invalid=The value [{0}] is not recognised diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 7e374997a358..2be4fd7904e9 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -133,6 +133,10 @@ RemoteIpFilter determines that this request was submitted via a secure channel. (lihan) + + Improve handling of failures within recycle() methods. + (markt) + @@ -150,6 +154,9 @@ malformed content-length header should always be rejected with a 400 response. (markt) + + Align validation of HTTP trailer fields with standard fields. (markt) +