[Git][java-team/undertow][upstream] New upstream version 2.1.1

Markus Koschany gitlab at salsa.debian.org
Sun May 17 21:01:29 BST 2020



Markus Koschany pushed to branch upstream at Debian Java Maintainers / undertow


Commits:
31090dc6 by Markus Koschany at 2020-05-17T21:59:41+02:00
New upstream version 2.1.1
- - - - -


30 changed files:

- benchmarks/pom.xml
- core/pom.xml
- core/src/main/java/io/undertow/UndertowLogger.java
- core/src/main/java/io/undertow/UndertowMessages.java
- core/src/main/java/io/undertow/conduits/ChunkReader.java
- core/src/main/java/io/undertow/server/HttpServerExchange.java
- core/src/main/java/io/undertow/server/handlers/HttpContinueReadHandler.java
- core/src/main/java/io/undertow/server/handlers/SameSiteCookieHandler.java
- core/src/main/java/io/undertow/server/handlers/resource/PathResourceManager.java
- + core/src/main/java/io/undertow/server/handlers/resource/SecurityActions.java
- core/src/main/java/io/undertow/server/protocol/ajp/AjpServerConnection.java
- core/src/main/java/io/undertow/server/protocol/http/HttpContinue.java
- core/src/main/java/io/undertow/server/protocol/http/HttpReadListener.java
- core/src/main/java/io/undertow/server/protocol/http/HttpResponseConduit.java
- core/src/main/java/io/undertow/server/protocol/http/HttpServerConnection.java
- core/src/main/java/io/undertow/server/protocol/http/HttpTransferEncoding.java
- core/src/main/java/io/undertow/server/session/InMemorySessionManager.java
- core/src/main/java/io/undertow/util/SameSiteNoneIncompatibleClientChecker.java
- + core/src/test/java/io/undertow/server/handlers/HttpContinueConduitWrappingHandlerBufferLeakTestCase.java
- core/src/test/java/io/undertow/server/handlers/SameSiteCookieHandlerTestCase.java
- core/src/test/java/io/undertow/util/SameSiteNoneIncompatibleClientCheckerTestCase.java
- coverage-report/pom.xml
- dist/pom.xml
- examples/pom.xml
- parser-generator/pom.xml
- pom.xml
- servlet/pom.xml
- servlet/src/main/java/io/undertow/servlet/spec/AsyncContextImpl.java
- + servlet/src/test/java/io/undertow/servlet/test/handlers/HttpContinueServletTestCase.java
- websockets-jsr/pom.xml


Changes:

=====================================
benchmarks/pom.xml
=====================================
@@ -25,11 +25,11 @@
     <parent>
         <groupId>io.undertow</groupId>
         <artifactId>undertow-parent</artifactId>
-        <version>2.1.0.Final</version>
+        <version>2.1.1.Final</version>
     </parent>
 
     <artifactId>undertow-benchmarks</artifactId>
-    <version>2.1.0.Final</version>
+    <version>2.1.1.Final</version>
 
     <name>Undertow Benchmarks</name>
 


=====================================
core/pom.xml
=====================================
@@ -25,12 +25,12 @@
     <parent>
         <groupId>io.undertow</groupId>
         <artifactId>undertow-parent</artifactId>
-        <version>2.1.0.Final</version>
+        <version>2.1.1.Final</version>
     </parent>
 
     <groupId>io.undertow</groupId>
     <artifactId>undertow-core</artifactId>
-    <version>2.1.0.Final</version>
+    <version>2.1.1.Final</version>
 
     <name>Undertow Core</name>
 


