[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