=====================================
core/src/main/java/io/undertow/UndertowLogger.java
=====================================
@@ -393,7 +393,7 @@ public interface UndertowLogger extends BasicLogger {
     @Message(id = 5084, value = "Attempted to write %s bytes however content-length has been set to %s")
     IOException dataLargerThanContentLength(long totalToWrite, long responseContentLength);
 
-    @LogMessage(level = ERROR)
+    @LogMessage(level = DEBUG)
     @Message(id = 5085, value = "Connection %s for exchange %s was not closed cleanly, forcibly closing connection")
     void responseWasNotTerminated(ServerConnection connection, HttpServerExchange exchange);
 


=====================================
core/src/main/java/io/undertow/UndertowMessages.java
=====================================
@@ -605,6 +605,9 @@ public interface UndertowMessages {
     @Message(id = 194, value = "Character decoding failed. Parameter with name [%s] has been ignored. Note: further occurrences of Parameter errors will be logged at DEBUG level.")
     String failedToDecodeParameterName(String parameter, @Cause Exception e);
 
-    @Message(id = 195, value = "Session with id %s already exists")
+    @Message(id = 195, value = "Chunk size too large")
+    IOException chunkSizeTooLarge();
+
+    @Message(id = 196, value = "Session with id %s already exists")
     IllegalStateException sessionWithIdAlreadyExists(String sessionID);
 }


=====================================
core/src/main/java/io/undertow/conduits/ChunkReader.java
=====================================
@@ -47,6 +47,8 @@ class ChunkReader<T extends Conduit> {
 
     private static final long MASK_COUNT = longBitMask(0, 56);
 
+    private static final long LIMIT = Long.MAX_VALUE >> 4;
+
     private long state;
     private final Attachable attachable;
     private final AttachmentKey<HeaderMap> trailerAttachmentKey;
@@ -100,6 +102,9 @@ class ChunkReader<T extends Conduit> {
                 while (buf.hasRemaining()) {
                     byte b = buf.get();
                     if ((b >= '0' && b <= '9') || (b >= 'a' && b <= 'f') || (b >= 'A' && b <= 'F')) {
+                        if (chunkRemaining > LIMIT) {
+                            throw UndertowMessages.MESSAGES.chunkSizeTooLarge();
+                        }
                         chunkRemaining <<= 4; //shift it 4 bytes and then add the next value to the end
                         chunkRemaining += Character.digit((char) b, 16);
                     } else {


=====================================
core/src/main/java/io/undertow/server/HttpServerExchange.java
=====================================
@@ -155,7 +155,7 @@ public final class HttpServerExchange extends AbstractAttachable {
     // mutable state
 
     private int state = 200;
-    private HttpString requestMethod;
+    private HttpString requestMethod = HttpString.EMPTY;
     private String requestScheme;
 
     /**


=====================================
core/src/main/java/io/undertow/server/handlers/HttpContinueReadHandler.java
=====================================
@@ -23,15 +23,18 @@ import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 import java.util.concurrent.TimeUnit;
 
+import org.xnio.channels.StreamSinkChannel;
+import org.xnio.conduits.AbstractStreamSourceConduit;
+import org.xnio.conduits.StreamSourceConduit;
+
 import io.undertow.server.ConduitWrapper;
-import io.undertow.server.protocol.http.HttpContinue;
+import io.undertow.server.Connectors;
 import io.undertow.server.HttpHandler;
 import io.undertow.server.HttpServerExchange;
+import io.undertow.server.ResponseCommitListener;
+import io.undertow.server.protocol.http.HttpContinue;
 import io.undertow.util.ConduitFactory;
 import io.undertow.util.StatusCodes;
-import org.xnio.channels.StreamSinkChannel;
-import org.xnio.conduits.AbstractStreamSourceConduit;
-import org.xnio.conduits.StreamSourceConduit;
 
 /**
  * Handler for requests that require 100-continue responses. If an attempt is made to read from the source
@@ -44,7 +47,7 @@ public class HttpContinueReadHandler implements HttpHandler {
     private static final ConduitWrapper<StreamSourceConduit> WRAPPER = new ConduitWrapper<StreamSourceConduit>() {
         @Override
         public StreamSourceConduit wrap(final ConduitFactory<StreamSourceConduit> factory, final HttpServerExchange exchange) {
-            if(exchange.isRequestChannelAvailable() && !exchange.isResponseStarted()) {
+            if (exchange.isRequestChannelAvailable() && !exchange.isResponseStarted()) {
                 return new ContinueConduit(factory.create(), exchange);
             }
             return factory.create();
@@ -61,6 +64,17 @@ public class HttpContinueReadHandler implements HttpHandler {
     public void handleRequest(final HttpServerExchange exchange) throws Exception {
         if (HttpContinue.requiresContinueResponse(exchange)) {
             exchange.addRequestWrapper(WRAPPER);
+            exchange.addResponseCommitListener(new ResponseCommitListener() {
+                @Override
+                public void beforeCommit(HttpServerExchange exchange) {
+                    //we are writing the response, and have not read the request then we mark this as non-persistent
+                    if (!HttpContinue.isContinueResponseSent(exchange)) {
+                        exchange.setPersistent(false);
+                        //we also kill the request channel, because it is unusable now
+                        exchange.getConnection().terminateRequestChannel(exchange);
+                    }
+                }
+            });
         }
         handler.handleRequest(exchange);
     }
@@ -81,6 +95,7 @@ public class HttpContinueReadHandler implements HttpHandler {
         public long transferTo(final long position, final long count, final FileChannel target) throws IOException {
             if (exchange.getStatusCode() == StatusCodes.EXPECTATION_FAILED) {
                 //rejected
+                Connectors.terminateRequest(exchange);
                 return -1;
             }
             if (!sent) {
@@ -100,6 +115,7 @@ public class HttpContinueReadHandler implements HttpHandler {
         public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException {
             if (exchange.getStatusCode() == StatusCodes.EXPECTATION_FAILED) {
                 //rejected
+                Connectors.terminateRequest(exchange);
                 return -1;
             }
             if (!sent) {
@@ -119,6 +135,7 @@ public class HttpContinueReadHandler implements HttpHandler {
         public int read(final ByteBuffer dst) throws IOException {
             if (exchange.getStatusCode() == StatusCodes.EXPECTATION_FAILED) {
                 //rejected
+                Connectors.terminateRequest(exchange);
                 return -1;
             }
             if (!sent) {
@@ -138,6 +155,7 @@ public class HttpContinueReadHandler implements HttpHandler {
         public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException {
             if (exchange.getStatusCode() == StatusCodes.EXPECTATION_FAILED) {
                 //rejected
+                Connectors.terminateRequest(exchange);
                 return -1;
             }
             if (!sent) {


=====================================
core/src/main/java/io/undertow/server/handlers/SameSiteCookieHandler.java
=====================================
@@ -74,8 +74,9 @@ public class SameSiteCookieHandler implements HttpHandler {
             exchange.addResponseCommitListener(new ResponseCommitListener() {
                 @Override
                 public void beforeCommit(HttpServerExchange exchange) {
-                    // Check user-agents and skip sending "SameSite=None" for incompatible user-agents
-                    if (enableClientChecker && !SameSiteNoneIncompatibleClientChecker.shouldSendSameSiteNone(exchange.getRequestHeaders().getFirst(Headers.USER_AGENT))) {
+                    // If user-agent is available check it and skip sending "SameSite=None" for incompatible user-agents
+                    String userAgent = exchange.getRequestHeaders().getFirst(Headers.USER_AGENT);
+                    if (enableClientChecker && userAgent != null && !SameSiteNoneIncompatibleClientChecker.shouldSendSameSiteNone(userAgent)) {
                         return;
                     }
                     for (Map.Entry<String, Cookie> cookie : exchange.getResponseCookies().entrySet()) {


=====================================
core/src/main/java/io/undertow/server/handlers/resource/PathResourceManager.java
=====================================
@@ -306,7 +306,7 @@ public class PathResourceManager implements ResourceManager  {
         int rootCount = root.getNameCount();
         Path f = file;
         for (int i = nameCount - 1; i>=0; i--) {
-            if (Files.isSymbolicLink(f)) {
+            if (SecurityActions.isSymbolicLink(f)) {
                 return new SymlinkResult(i+1 > rootCount, f);
             }
             f = f.getParent();


=====================================
core/src/main/java/io/undertow/server/handlers/resource/SecurityActions.java
=====================================
@@ -0,0 +1,40 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2020 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed 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 io.undertow.server.handlers.resource;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+class SecurityActions {
+
+    static Boolean isSymbolicLink(Path file) {
+        if (System.getSecurityManager() == null) {
+            return Files.isSymbolicLink(file);
+        } else {
+            return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+                @Override
+                public Boolean run() {
+                    return Files.isSymbolicLink(file);
+                }
+            });
+        }
+    }
+
+}


=====================================
core/src/main/java/io/undertow/server/protocol/ajp/AjpServerConnection.java
=====================================
@@ -26,6 +26,8 @@ import io.undertow.server.HttpHandler;
 import io.undertow.server.HttpServerExchange;
 import io.undertow.server.SSLSessionInfo;
 import io.undertow.util.DateUtils;
+
+import org.xnio.IoUtils;
 import org.xnio.OptionMap;
 import io.undertow.connector.ByteBufferPool;
 import org.xnio.StreamConnection;
@@ -61,7 +63,9 @@ public final class AjpServerConnection extends AbstractServerConnection {
 
     @Override
     public void terminateRequestChannel(HttpServerExchange exchange) {
-        //todo: terminate
+        if (!exchange.isPersistent()) {
+            IoUtils.safeClose(getChannel().getSourceChannel());
+        }
     }
 
     @Override


=====================================
core/src/main/java/io/undertow/server/protocol/http/HttpContinue.java
=====================================
@@ -91,6 +91,9 @@ public class HttpContinue {
         return false;
     }
 
+    public static boolean isContinueResponseSent(HttpServerExchange exchange) {
+        return exchange.getAttachment(ALREADY_SENT) != null;
+    }
 
     /**
      * Sends a continuation using async IO, and calls back when it is complete.


=====================================
core/src/main/java/io/undertow/server/protocol/http/HttpReadListener.java
=====================================
@@ -365,6 +365,10 @@ final class HttpReadListener implements ChannelListener<ConduitStreamSourceChann
                 }
             }
         } else if (!exchange.isPersistent()) {
+            if (connection.getExtraBytes() != null) {
+                connection.getExtraBytes().close();
+                connection.setExtraBytes(null);
+            }
             ConnectionUtils.cleanClose(connection.getChannel(), connection);
         } else {
             //upgrade or connect handling


=====================================
core/src/main/java/io/undertow/server/protocol/http/HttpResponseConduit.java
=====================================
@@ -18,18 +18,16 @@
 
 package io.undertow.server.protocol.http;
 
-import io.undertow.UndertowMessages;
-import io.undertow.server.Connectors;
-import io.undertow.server.HttpServerExchange;
-import io.undertow.util.HeaderMap;
-import io.undertow.util.HeaderValues;
-import io.undertow.util.HttpString;
-import io.undertow.util.Protocols;
-import io.undertow.util.StatusCodes;
+import static org.xnio.Bits.allAreClear;
+import static org.xnio.Bits.allAreSet;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.FileChannel;
+
 import org.xnio.Buffers;
 import org.xnio.IoUtils;
-import io.undertow.connector.ByteBufferPool;
-import io.undertow.connector.PooledByteBuffer;
 import org.xnio.XnioWorker;
 import org.xnio.channels.StreamSourceChannel;
 import org.xnio.conduits.AbstractStreamSinkConduit;
@@ -37,13 +35,16 @@ import org.xnio.conduits.ConduitWritableByteChannel;
 import org.xnio.conduits.Conduits;
 import org.xnio.conduits.StreamSinkConduit;
 
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.ClosedChannelException;
-import java.nio.channels.FileChannel;
-
-import static org.xnio.Bits.allAreClear;
-import static org.xnio.Bits.allAreSet;
+import io.undertow.UndertowMessages;
+import io.undertow.connector.ByteBufferPool;
+import io.undertow.connector.PooledByteBuffer;
+import io.undertow.server.Connectors;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.HeaderMap;
+import io.undertow.util.HeaderValues;
+import io.undertow.util.HttpString;
+import io.undertow.util.Protocols;
+import io.undertow.util.StatusCodes;
 
 /**
  * @author <a href="mailto:david.lloyd at redhat.com">David M. Lloyd</a>
@@ -290,6 +291,13 @@ final class HttpResponseConduit extends AbstractStreamSinkConduit<StreamSinkCond
         }
     }
 
+    public void freeContinueResponse() {
+        if (pooledBuffer != null) {
+            pooledBuffer.close();
+            pooledBuffer = null;
+        }
+    }
+
     private static void writeString(ByteBuffer buffer, String string) {
         int length = string.length();
         for (int charIndex = 0; charIndex < length; charIndex++) {


=====================================
core/src/main/java/io/undertow/server/protocol/http/HttpServerConnection.java
=====================================
@@ -36,6 +36,8 @@ import io.undertow.util.Headers;
 import io.undertow.util.HttpString;
 import io.undertow.util.ImmediatePooledByteBuffer;
 import io.undertow.util.Methods;
+
+import org.xnio.IoUtils;
 import org.xnio.OptionMap;
 import io.undertow.connector.ByteBufferPool;
 import io.undertow.connector.PooledByteBuffer;
@@ -111,7 +113,15 @@ public final class HttpServerConnection extends AbstractServerConnection {
             @Override
             public StreamSinkConduit wrap(ConduitFactory<StreamSinkConduit> factory, HttpServerExchange exchange) {
 
-                ServerFixedLengthStreamSinkConduit fixed = new ServerFixedLengthStreamSinkConduit(new HttpResponseConduit(getSinkChannel().getConduit(), getByteBufferPool(), HttpServerConnection.this, exchange), false, false);
+                HttpResponseConduit httpResponseConduit = new HttpResponseConduit(getSinkChannel().getConduit(), getByteBufferPool(), HttpServerConnection.this, exchange);
+                exchange.addExchangeCompleteListener(new ExchangeCompletionListener() {
+                    @Override
+                    public void exchangeEvent(HttpServerExchange exchange, NextListener nextListener) {
+                        httpResponseConduit.freeContinueResponse();
+                        nextListener.proceed();
+                    }
+                });
+                ServerFixedLengthStreamSinkConduit fixed = new ServerFixedLengthStreamSinkConduit(httpResponseConduit, false, false);
                 fixed.reset(0, exchange);
                 return fixed;
             }
@@ -135,7 +145,9 @@ public final class HttpServerConnection extends AbstractServerConnection {
 
     @Override
     public void terminateRequestChannel(HttpServerExchange exchange) {
-
+        if (!exchange.isPersistent()) {
+            IoUtils.safeClose(getChannel().getSourceChannel());
+        }
     }
 
     /**


=====================================
core/src/main/java/io/undertow/server/protocol/http/HttpTransferEncoding.java
=====================================
@@ -34,6 +34,8 @@ import io.undertow.util.HeaderMap;
 import io.undertow.util.Headers;
 import io.undertow.util.HttpString;
 import io.undertow.util.Methods;
+import io.undertow.util.StatusCodes;
+
 import org.jboss.logging.Logger;
 import org.xnio.conduits.ConduitStreamSourceChannel;
 import org.xnio.conduits.StreamSinkConduit;
@@ -224,6 +226,11 @@ class HttpTransferEncoding {
         final HeaderMap responseHeaders = exchange.getResponseHeaders();
         // test to see if we're still persistent
         String connection = responseHeaders.getFirst(Headers.CONNECTION);
+        if(exchange.getStatusCode() == StatusCodes.EXPECTATION_FAILED) {
+            //417 responses are never persistent, as we have no idea if there is a response body
+            //still coming on the wire.
+            exchange.setPersistent(false);
+        }
         if (!exchange.isPersistent()) {
             responseHeaders.put(Headers.CONNECTION, Headers.CLOSE.toString());
         } else if (exchange.isPersistent() && connection != null) {


=====================================
core/src/main/java/io/undertow/server/session/InMemorySessionManager.java
=====================================
@@ -476,6 +476,7 @@ public class InMemorySessionManager implements SessionManager, SessionManagerSta
             if(existing != null) {
                 lastAccessed = existing;
             }
+            bumpTimeout();
         }
 
         @Override
@@ -501,7 +502,6 @@ public class InMemorySessionManager implements SessionManager, SessionManagerSta
             }
             UndertowLogger.SESSION_LOGGER.debugf("Setting max inactive interval for %s to %s", sessionId, interval);
             maxInactiveInterval = interval;
-            bumpTimeout();
         }
 
         @Override
@@ -517,7 +517,6 @@ public class InMemorySessionManager implements SessionManager, SessionManagerSta
             if (invalid) {
                 throw UndertowMessages.MESSAGES.sessionIsInvalid(sessionId);
             }
-            bumpTimeout();
             return attributes.get(name);
         }
 
@@ -526,7 +525,6 @@ public class InMemorySessionManager implements SessionManager, SessionManagerSta
             if (invalid) {
                 throw UndertowMessages.MESSAGES.sessionIsInvalid(sessionId);
             }
-            bumpTimeout();
             return attributes.keySet();
         }
 
@@ -544,7 +542,6 @@ public class InMemorySessionManager implements SessionManager, SessionManagerSta
             } else {
                sessionManager.sessionListeners.attributeUpdated(this, name, value, existing);
             }
-            bumpTimeout();
             UndertowLogger.SESSION_LOGGER.tracef("Setting session attribute %s to %s for session %s", name, value, sessionId);
             return existing;
         }
@@ -556,7 +553,6 @@ public class InMemorySessionManager implements SessionManager, SessionManagerSta
             }
             final Object existing = attributes.remove(name);
             sessionManager.sessionListeners.attributeRemoved(this, name, existing);
-            bumpTimeout();
             UndertowLogger.SESSION_LOGGER.tracef("Removing session attribute %s for session %s", name, sessionId);
             return existing;
         }


=====================================
core/src/main/java/io/undertow/util/SameSiteNoneIncompatibleClientChecker.java
=====================================
@@ -65,17 +65,21 @@ public final class SameSiteNoneIncompatibleClientChecker {
 
     // browsers known to be incompatible.
     public static boolean isSameSiteNoneIncompatible(String useragent) {
+        if (useragent == null || useragent.isEmpty()) {
+            return false;
+        }
+
         return hasWebKitSameSiteBug(useragent) ||
             dropsUnrecognizedSameSiteCookies(useragent);
     }
 
-    static boolean hasWebKitSameSiteBug(String useragent) {
+    private static boolean hasWebKitSameSiteBug(String useragent) {
         return isIosVersion(12, useragent) ||
             (isMacosxVersion(10, 14, useragent) &&
              (isSafari(useragent) || isMacEmbeddedBrowser(useragent)));
     }
 
-    static boolean dropsUnrecognizedSameSiteCookies(String useragent) {
+    private static boolean dropsUnrecognizedSameSiteCookies(String useragent) {
         if (isUcBrowser(useragent)) {
             return !isUcBrowserVersionAtLeast(12, 13, 2, useragent);
         }
@@ -86,7 +90,7 @@ public final class SameSiteNoneIncompatibleClientChecker {
 
     // Regex parsing of User-Agent String. (See note above!)
 
-    static boolean isIosVersion(int major, String useragent) {
+    private static boolean isIosVersion(int major, String useragent) {
         Matcher m = IOS_PATTERN.matcher(useragent);
         if (m.find()) {
             // Extract digits from first capturing group.
@@ -95,7 +99,7 @@ public final class SameSiteNoneIncompatibleClientChecker {
         return false;
     }
 
-    static boolean isMacosxVersion(int major, int minor, String useragent) {
+    private static boolean isMacosxVersion(int major, int minor, String useragent) {
         Matcher m = MACOSX_PATTERN.matcher(useragent);
         if (m.find()) {
             // Extract digits from first and second capturing groups.
@@ -105,20 +109,20 @@ public final class SameSiteNoneIncompatibleClientChecker {
         return false;
     }
 
-    static boolean isSafari(String useragent) {
+    private static boolean isSafari(String useragent) {
         return SAFARI_PATTERN.matcher(useragent).find() &&
             !isChromiumBased(useragent);
     }
 
-    static boolean isMacEmbeddedBrowser(String useragent) {
+    private static boolean isMacEmbeddedBrowser(String useragent) {
         return MAC_EMBEDDED_BROWSER_PATTERN.matcher(useragent).find();
     }
 
-    static boolean isChromiumBased(String useragent) {
+    private static boolean isChromiumBased(String useragent) {
         return CHROMIUM_PATTERN.matcher(useragent).find();
     }
 
-    static boolean isChromiumVersionAtLeast(int major, String useragent) {
+    private static boolean isChromiumVersionAtLeast(int major, String useragent) {
         Matcher m = CHROMIUM_VERSION_PATTERN.matcher(useragent);
         if (m.find()) {
             // Extract digits from first capturing group.
@@ -132,7 +136,7 @@ public final class SameSiteNoneIncompatibleClientChecker {
         return useragent.contains("UCBrowser/");
     }
 
-    static boolean isUcBrowserVersionAtLeast(int major, int minor, int build, String useragent) {
+    private static boolean isUcBrowserVersionAtLeast(int major, int minor, int build, String useragent) {
         Matcher m = UC_BROWSER_VERSION_PATTERN.matcher(useragent);
         if (m.find()) {
             // Extract digits from three capturing groups.


=====================================
core/src/test/java/io/undertow/server/handlers/HttpContinueConduitWrappingHandlerBufferLeakTestCase.java
=====================================
@@ -0,0 +1,100 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2020 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed 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 io.undertow.server.handlers;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import io.undertow.server.HttpHandler;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.testutils.DefaultServer;
+import io.undertow.util.StatusCodes;
+
+/**
+ * @author Stuart Douglas
+ */
+ at RunWith(DefaultServer.class)
+public class HttpContinueConduitWrappingHandlerBufferLeakTestCase {
+
+    static Socket persistentSocket;
+
+    @BeforeClass
+    public static void setup() {
+        final BlockingHandler blockingHandler = new BlockingHandler();
+        final HttpContinueReadHandler handler = new HttpContinueReadHandler(blockingHandler);
+        DefaultServer.setRootHandler(handler);
+        blockingHandler.setRootHandler(new HttpHandler() {
+            @Override
+            public void handleRequest(final HttpServerExchange exchange) {
+                try {
+                    if (exchange.getQueryParameters().containsKey("reject")) {
+                        exchange.getRequestChannel();
+                        exchange.setStatusCode(StatusCodes.EXPECTATION_FAILED);
+                        exchange.getOutputStream().close();
+                    }
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        });
+    }
+
+    @Before
+    public void before() {
+        Assume.assumeFalse(DefaultServer.isAjp());
+    }
+
+    @Test
+    public void testHttpContinueRejectedBodySentAnywayNoBufferLeak() throws IOException {
+        persistentSocket = new Socket(DefaultServer.getHostAddress(), DefaultServer.getHostPort());
+
+        String message = "POST /path?reject=true HTTP/1.1\r\n" +
+                "Expect: 100-continue\r\n" +
+                "Content-Length: 16\r\n" +
+                "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
+                "Host: localhost:7777\r\n" +
+                "Connection: Keep-Alive\r\n\r\nMy HTTP Request!";
+        persistentSocket.getOutputStream().write(message.getBytes(StandardCharsets.UTF_8));
+        persistentSocket.getOutputStream().flush();
+        persistentSocket.getInputStream().read();
+    }
+
+    @Test
+    public void testHttpContinueBodySentAnywayNoLeak() throws IOException {
+        persistentSocket = new Socket(DefaultServer.getHostAddress(), DefaultServer.getHostPort());
+
+        String message = "POST /path HTTP/1.1\r\n" +
+                "Expect: 100-continue\r\n" +
+                "Content-Length: 16\r\n" +
+                "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
+                "Host: localhost:7777\r\n" +
+                "Connection: Keep-Alive\r\n\r\nMy HTTP Request!";
+        persistentSocket.getOutputStream().write(message.getBytes(StandardCharsets.UTF_8));
+        persistentSocket.getOutputStream().flush();
+        persistentSocket.getInputStream().read();
+    }
+
+}


=====================================
core/src/test/java/io/undertow/server/handlers/SameSiteCookieHandlerTestCase.java
=====================================
@@ -19,11 +19,14 @@
 package io.undertow.server.handlers;
 
 import java.io.IOException;
-import java.security.GeneralSecurityException;
 
+import io.undertow.util.Headers;
 import org.apache.http.Header;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.methods.HttpGet;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -39,10 +42,10 @@ import io.undertow.util.StatusCodes;
 public class SameSiteCookieHandlerTestCase {
 
     @Test
-    public void testStrict() throws IOException, GeneralSecurityException {
+    public void testStrict() throws IOException {
         DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
             @Override
-            public void handleRequest(final HttpServerExchange exchange) throws Exception {
+            public void handleRequest(final HttpServerExchange exchange) {
                 exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
             }
         }, "Strict", "foo"));
@@ -64,10 +67,10 @@ public class SameSiteCookieHandlerTestCase {
     }
 
     @Test
-    public void testLax() throws IOException, GeneralSecurityException {
+    public void testLax() throws IOException {
         DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
             @Override
-            public void handleRequest(final HttpServerExchange exchange) throws Exception {
+            public void handleRequest(final HttpServerExchange exchange) {
                 exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
             }
         }, "Lax", "foo"));
@@ -89,10 +92,10 @@ public class SameSiteCookieHandlerTestCase {
     }
 
     @Test
-    public void testNone() throws IOException, GeneralSecurityException {
+    public void testNone() throws IOException {
         DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
             @Override
-            public void handleRequest(final HttpServerExchange exchange) throws Exception {
+            public void handleRequest(final HttpServerExchange exchange) {
                 exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
             }
         }, "None", "foo"));
@@ -114,10 +117,10 @@ public class SameSiteCookieHandlerTestCase {
     }
 
     @Test
-    public void testInvalidMode() throws IOException, GeneralSecurityException {
+    public void testInvalidMode() throws IOException {
         DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
             @Override
-            public void handleRequest(final HttpServerExchange exchange) throws Exception {
+            public void handleRequest(final HttpServerExchange exchange) {
                 exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
             }
         }, "invalidmode", "foo"));
@@ -139,10 +142,10 @@ public class SameSiteCookieHandlerTestCase {
     }
 
     @Test
-    public void testRegexPattern() throws IOException, GeneralSecurityException {
+    public void testRegexPattern() throws IOException {
         DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
             @Override
-            public void handleRequest(final HttpServerExchange exchange) throws Exception {
+            public void handleRequest(final HttpServerExchange exchange) {
                 exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
             }
         }, "Lax", "fo.*"));
@@ -165,10 +168,10 @@ public class SameSiteCookieHandlerTestCase {
 
 
     @Test
-    public void testCaseInsensitivePattern() throws IOException, GeneralSecurityException {
+    public void testCaseInsensitivePattern() throws IOException {
         DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
             @Override
-            public void handleRequest(final HttpServerExchange exchange) throws Exception {
+            public void handleRequest(final HttpServerExchange exchange) {
                 exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
             }
         }, "Lax", "FOO", false));
@@ -190,10 +193,10 @@ public class SameSiteCookieHandlerTestCase {
     }
 
     @Test
-    public void testPatternUnmatched() throws IOException, GeneralSecurityException {
+    public void testPatternUnmatched() throws IOException {
         DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
             @Override
-            public void handleRequest(final HttpServerExchange exchange) throws Exception {
+            public void handleRequest(final HttpServerExchange exchange) {
                 exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
             }
         }, "Lax", "FO.*"));
@@ -215,10 +218,10 @@ public class SameSiteCookieHandlerTestCase {
     }
 
     @Test
-    public void testAllCookies() throws IOException, GeneralSecurityException {
+    public void testAllCookies() throws IOException {
         DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
             @Override
-            public void handleRequest(final HttpServerExchange exchange) throws Exception {
+            public void handleRequest(final HttpServerExchange exchange) {
                 exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
                 exchange.getResponseCookies().put("baz", new CookieImpl("baz", "qux"));
                 exchange.getResponseCookies().put("test", new CookieImpl("test", "test"));
@@ -253,10 +256,10 @@ public class SameSiteCookieHandlerTestCase {
 
 
     @Test
-    public void testMultipleCookiesMatched() throws IOException, GeneralSecurityException {
+    public void testMultipleCookiesMatched() throws IOException {
         DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
             @Override
-            public void handleRequest(final HttpServerExchange exchange) throws Exception {
+            public void handleRequest(final HttpServerExchange exchange) {
                 exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
                 exchange.getResponseCookies().put("baz", new CookieImpl("baz", "qux"));
                 exchange.getResponseCookies().put("test", new CookieImpl("test", "test"));
@@ -290,10 +293,10 @@ public class SameSiteCookieHandlerTestCase {
     }
 
     @Test
-    public void testNoneIncompatibleUA() throws IOException, GeneralSecurityException {
+    public void testNoneIncompatibleUA() throws IOException {
         DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
             @Override
-            public void handleRequest(final HttpServerExchange exchange) throws Exception {
+            public void handleRequest(final HttpServerExchange exchange) {
                 exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
             }
         }, "None", "foo"));
@@ -317,10 +320,10 @@ public class SameSiteCookieHandlerTestCase {
     }
 
     @Test
-    public void testNoneUACheckerDisabled() throws IOException, GeneralSecurityException {
+    public void testNoneUACheckerDisabled() throws IOException {
         DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
             @Override
-            public void handleRequest(final HttpServerExchange exchange) throws Exception {
+            public void handleRequest(final HttpServerExchange exchange) {
                 exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
             }
         }, "None", "foo", true, false, true));
@@ -344,10 +347,72 @@ public class SameSiteCookieHandlerTestCase {
     }
 
     @Test
-    public void testNoneWithoutSecure() throws IOException, GeneralSecurityException {
+    public void testNoneUACheckerEnabledAlthoughUAHeaderEmpty() throws IOException {
         DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
             @Override
-            public void handleRequest(final HttpServerExchange exchange) throws Exception {
+            public void handleRequest(final HttpServerExchange exchange) {
+                exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
+            }
+        }, "None", "foo"));
+        DefaultServer.startSSLServer();
+
+        TestHttpClient client = new TestHttpClient();
+        client.setSSLContext(DefaultServer.getClientSSLContext());
+        try {
+            HttpGet get = new HttpGet(DefaultServer.getDefaultServerSSLAddress());
+            // Use empty User-Agent header
+            get.setHeader(Headers.USER_AGENT.toString(), "");
+            HttpResponse result = client.execute(get);
+            Assert.assertEquals(StatusCodes.OK, result.getStatusLine().getStatusCode());
+            Header header = result.getFirstHeader("set-cookie");
+            Assert.assertEquals("foo=bar; secure; SameSite=None", header.getValue());
+            FileUtils.readFile(result.getEntity().getContent());
+        } finally {
+            client.getConnectionManager().shutdown();
+            DefaultServer.stopSSLServer();
+        }
+    }
+
+    @Test
+    public void testNoneUACheckerEnabledAlthoughUAHeaderNotSet() throws IOException {
+        DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
+            @Override
+            public void handleRequest(final HttpServerExchange exchange) {
+                exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
+            }
+        }, "None", "foo"));
+        DefaultServer.startSSLServer();
+
+        TestHttpClient client = new TestHttpClient() {
+            // Here we need to get client instance that does not set ANY User-Agent header by default.
+            @Override
+            protected HttpParams createHttpParams() {
+                HttpParams params = super.createHttpParams();
+                params.removeParameter(CoreProtocolPNames.USER_AGENT);
+                HttpConnectionParams.setSoTimeout(params, 30000);
+                return params;
+            }
+        };
+        client.setSSLContext(DefaultServer.getClientSSLContext());
+        try {
+            HttpGet get = new HttpGet(DefaultServer.getDefaultServerSSLAddress());
+            // Don't set any User-Agent header
+            HttpResponse result = client.execute(get);
+            Assert.assertEquals(StatusCodes.OK, result.getStatusLine().getStatusCode());
+            Header header = result.getFirstHeader("set-cookie");
+            Assert.assertEquals("foo=bar; secure; SameSite=None", header.getValue());
+            FileUtils.readFile(result.getEntity().getContent());
+        } finally {
+            client.getConnectionManager().shutdown();
+            DefaultServer.stopSSLServer();
+        }
+    }
+
+    @Test
+    public void testNoneWithoutSecure() throws IOException {
+        DefaultServer.setRootHandler(new SameSiteCookieHandler(new HttpHandler() {
+            @Override
+            public void handleRequest(final HttpServerExchange exchange) {
                 exchange.getResponseCookies().put("foo", new CookieImpl("foo", "bar"));
             }
         }, "None", "foo", true, true, false));


=====================================
core/src/test/java/io/undertow/util/SameSiteNoneIncompatibleClientCheckerTestCase.java
=====================================
@@ -26,6 +26,11 @@ import org.junit.experimental.categories.Category;
 @Category(UnitTest.class)
 public class SameSiteNoneIncompatibleClientCheckerTestCase {
 
+    /**
+     * List of incompatible User-Agents that contain bug in same-site cookie behavior.
+     *
+     * @see SameSiteNoneIncompatibleClientChecker
+     */
     String[] incompatibleWebKitUserAgents = {
             // Safari on Mac OS X 10.14
             "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.2 Safari/605.1.15",
@@ -35,6 +40,12 @@ public class SameSiteNoneIncompatibleClientCheckerTestCase {
             "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/69.0.3497.91 Mobile/15E148 Safari/605.1"
     };
 
+    /**
+     * List of compatible User-Agents that not containing bug in same-site cookie behavior.
+     * There is also empty string and 'null' to check incorrect input User-Agent value behavior.
+     *
+     * @see SameSiteNoneIncompatibleClientChecker
+     */
     String[] compatibleWebKitUserAgents = {
             // Safari on Mac OS X 10.15
             "Mozilla/6.0 (Macintosh; U; Intel Mac OS X 10_15_3) AppleWebKit/663.16 (KHTML, like Gecko) Version/10.0 Safari/663.16",
@@ -42,8 +53,15 @@ public class SameSiteNoneIncompatibleClientCheckerTestCase {
             "Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.1 Mobile/15E148 Safari/604.1",
             // Chrome on iOS 13
             "Mozilla/5.0 (iPhone; CPU iPhone OS 13_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/77.0.3865.69 Mobile/15E148 Safari/605.1",
+            "",
+            null
     };
 
+    /**
+     * List of incompatible User-Agents that drop same-site cookies entirely.
+     *
+     * @see SameSiteNoneIncompatibleClientChecker
+     */
     String[] incompatibleWebKitUserAgents2 = {
             // Chrome 51 on Windows
             "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36",
@@ -55,6 +73,12 @@ public class SameSiteNoneIncompatibleClientCheckerTestCase {
             "Mozilla/5.0 (Linux; U; Android 9; en-US; ...) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.13.0.1207 Mobile Safari/537.36",
     };
 
+    /**
+     * List of compatible User-Agents that don't drop same-site cookies entirely.
+     * There is also empty string and 'null' to check incorrect input User-Agent value behavior.
+     *
+     * @see SameSiteNoneIncompatibleClientChecker
+     */
     String[] compatibleWebKitUserAgents2 = {
             // Chrome 72 on Windows
             "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
@@ -62,40 +86,10 @@ public class SameSiteNoneIncompatibleClientCheckerTestCase {
             "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
             // UC Browser 12.13.4 on Android
             "Mozilla/5.0 (Linux; U; Android 10; en-US; ...) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.13.4.1214 Mobile Safari/537.36",
+            "",
+            null
     };
 
-    @Test
-    public void testHasWebKitSameSiteBug() {
-
-        boolean result;
-
-        for (String userAgent : incompatibleWebKitUserAgents) {
-            result = SameSiteNoneIncompatibleClientChecker.hasWebKitSameSiteBug(userAgent);
-            Assert.assertTrue("Tested user-agent: '" + userAgent + "'", result);
-        }
-
-        for (String userAgent : compatibleWebKitUserAgents) {
-            result = SameSiteNoneIncompatibleClientChecker.hasWebKitSameSiteBug(userAgent);
-            Assert.assertFalse("Tested user-agent: '" + userAgent + "'", result);
-        }
-    }
-
-    @Test
-    public void testDropsUnrecognizedSameSiteCookies() {
-
-        boolean result;
-
-        for (String userAgent : incompatibleWebKitUserAgents2) {
-            result = SameSiteNoneIncompatibleClientChecker.dropsUnrecognizedSameSiteCookies(userAgent);
-            Assert.assertTrue("Tested user-agent: '" + userAgent + "'", result);
-        }
-
-        for (String userAgent : compatibleWebKitUserAgents2) {
-            result = SameSiteNoneIncompatibleClientChecker.dropsUnrecognizedSameSiteCookies(userAgent);
-            Assert.assertFalse("Tested user-agent: '" + userAgent + "'", result);
-        }
-    }
-
     @Test
     public void testShouldSendSameSiteNone() {
 


=====================================
coverage-report/pom.xml
=====================================
@@ -3,7 +3,7 @@
     <parent>
         <groupId>io.undertow</groupId>
         <artifactId>undertow-parent</artifactId>
-        <version>2.1.0.Final</version>
+        <version>2.1.1.Final</version>
     </parent>
     <artifactId>undertow-coverage-report</artifactId>
     <name>Undertow Test Coverage Report</name>


=====================================
dist/pom.xml
=====================================
@@ -25,12 +25,12 @@
     <parent>
         <groupId>io.undertow</groupId>
         <artifactId>undertow-parent</artifactId>
-        <version>2.1.0.Final</version>
+        <version>2.1.1.Final</version>
     </parent>
 
     <groupId>io.undertow</groupId>
     <artifactId>undertow-dist</artifactId>
-    <version>2.1.0.Final</version>
+    <version>2.1.1.Final</version>
 
     <name>Undertow: Distribution</name>
 


=====================================
examples/pom.xml
=====================================
@@ -25,12 +25,12 @@
     <parent>
         <groupId>io.undertow</groupId>
         <artifactId>undertow-parent</artifactId>
-        <version>2.1.0.Final</version>
+        <version>2.1.1.Final</version>
     </parent>
 
     <groupId>io.undertow</groupId>
     <artifactId>undertow-examples</artifactId>
-    <version>2.1.0.Final</version>
+    <version>2.1.1.Final</version>
 
     <name>Undertow Examples</name>
 


=====================================
parser-generator/pom.xml
=====================================
@@ -25,12 +25,12 @@
     <parent>
         <groupId>io.undertow</groupId>
         <artifactId>undertow-parent</artifactId>
-        <version>2.1.0.Final</version>
+        <version>2.1.1.Final</version>
     </parent>
 
     <groupId>io.undertow</groupId>
     <artifactId>undertow-parser-generator</artifactId>
-    <version>2.1.0.Final</version>
+    <version>2.1.1.Final</version>
 
     <name>Undertow Parser Generator</name>
     <description>An annotation processor that is used to generate the HTTP parser</description>


=====================================
pom.xml
=====================================
@@ -28,7 +28,7 @@
 
     <groupId>io.undertow</groupId>
     <artifactId>undertow-parent</artifactId>
-    <version>2.1.0.Final</version>
+    <version>2.1.1.Final</version>
 
     <name>Undertow</name>
     <description>Undertow</description>
@@ -63,7 +63,7 @@
         <version.com.h2database>1.4.200</version.com.h2database>
         <version.easymock>4.2</version.easymock>
         <version.junit>4.13</version.junit>
-        <version.netty>4.1.48.Final</version.netty>
+        <version.netty>4.1.50.Final</version.netty>
         <version.org.apache.directory.server>2.0.0-M15</version.org.apache.directory.server>
         <version.org.apache.httpcomponents>4.5.12</version.org.apache.httpcomponents>
         <version.org.jboss.classfilewriter>1.2.4.Final</version.org.jboss.classfilewriter>
@@ -76,6 +76,7 @@
         <version.xnio>3.8.0.Final</version.xnio>
         <!-- TODO remove this dependency once xnio upgrades to latest jboss threads -->
         <version.org.jboss.threads>3.1.0.Final</version.org.jboss.threads>
+        <version.org.wildfly.common>1.5.4.Final</version.org.wildfly.common>
 
         <!-- jacoco -->
         <version.org.jacoco>0.7.9</version.org.jacoco>
@@ -448,12 +449,30 @@
                 <groupId>org.jboss.xnio</groupId>
                 <artifactId>xnio-nio</artifactId>
                 <version>${version.xnio}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.wildfly.common</groupId>
+                        <artifactId>wildfly-common</artifactId>
+                    </exclusion>
+                </exclusions>
             </dependency>
 
             <dependency>
                 <groupId>org.jboss.threads</groupId>
                 <artifactId>jboss-threads</artifactId>
                 <version>${version.org.jboss.threads}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.wildfly.common</groupId>
+                        <artifactId>wildfly-common</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
+            <dependency>
+                <groupId>org.wildfly.common</groupId>
+                <artifactId>wildfly-common</artifactId>
+                <version>${version.org.wildfly.common}</version>
             </dependency>
 
             <dependency>


=====================================
servlet/pom.xml
=====================================
@@ -25,12 +25,12 @@
     <parent>
         <groupId>io.undertow</groupId>
         <artifactId>undertow-parent</artifactId>
-        <version>2.1.0.Final</version>
+        <version>2.1.1.Final</version>
     </parent>
 
     <groupId>io.undertow</groupId>
     <artifactId>undertow-servlet</artifactId>
-    <version>2.1.0.Final</version>
+    <version>2.1.1.Final</version>
 
     <name>Undertow Servlet</name>
 


=====================================
servlet/src/main/java/io/undertow/servlet/spec/AsyncContextImpl.java
=====================================
@@ -195,6 +195,9 @@ public class AsyncContextImpl implements AsyncContext {
                 Connectors.executeRootHandler(new HttpHandler() {
                     @Override
                     public void handleRequest(final HttpServerExchange exchange) throws Exception {
+                        ServletRequestContext src = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
+                        src.setServletRequest(servletRequest);
+                        src.setServletResponse(servletResponse);
                         servletDispatcher.dispatchToPath(exchange, pathInfo, DispatcherType.ASYNC);
                     }
                 }, exchange);


=====================================
servlet/src/test/java/io/undertow/servlet/test/handlers/HttpContinueServletTestCase.java
=====================================
@@ -0,0 +1,191 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2014 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed 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 io.undertow.servlet.test.handlers;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpParams;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import io.undertow.servlet.Servlets;
+import io.undertow.servlet.test.util.DeploymentUtils;
+import io.undertow.testutils.DefaultServer;
+import io.undertow.testutils.HttpClientUtils;
+import io.undertow.testutils.TestHttpClient;
+import io.undertow.util.StatusCodes;
+
+/**
+ * @author Stuart Douglas
+ */
+ at RunWith(DefaultServer.class)
+public class HttpContinueServletTestCase {
+
+    private static volatile boolean accept = false;
+
+    @BeforeClass
+    public static void setup() {
+        DeploymentUtils.setupServlet(Servlets.servlet(ContinueConsumeServlet.class).addMappings("/path"),
+                Servlets.servlet(ContinueIgnoreServlet.class).addMappings("/ignore"));
+    }
+
+    @Before
+    public void before() {
+        Assume.assumeFalse(DefaultServer.isAjp());
+    }
+
+    @Test
+    public void testHttpContinueRejected() throws IOException {
+        accept = false;
+        String message = "My HTTP Request!";
+        HttpParams httpParams = new BasicHttpParams();
+        httpParams.setParameter("http.protocol.wait-for-continue", Integer.MAX_VALUE);
+
+        TestHttpClient client = new TestHttpClient();
+        client.setParams(httpParams);
+        try {
+            HttpPost post = new HttpPost(DefaultServer.getDefaultServerURL() + "/servletContext/path");
+            post.addHeader("Expect", "100-continue");
+            post.setEntity(new StringEntity(message));
+
+            HttpResponse result = client.execute(post);
+            Assert.assertEquals(StatusCodes.EXPECTATION_FAILED, result.getStatusLine().getStatusCode());
+        } finally {
+            client.getConnectionManager().shutdown();
+        }
+    }
+
+    @Test
+    public void testHttpContinueAccepted() throws IOException {
+        accept = true;
+        String message = "My HTTP Request!";
+        HttpParams httpParams = new BasicHttpParams();
+        httpParams.setParameter("http.protocol.wait-for-continue", Integer.MAX_VALUE);
+
+        TestHttpClient client = new TestHttpClient();
+        client.setParams(httpParams);
+        try {
+            HttpPost post = new HttpPost(DefaultServer.getDefaultServerURL() + "/servletContext/path");
+            post.addHeader("Expect", "100-continue");
+            post.setEntity(new StringEntity(message));
+
+            HttpResponse result = client.execute(post);
+            Assert.assertEquals(StatusCodes.OK, result.getStatusLine().getStatusCode());
+            Assert.assertEquals(message, HttpClientUtils.readResponse(result));
+        } finally {
+            client.getConnectionManager().shutdown();
+        }
+    }
+
+    @Test
+    public void testHttpContinueIgnored() throws IOException {
+        accept = true;
+        String message = "My HTTP Request!";
+        HttpParams httpParams = new BasicHttpParams();
+        httpParams.setParameter("http.protocol.wait-for-continue", Integer.MAX_VALUE);
+
+        TestHttpClient client = new TestHttpClient();
+        client.setParams(httpParams);
+        try {
+            HttpPost post = new HttpPost(DefaultServer.getDefaultServerURL() + "/servletContext/ignore");
+            post.addHeader("Expect", "100-continue");
+            post.setEntity(new StringEntity(message));
+
+            HttpResponse result = client.execute(post);
+            Assert.assertEquals(StatusCodes.OK, result.getStatusLine().getStatusCode());
+            Assert.assertEquals("", HttpClientUtils.readResponse(result));
+        } finally {
+            client.getConnectionManager().shutdown();
+        }
+    }
+    //UNDERTOW-162
+    @Test
+    public void testHttpContinueAcceptedWithChunkedRequest() throws IOException {
+        accept = true;
+        String message = "My HTTP Request!";
+        HttpParams httpParams = new BasicHttpParams();
+        httpParams.setParameter("http.protocol.wait-for-continue", Integer.MAX_VALUE);
+
+        TestHttpClient client = new TestHttpClient();
+        client.setParams(httpParams);
+        try {
+            HttpPost post = new HttpPost(DefaultServer.getDefaultServerURL() + "/servletContext/path");
+            post.addHeader("Expect", "100-continue");
+            post.setEntity(new StringEntity(message) {
+                @Override
+                public long getContentLength() {
+                    return -1;
+                }
+            });
+
+            HttpResponse result = client.execute(post);
+            Assert.assertEquals(StatusCodes.OK, result.getStatusLine().getStatusCode());
+            Assert.assertEquals(message, HttpClientUtils.readResponse(result));
+        } finally {
+            client.getConnectionManager().shutdown();
+        }
+    }
+
+    public static class ContinueConsumeServlet extends HttpServlet {
+        @Override
+        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+            try {
+                if (!accept) {
+                    resp.setStatus(StatusCodes.EXPECTATION_FAILED);
+                    return;
+                }
+                byte[] buffer = new byte[1024];
+                final ByteArrayOutputStream b = new ByteArrayOutputStream();
+                int r = 0;
+                final OutputStream outputStream = resp.getOutputStream();
+                final InputStream inputStream = req.getInputStream();
+                while ((r = inputStream.read(buffer)) > 0) {
+                    b.write(buffer, 0, r);
+                }
+                outputStream.write(b.toByteArray());
+                outputStream.close();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public static class ContinueIgnoreServlet extends HttpServlet {
+
+        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+
+        }
+    }
+}


=====================================
websockets-jsr/pom.xml
=====================================
@@ -25,12 +25,12 @@
     <parent>
         <groupId>io.undertow</groupId>
         <artifactId>undertow-parent</artifactId>
-        <version>2.1.0.Final</version>
+        <version>2.1.1.Final</version>
     </parent>
 
     <groupId>io.undertow</groupId>
     <artifactId>undertow-websockets-jsr</artifactId>
-    <version>2.1.0.Final</version>
+    <version>2.1.1.Final</version>
 
     <name>Undertow WebSockets JSR356 implementations</name>
 



View it on GitLab: https://salsa.debian.org/java-team/undertow/-/commit/31090dc60b12f8368e171e9b9d696021204156ad

-- 
View it on GitLab: https://salsa.debian.org/java-team/undertow/-/commit/31090dc60b12f8368e171e9b9d696021204156ad
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20200517/9d0a7468/attachment.html>


More information about the pkg-java-commits mailing list