diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java index 1fe2cd264cf..1388931e233 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AuthenticationProtocolHandler.java @@ -37,6 +37,7 @@ import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.util.BufferingResponseListener; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.QuotedCSV; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -309,7 +310,9 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler @Override public void onSuccess(Response response) { - client.getAuthenticationStore().addAuthenticationResult(authenticationResult); + int status = response.getStatus(); + if (HttpStatus.isSuccess(status) || HttpStatus.isRedirection(status)) + client.getAuthenticationStore().addAuthenticationResult(authenticationResult); } } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java index 4d8c2680f6a..50a2bdc344b 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/BasicAuthentication.java @@ -103,7 +103,8 @@ public class BasicAuthentication extends AbstractAuthentication @Override public void apply(Request request) { - request.header(header, value); + if (!request.getHeaders().contains(header, value)) + request.header(header, value); } @Override diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java index da66f466d51..5e3307746a2 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientAuthenticationTest.java @@ -18,13 +18,6 @@ package org.eclipse.jetty.client; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalToIgnoringCase; -import static org.hamcrest.Matchers.equalTo; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.File; import java.io.IOException; import java.net.URI; @@ -38,7 +31,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.IntFunction; -import javax.servlet.ServletException; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -74,6 +67,13 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalToIgnoringCase; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest { private String realm = "TestRealm"; @@ -232,7 +232,7 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest private final AtomicInteger requests = new AtomicInteger(); @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { baseRequest.setHandled(true); if (requests.incrementAndGet() == 1) @@ -272,7 +272,7 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest startBasic(scenario, new AbstractHandler() { @Override - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { baseRequest.setHandled(true); if (request.getRequestURI().endsWith("/redirect")) @@ -369,6 +369,9 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest ContentResponse response = request.timeout(5, TimeUnit.SECONDS).send(); assertNotNull(response); assertEquals(401, response.getStatus()); + + Authentication.Result authenticationResult = authenticationStore.findAuthenticationResult(uri); + assertNull(authenticationResult); } @ParameterizedTest @@ -401,15 +404,11 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest .scheme(scenario.getScheme()) .path("/secure") .timeout(5, TimeUnit.SECONDS) - .send(new Response.CompleteListener() + .send(result -> { - @Override - public void onComplete(Result result) - { - assertTrue(result.isFailed()); - assertEquals(cause, result.getFailure().getMessage()); - latch.countDown(); - } + assertTrue(result.isFailed()); + assertEquals(cause, result.getFailure().getMessage()); + latch.countDown(); }); assertTrue(latch.await(5, TimeUnit.SECONDS)); @@ -480,7 +479,6 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); } - @ParameterizedTest @ArgumentsSource(ScenarioProvider.class) public void test_RequestFailsAfterResponse(Scenario scenario) throws Exception @@ -488,10 +486,9 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest startBasic(scenario, new EmptyServerHandler() { @Override - protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException + protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { - IO.readBytes(jettyRequest.getInputStream()); + IO.readBytes(jettyRequest.getInputStream()); } }); @@ -543,8 +540,9 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest { authLatch.await(); } - catch(InterruptedException e) - {} + catch(InterruptedException ignored) + { + } // Trigger request failure. throw new RuntimeException(); @@ -636,28 +634,27 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest HeaderInfo headerInfo = aph.getHeaderInfo("Digest realm=\"thermostat\", qop=\"auth\", nonce=\"1523430383\"").get(0); assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfo.getParameter("qop").equals("auth")); - assertTrue(headerInfo.getParameter("realm").equals("thermostat")); - assertTrue(headerInfo.getParameter("nonce").equals("1523430383")); + assertEquals("auth", headerInfo.getParameter("qop")); + assertEquals("thermostat", headerInfo.getParameter("realm")); + assertEquals("1523430383", headerInfo.getParameter("nonce")); headerInfo = aph.getHeaderInfo("Digest qop=\"auth\", realm=\"thermostat\", nonce=\"1523430383\"").get(0); assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfo.getParameter("qop").equals("auth")); - assertTrue(headerInfo.getParameter("realm").equals("thermostat")); - assertTrue(headerInfo.getParameter("nonce").equals("1523430383")); + assertEquals("auth", headerInfo.getParameter("qop")); + assertEquals("thermostat", headerInfo.getParameter("realm")); + assertEquals("1523430383", headerInfo.getParameter("nonce")); headerInfo = aph.getHeaderInfo("Digest qop=\"auth\", nonce=\"1523430383\", realm=\"thermostat\"").get(0); assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfo.getParameter("qop").equals("auth")); - assertTrue(headerInfo.getParameter("realm").equals("thermostat")); - assertTrue(headerInfo.getParameter("nonce").equals("1523430383")); + assertEquals("auth", headerInfo.getParameter("qop")); + assertEquals("thermostat", headerInfo.getParameter("realm")); + assertEquals("1523430383", headerInfo.getParameter("nonce")); headerInfo = aph.getHeaderInfo("Digest qop=\"auth\", nonce=\"1523430383\"").get(0); assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfo.getParameter("qop").equals("auth")); - assertTrue(headerInfo.getParameter("realm") == null); - assertTrue(headerInfo.getParameter("nonce").equals("1523430383")); - + assertEquals("auth", headerInfo.getParameter("qop")); + assertNull(headerInfo.getParameter("realm")); + assertEquals("1523430383", headerInfo.getParameter("nonce")); // test multiple authentications List headerInfoList = aph.getHeaderInfo("Digest qop=\"auth\", realm=\"thermostat\", nonce=\"1523430383\", " @@ -666,34 +663,34 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest + "Digest qop=\"auth4\", nonce=\"3526435321\""); assertTrue(headerInfoList.get(0).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(0).getParameter("qop").equals("auth")); - assertTrue(headerInfoList.get(0).getParameter("realm").equals("thermostat")); - assertTrue(headerInfoList.get(0).getParameter("nonce").equals("1523430383")); + assertEquals("auth", headerInfoList.get(0).getParameter("qop")); + assertEquals("thermostat", headerInfoList.get(0).getParameter("realm")); + assertEquals("1523430383", headerInfoList.get(0).getParameter("nonce")); assertTrue(headerInfoList.get(1).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(1).getParameter("qop").equals("auth2")); - assertTrue(headerInfoList.get(1).getParameter("realm").equals("thermostat2")); - assertTrue(headerInfoList.get(1).getParameter("nonce").equals("4522530354")); + assertEquals("auth2", headerInfoList.get(1).getParameter("qop")); + assertEquals("thermostat2", headerInfoList.get(1).getParameter("realm")); + assertEquals("4522530354", headerInfoList.get(1).getParameter("nonce")); assertTrue(headerInfoList.get(2).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(2).getParameter("qop").equals("auth3")); - assertTrue(headerInfoList.get(2).getParameter("realm").equals("thermostat3")); - assertTrue(headerInfoList.get(2).getParameter("nonce").equals("9523570528")); + assertEquals("auth3", headerInfoList.get(2).getParameter("qop")); + assertEquals("thermostat3", headerInfoList.get(2).getParameter("realm")); + assertEquals("9523570528", headerInfoList.get(2).getParameter("nonce")); assertTrue(headerInfoList.get(3).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(3).getParameter("qop").equals("auth4")); - assertTrue(headerInfoList.get(3).getParameter("realm") == null); - assertTrue(headerInfoList.get(3).getParameter("nonce").equals("3526435321")); + assertEquals("auth4", headerInfoList.get(3).getParameter("qop")); + assertNull(headerInfoList.get(3).getParameter("realm")); + assertEquals("3526435321", headerInfoList.get(3).getParameter("nonce")); List headerInfos = aph.getHeaderInfo("Newauth realm=\"apps\", type=1, title=\"Login to \\\"apps\\\"\", Basic realm=\"simple\""); assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Newauth")); - assertTrue(headerInfos.get(0).getParameter("realm").equals("apps")); - assertTrue(headerInfos.get(0).getParameter("type").equals("1")); + assertEquals("apps", headerInfos.get(0).getParameter("realm")); + assertEquals("1", headerInfos.get(0).getParameter("type")); assertEquals(headerInfos.get(0).getParameter("title"),"Login to \"apps\""); assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Basic")); - assertTrue(headerInfos.get(1).getParameter("realm").equals("simple")); + assertEquals("simple", headerInfos.get(1).getParameter("realm")); } @Test @@ -702,7 +699,7 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest HeaderInfo headerInfo = aph.getHeaderInfo("Scheme").get(0); assertTrue(headerInfo.getType().equalsIgnoreCase("Scheme")); - assertTrue(headerInfo.getParameter("realm") == null); + assertNull(headerInfo.getParameter("realm")); List headerInfos = aph.getHeaderInfo("Scheme1 , Scheme2 , Scheme3"); assertEquals(3, headerInfos.size()); @@ -712,51 +709,49 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest headerInfo = aph.getHeaderInfo("Scheme name=\"value\", other=\"value2\"").get(0); assertTrue(headerInfo.getType().equalsIgnoreCase("Scheme")); - assertTrue(headerInfo.getParameter("name").equals("value")); - assertTrue(headerInfo.getParameter("other").equals("value2")); + assertEquals("value", headerInfo.getParameter("name")); + assertEquals("value2", headerInfo.getParameter("other")); headerInfo = aph.getHeaderInfo("Scheme name = value , other = \"value2\" ").get(0); assertTrue(headerInfo.getType().equalsIgnoreCase("Scheme")); - assertTrue(headerInfo.getParameter("name").equals("value")); - assertTrue(headerInfo.getParameter("other").equals("value2")); + assertEquals("value", headerInfo.getParameter("name")); + assertEquals("value2", headerInfo.getParameter("other")); headerInfos = aph.getHeaderInfo(", , , , ,,,Scheme name=value, ,,Scheme2 name=value2,, ,,"); assertEquals(headerInfos.size(), 2); assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme")); - assertTrue(headerInfos.get(0).getParameter("nAmE").equals("value")); + assertEquals("value", headerInfos.get(0).getParameter("nAmE")); assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Scheme2")); headerInfos = aph.getHeaderInfo("Scheme name=value, Scheme2 name=value2"); assertEquals(headerInfos.size(), 2); assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme")); - assertTrue(headerInfos.get(0).getParameter("nAmE").equals("value")); + assertEquals("value", headerInfos.get(0).getParameter("nAmE")); assertThat(headerInfos.get(1).getType(), equalToIgnoringCase("Scheme2")); - assertTrue(headerInfos.get(1).getParameter("nAmE").equals("value2")); + assertEquals("value2", headerInfos.get(1).getParameter("nAmE")); headerInfos = aph.getHeaderInfo("Scheme , ,, ,, name=value, Scheme2 name=value2"); assertEquals(headerInfos.size(), 2); assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme")); - assertTrue(headerInfos.get(0).getParameter("name").equals("value")); + assertEquals("value", headerInfos.get(0).getParameter("name")); assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Scheme2")); - assertTrue(headerInfos.get(1).getParameter("name").equals("value2")); + assertEquals("value2", headerInfos.get(1).getParameter("name")); //Negotiate with base64 Content headerInfo = aph.getHeaderInfo("Negotiate TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAFAs4OAAAADw==").get(0); assertTrue(headerInfo.getType().equalsIgnoreCase("Negotiate")); - assertTrue(headerInfo.getBase64().equals("TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAFAs4OAAAADw==")); + assertEquals("TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAFAs4OAAAADw==", headerInfo.getBase64()); headerInfos = aph.getHeaderInfo("Negotiate TlRMTVNTUAABAAAAAAAAAFAs4OAAAADw==, " + "Negotiate YIIJvwYGKwYBBQUCoIIJszCCCa+gJDAi="); assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Negotiate")); - assertTrue(headerInfos.get(0).getBase64().equals("TlRMTVNTUAABAAAAAAAAAFAs4OAAAADw==")); + assertEquals("TlRMTVNTUAABAAAAAAAAAFAs4OAAAADw==", headerInfos.get(0).getBase64()); assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Negotiate")); - assertTrue(headerInfos.get(1).getBase64().equals("YIIJvwYGKwYBBQUCoIIJszCCCa+gJDAi=")); + assertEquals("YIIJvwYGKwYBBQUCoIIJszCCCa+gJDAi=", headerInfos.get(1).getBase64()); } - - @Test public void testEqualsInParam() { @@ -765,10 +760,9 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest headerInfo = aph.getHeaderInfo("Digest realm=\"=the=rmo=stat=\", qop=\"=a=u=t=h=\", nonce=\"=1523430383=\"").get(0); assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfo.getParameter("qop").equals("=a=u=t=h=")); - assertTrue(headerInfo.getParameter("realm").equals("=the=rmo=stat=")); - assertTrue(headerInfo.getParameter("nonce").equals("=1523430383=")); - + assertEquals("=a=u=t=h=", headerInfo.getParameter("qop")); + assertEquals("=the=rmo=stat=", headerInfo.getParameter("realm")); + assertEquals("=1523430383=", headerInfo.getParameter("nonce")); // test multiple authentications List headerInfoList = aph.getHeaderInfo("Digest qop=\"=au=th=\", realm=\"=ther=mostat=\", nonce=\"=152343=0383=\", " @@ -776,23 +770,23 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest + "Digest qop=\"auth3=\", nonce=\"9523570528=\", realm=\"thermostat3=\", "); assertTrue(headerInfoList.get(0).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(0).getParameter("qop").equals("=au=th=")); - assertTrue(headerInfoList.get(0).getParameter("realm").equals("=ther=mostat=")); - assertTrue(headerInfoList.get(0).getParameter("nonce").equals("=152343=0383=")); + assertEquals("=au=th=", headerInfoList.get(0).getParameter("qop")); + assertEquals("=ther=mostat=", headerInfoList.get(0).getParameter("realm")); + assertEquals("=152343=0383=", headerInfoList.get(0).getParameter("nonce")); assertTrue(headerInfoList.get(1).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(1).getParameter("qop").equals("=auth2")); - assertTrue(headerInfoList.get(1).getParameter("realm").equals("=thermostat2")); - assertTrue(headerInfoList.get(1).getParameter("nonce").equals("=4522530354")); + assertEquals("=auth2", headerInfoList.get(1).getParameter("qop")); + assertEquals("=thermostat2", headerInfoList.get(1).getParameter("realm")); + assertEquals("=4522530354", headerInfoList.get(1).getParameter("nonce")); assertTrue(headerInfoList.get(2).getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfoList.get(2).getParameter("qop").equals("auth3=")); - assertTrue(headerInfoList.get(2).getParameter("realm").equals("thermostat3=")); - assertTrue(headerInfoList.get(2).getParameter("nonce").equals("9523570528=")); + assertEquals("auth3=", headerInfoList.get(2).getParameter("qop")); + assertEquals("thermostat3=", headerInfoList.get(2).getParameter("realm")); + assertEquals("9523570528=", headerInfoList.get(2).getParameter("nonce")); } @Test - public void testSingleChallangeLooksLikeMultipleChallenge() + public void testSingleChallengeLooksLikeMultipleChallenges() { AuthenticationProtocolHandler aph = new WWWAuthenticationProtocolHandler(client); List headerInfoList = aph.getHeaderInfo("Digest param=\",f \""); @@ -803,8 +797,8 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest HeaderInfo headerInfo = headerInfoList.get(0); assertTrue(headerInfo.getType().equalsIgnoreCase("Digest")); - assertTrue(headerInfo.getParameter("qop").equals(",Digest realm=hello")); - assertTrue(headerInfo.getParameter("realm").equals("thermostat")); + assertEquals(",Digest realm=hello", headerInfo.getParameter("qop")); + assertEquals("thermostat", headerInfo.getParameter("realm")); assertEquals(headerInfo.getParameter("nonce"), "1523430383="); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java index f46d58d330e..f28893ca4e8 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientProxyTest.java @@ -18,8 +18,6 @@ package org.eclipse.jetty.client; -import static org.junit.jupiter.api.Assertions.assertEquals; - import java.io.IOException; import java.net.URI; import java.nio.charset.StandardCharsets; @@ -41,6 +39,8 @@ import org.eclipse.jetty.util.B64Code; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ArgumentsSource; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class HttpClientProxyTest extends AbstractHttpClientServerTest { @ParameterizedTest @@ -315,7 +315,7 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest assertEquals(status, response1.getStatus()); assertEquals(3, requests.get()); - // Make again the request, authentication is cached, expect 204. + // Make again the request, only the server authentication is cached, expect 407 + 204. requests.set(0); ContentResponse response2 = client.newRequest(serverHost, serverPort) .scheme(scenario.getScheme()) @@ -323,7 +323,7 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest .send(); assertEquals(status, response2.getStatus()); - assertEquals(1, requests.get()); + assertEquals(2, requests.get()); } @ParameterizedTest diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java index 1ab7f718e22..bff0dd69914 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java @@ -424,8 +424,9 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint { Connection old_connection = getConnection(); - ByteBuffer prefilled = (old_connection instanceof Connection.UpgradeFrom) - ?((Connection.UpgradeFrom)old_connection).onUpgradeFrom():null; + ByteBuffer buffer = (old_connection instanceof Connection.UpgradeFrom) ? + ((Connection.UpgradeFrom)old_connection).onUpgradeFrom() : + null; old_connection.onClose(); old_connection.getEndPoint().setConnection(newConnection); @@ -434,9 +435,9 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint this, old_connection, newConnection, BufferUtil.toDetailString(prefilled)); if (newConnection instanceof Connection.UpgradeTo) - ((Connection.UpgradeTo)newConnection).onUpgradeTo(prefilled); - else if (BufferUtil.hasContent(prefilled)) - throw new IllegalStateException(); + ((Connection.UpgradeTo)newConnection).onUpgradeTo(buffer); + else if (BufferUtil.hasContent(buffer)) + throw new IllegalStateException("Cannot upgrade: " + newConnection + " does not implement " + Connection.UpgradeTo.class.getName()); newConnection.onOpen(); } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java index 93ba2f3fbe6..1dca5816e75 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java @@ -35,6 +35,7 @@ import java.util.Collections; import java.util.Deque; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; @@ -60,6 +61,20 @@ import org.eclipse.jetty.util.thread.strategy.EatWhatYouKill; public class ManagedSelector extends ContainerLifeCycle implements Dumpable { private static final Logger LOG = Log.getLogger(ManagedSelector.class); + private static final boolean FORCE_SELECT_NOW; + static + { + String property = System.getProperty("org.eclipse.jetty.io.forceSelectNow"); + if (property != null) + { + FORCE_SELECT_NOW = Boolean.parseBoolean(property); + } + else + { + property = System.getProperty("os.name"); + FORCE_SELECT_NOW = property != null && property.toLowerCase(Locale.ENGLISH).contains("windows"); + } + } private final AtomicBoolean _started = new AtomicBoolean(false); private boolean _selecting = false; @@ -457,7 +472,8 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable if (Thread.interrupted() && !isRunning()) throw new ClosedSelectorException(); - selected = selector.selectNow(); + if (FORCE_SELECT_NOW) + selected = selector.selectNow(); } if (LOG.isDebugEnabled()) LOG.debug("Selector {} woken up from select, {}/{}/{} selected", selector, selected, selector.selectedKeys().size(), selector.keys().size()); diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java index 2d76b105675..53467589e95 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java @@ -76,7 +76,7 @@ import org.eclipse.jetty.util.thread.Invocable; * be called again and make another best effort attempt to progress the connection. * */ -public class SslConnection extends AbstractConnection +public class SslConnection extends AbstractConnection implements Connection.UpgradeTo { private static final Logger LOG = Log.getLogger(SslConnection.class); private static final String TLS_1_3 = "TLSv1.3"; @@ -260,6 +260,22 @@ public class SslConnection extends AbstractConnection this._allowMissingCloseMessage = allowMissingCloseMessage; } + private void acquireEncryptedInput() + { + if (_encryptedInput == null) + _encryptedInput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers); + } + + @Override + public void onUpgradeTo(ByteBuffer buffer) + { + if (BufferUtil.hasContent(buffer)) + { + acquireEncryptedInput(); + BufferUtil.append(_encryptedInput, buffer); + } + } + @Override public void onOpen() { @@ -526,8 +542,7 @@ public class SslConnection extends AbstractConnection throw new IllegalStateException("Unexpected HandshakeStatus " + status); } - if (_encryptedInput == null) - _encryptedInput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers); + acquireEncryptedInput(); // can we use the passed buffer if it is big enough ByteBuffer app_in; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java index 65e1c880f11..f2ffe24fb85 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java @@ -29,7 +29,10 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.QuotedCSV; import org.eclipse.jetty.server.HttpConfiguration.Customizer; +import org.eclipse.jetty.util.HostPort; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; /* ------------------------------------------------------------ */ @@ -54,6 +57,8 @@ import org.eclipse.jetty.util.StringUtil; */ public class ForwardedRequestCustomizer implements Customizer { + private static final Logger LOG = Log.getLogger(ForwardedRequestCustomizer.class); + private HostPortHttpField _forcedHost; private String _forwardedHeader = HttpHeader.FORWARDED.toString(); private String _forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString(); @@ -297,7 +302,7 @@ public class ForwardedRequestCustomizer implements Customizer RFC7239 rfc7239 = null; String forwardedHost = null; String forwardedServer = null; - String forwardedFor = null; + HostPort forwardedFor = null; String forwardedProto = null; String forwardedHttps = null; @@ -333,7 +338,7 @@ public class ForwardedRequestCustomizer implements Customizer forwardedServer = getLeftMost(field.getValue()); if (forwardedFor==null && _forwardedForHeader!=null && _forwardedForHeader.equalsIgnoreCase(name)) - forwardedFor = getLeftMost(field.getValue()); + forwardedFor = getRemoteAddr(field.getValue()); if (forwardedProto==null && _forwardedProtoHeader!=null && _forwardedProtoHeader.equalsIgnoreCase(name)) forwardedProto = getLeftMost(field.getValue()); @@ -389,7 +394,7 @@ public class ForwardedRequestCustomizer implements Customizer } else if (forwardedFor != null) { - request.setRemoteAddr(InetSocketAddress.createUnresolved(forwardedFor,request.getRemotePort())); + request.setRemoteAddr(InetSocketAddress.createUnresolved(forwardedFor.getHost(), (forwardedFor.getPort() > 0) ? forwardedFor.getPort() : request.getRemotePort())); } // handle protocol identifier @@ -430,6 +435,26 @@ public class ForwardedRequestCustomizer implements Customizer // The left-most value is the farthest downstream client return headerValue.substring(0,commaIndex).trim(); } + + protected HostPort getRemoteAddr(String headerValue) + { + String leftMost = getLeftMost(headerValue); + if (leftMost == null) + { + return null; + } + + try + { + return new HostPort(leftMost); + } + catch (Exception e) + { + // failed to parse in host[:port] format + LOG.ignore(e); + return null; + } + } @Override public String toString() diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 5bb963c10a4..91575cfe9bd 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -50,7 +50,7 @@ import org.eclipse.jetty.util.log.Logger; /** *

A {@link Connection} that handles the HTTP protocol.

*/ -public class HttpConnection extends AbstractConnection implements Runnable, HttpTransport, Connection.UpgradeFrom, WriteFlusher.Listener +public class HttpConnection extends AbstractConnection implements Runnable, HttpTransport, WriteFlusher.Listener, Connection.UpgradeFrom, Connection.UpgradeTo { private static final Logger LOG = Log.getLogger(HttpConnection.class); public static final HttpField CONNECTION_CLOSE = new PreEncodedHttpField(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE.asString()); @@ -193,6 +193,13 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http return null; } + @Override + public void onUpgradeTo(ByteBuffer buffer) + { + if (BufferUtil.hasContent(buffer)) + BufferUtil.append(getRequestBuffer(), buffer); + } + @Override public void onFlushed(long bytes) throws IOException { @@ -497,7 +504,10 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http public void onOpen() { super.onOpen(); - fillInterested(); + if (isRequestBufferEmpty()) + fillInterested(); + else + getExecutor().execute(this); } @Override diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/OptionalSslConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/OptionalSslConnectionFactory.java new file mode 100644 index 00000000000..7b75a01917a --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/OptionalSslConnectionFactory.java @@ -0,0 +1,226 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +import org.eclipse.jetty.io.AbstractConnection; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +/** + *

A ConnectionFactory whose connections detect whether the first bytes are + * TLS bytes and upgrades to either a TLS connection or to another configurable + * connection.

+ */ +public class OptionalSslConnectionFactory extends AbstractConnectionFactory +{ + private static final Logger LOG = Log.getLogger(OptionalSslConnection.class); + private static final int TLS_ALERT_FRAME_TYPE = 0x15; + private static final int TLS_HANDSHAKE_FRAME_TYPE = 0x16; + private static final int TLS_MAJOR_VERSION = 3; + + private final SslConnectionFactory sslConnectionFactory; + private final String otherProtocol; + + /** + *

Creates a new ConnectionFactory whose connections can upgrade to TLS or another protocol.

+ *

If {@code otherProtocol} is {@code null}, and the first bytes are not TLS, then + * {@link #otherProtocol(ByteBuffer, EndPoint)} is called.

+ * + * @param sslConnectionFactory The SslConnectionFactory to use if the first bytes are TLS + * @param otherProtocol the protocol of the ConnectionFactory to use if the first bytes are not TLS, + * or null to explicitly handle the non-TLS case + */ + public OptionalSslConnectionFactory(SslConnectionFactory sslConnectionFactory, String otherProtocol) + { + super("ssl|other"); + this.sslConnectionFactory = sslConnectionFactory; + this.otherProtocol = otherProtocol; + } + + @Override + public Connection newConnection(Connector connector, EndPoint endPoint) + { + return configure(new OptionalSslConnection(endPoint, connector), connector, endPoint); + } + + /** + * @param buffer The buffer with the first bytes of the connection + * @return whether the bytes seem TLS bytes + */ + protected boolean seemsTLS(ByteBuffer buffer) + { + int tlsFrameType = buffer.get(0) & 0xFF; + int tlsMajorVersion = buffer.get(1) & 0xFF; + return (tlsFrameType == TLS_HANDSHAKE_FRAME_TYPE || tlsFrameType == TLS_ALERT_FRAME_TYPE) && tlsMajorVersion == TLS_MAJOR_VERSION; + } + + /** + *

Callback method invoked when {@code otherProtocol} is {@code null} + * and the first bytes are not TLS.

+ *

This typically happens when a client is trying to connect to a TLS + * port using the {@code http} scheme (and not the {@code https} scheme).

+ * + * @param buffer The buffer with the first bytes of the connection + * @param endPoint The connection EndPoint object + * @see #seemsTLS(ByteBuffer) + */ + protected void otherProtocol(ByteBuffer buffer, EndPoint endPoint) + { + // There are always at least 2 bytes. + int byte1 = buffer.get(0) & 0xFF; + int byte2 = buffer.get(1) & 0xFF; + if (byte1 == 'G' && byte2 == 'E') + { + // Plain text HTTP to a HTTPS port, + // write a minimal response. + String body = "" + + "\r\n" + + "\r\n" + + "Bad Request\r\n" + + "" + + "

Bad Request

" + + "

HTTP request to HTTPS port

" + + "\r\n" + + ""; + String response = "" + + "HTTP/1.1 400 Bad Request\r\n" + + "Content-Type: text/html\r\n" + + "Content-Length: " + body.length() + "\r\n" + + "Connection: close\r\n" + + "\r\n" + + body; + Callback.Completable completable = new Callback.Completable(); + endPoint.write(completable, ByteBuffer.wrap(response.getBytes(StandardCharsets.US_ASCII))); + completable.whenComplete((r, x) -> endPoint.close()); + } + else + { + endPoint.close(); + } + } + + private class OptionalSslConnection extends AbstractConnection implements Connection.UpgradeFrom + { + private final Connector connector; + private final ByteBuffer buffer; + + public OptionalSslConnection(EndPoint endPoint, Connector connector) + { + super(endPoint, connector.getExecutor()); + this.connector = connector; + this.buffer = BufferUtil.allocateDirect(1536); + } + + @Override + public void onOpen() + { + super.onOpen(); + fillInterested(); + } + + @Override + public void onFillable() + { + try + { + while (true) + { + int filled = getEndPoint().fill(buffer); + if (filled > 0) + { + // Always have at least 2 bytes. + if (BufferUtil.length(buffer) >= 2) + { + upgrade(buffer); + break; + } + } + else if (filled == 0) + { + fillInterested(); + break; + } + else + { + close(); + break; + } + } + } + catch (IOException x) + { + LOG.warn(x); + close(); + } + } + + @Override + public ByteBuffer onUpgradeFrom() + { + return buffer; + } + + private void upgrade(ByteBuffer buffer) + { + if (LOG.isDebugEnabled()) + LOG.debug("Read {}", BufferUtil.toDetailString(buffer)); + + EndPoint endPoint = getEndPoint(); + if (seemsTLS(buffer)) + { + if (LOG.isDebugEnabled()) + LOG.debug("Detected TLS bytes, upgrading to {}", sslConnectionFactory); + endPoint.upgrade(sslConnectionFactory.newConnection(connector, endPoint)); + } + else + { + if (otherProtocol != null) + { + ConnectionFactory connectionFactory = connector.getConnectionFactory(otherProtocol); + if (connectionFactory != null) + { + if (LOG.isDebugEnabled()) + LOG.debug("Detected non-TLS bytes, upgrading to {}", connectionFactory); + Connection next = connectionFactory.newConnection(connector, endPoint); + endPoint.upgrade(next); + } + else + { + LOG.warn("Missing {} {} in {}", otherProtocol, ConnectionFactory.class.getSimpleName(), connector); + close(); + } + } + else + { + if (LOG.isDebugEnabled()) + LOG.debug("Detected non-TLS bytes, but no other protocol to upgrade to"); + otherProtocol(buffer, endPoint); + } + } + } + } +} diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java index 7e8bf1ab279..e1b2c69d467 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java @@ -233,6 +233,38 @@ public class ForwardedRequestCustomizerTest assertEquals("0",_results.poll()); } + @Test + public void testForIpv4WithPort() throws Exception + { + String response=_connector.getResponse( + "GET / HTTP/1.1\n"+ + "Host: myhost\n"+ + "X-Forwarded-For: 10.9.8.7:1111,6.5.4.3:2222\n"+ + "\n"); + assertThat(response, Matchers.containsString("200 OK")); + assertEquals("http",_results.poll()); + assertEquals("myhost",_results.poll()); + assertEquals("80",_results.poll()); + assertEquals("10.9.8.7",_results.poll()); + assertEquals("1111",_results.poll()); + } + + @Test + public void testForIpv6WithPort() throws Exception + { + String response=_connector.getResponse( + "GET / HTTP/1.1\n"+ + "Host: myhost\n"+ + "X-Forwarded-For: [2001:db8:cafe::17]:1111,6.5.4.3:2222\n"+ + "\n"); + assertThat(response, Matchers.containsString("200 OK")); + assertEquals("http",_results.poll()); + assertEquals("myhost",_results.poll()); + assertEquals("80",_results.poll()); + assertEquals("[2001:db8:cafe::17]",_results.poll()); + assertEquals("1111",_results.poll()); + } + @Test public void testLegacyProto() throws Exception { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/OptionalSslConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/OptionalSslConnectionTest.java new file mode 100644 index 00000000000..7a8e7a00e7e --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/OptionalSslConnectionTest.java @@ -0,0 +1,216 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server; + +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.util.function.Function; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpTester; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class OptionalSslConnectionTest +{ + private Server server; + private ServerConnector connector; + + private void startServer(Function configFn, Handler handler) throws Exception + { + QueuedThreadPool serverThreads = new QueuedThreadPool(); + serverThreads.setName("server"); + server = new Server(serverThreads); + + String keystore = MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath(); + SslContextFactory sslContextFactory = new SslContextFactory(); + sslContextFactory.setKeyStorePath(keystore); + sslContextFactory.setKeyStorePassword("storepwd"); + sslContextFactory.setKeyManagerPassword("keypwd"); + + HttpConfiguration httpConfig = new HttpConfiguration(); + HttpConnectionFactory http = new HttpConnectionFactory(httpConfig); + SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, http.getProtocol()); + OptionalSslConnectionFactory sslOrOther = configFn.apply(ssl); + connector = new ServerConnector(server, 1, 1, sslOrOther, ssl, http); + server.addConnector(connector); + + server.setHandler(handler); + + server.start(); + } + + @AfterEach + public void stopServer() throws Exception + { + if (server != null) + server.stop(); + } + + private OptionalSslConnectionFactory optionalSsl(SslConnectionFactory ssl) + { + return new OptionalSslConnectionFactory(ssl, ssl.getNextProtocol()); + } + + private OptionalSslConnectionFactory optionalSslNoOtherProtocol(SslConnectionFactory ssl) + { + return new OptionalSslConnectionFactory(ssl, null); + } + + @Test + public void testOptionalSslConnection() throws Exception + { + startServer(this::optionalSsl, new EmptyServerHandler()); + + String request = "" + + "GET / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "\r\n"; + byte[] requestBytes = request.getBytes(StandardCharsets.US_ASCII); + + // Try first a plain text connection. + try (Socket plain = new Socket()) + { + plain.connect(new InetSocketAddress("localhost", connector.getLocalPort()), 1000); + OutputStream plainOutput = plain.getOutputStream(); + plainOutput.write(requestBytes); + plainOutput.flush(); + + plain.setSoTimeout(5000); + InputStream plainInput = plain.getInputStream(); + HttpTester.Response response = HttpTester.parseResponse(plainInput); + assertNotNull(response); + assertEquals(HttpStatus.OK_200, response.getStatus()); + } + + // Then try a SSL connection. + SslContextFactory sslContextFactory = new SslContextFactory(true); + sslContextFactory.start(); + try (Socket ssl = sslContextFactory.newSslSocket()) + { + ssl.connect(new InetSocketAddress("localhost", connector.getLocalPort()), 1000); + OutputStream sslOutput = ssl.getOutputStream(); + sslOutput.write(requestBytes); + sslOutput.flush(); + + ssl.setSoTimeout(5000); + InputStream sslInput = ssl.getInputStream(); + HttpTester.Response response = HttpTester.parseResponse(sslInput); + assertNotNull(response); + assertEquals(HttpStatus.OK_200, response.getStatus()); + } + finally + { + sslContextFactory.stop(); + } + } + + @Test + public void testOptionalSslConnectionWithOnlyOneByteShouldIdleTimeout() throws Exception + { + startServer(this::optionalSsl, new EmptyServerHandler()); + long idleTimeout = 1000; + connector.setIdleTimeout(idleTimeout); + + try (Socket socket = new Socket()) + { + socket.connect(new InetSocketAddress("localhost", connector.getLocalPort()), 1000); + OutputStream output = socket.getOutputStream(); + output.write(0x16); + output.flush(); + + socket.setSoTimeout((int)(2 * idleTimeout)); + InputStream input = socket.getInputStream(); + int read = input.read(); + assertEquals(-1, read); + } + } + + @Test + public void testOptionalSslConnectionWithUnknownBytes() throws Exception + { + startServer(this::optionalSslNoOtherProtocol, new EmptyServerHandler()); + + try (Socket socket = new Socket()) + { + socket.connect(new InetSocketAddress("localhost", connector.getLocalPort()), 1000); + OutputStream output = socket.getOutputStream(); + output.write(0x00); + output.flush(); + Thread.sleep(500); + output.write(0x00); + output.flush(); + + socket.setSoTimeout(5000); + InputStream input = socket.getInputStream(); + int read = input.read(); + assertEquals(-1, read); + } + } + + @Test + public void testOptionalSslConnectionWithHTTPBytes() throws Exception + { + startServer(this::optionalSslNoOtherProtocol, new EmptyServerHandler()); + + String request = "" + + "GET / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "\r\n"; + byte[] requestBytes = request.getBytes(StandardCharsets.US_ASCII); + + // Send a plain text HTTP request to SSL port, + // we should get back a minimal HTTP response. + try (Socket socket = new Socket()) + { + socket.connect(new InetSocketAddress("localhost", connector.getLocalPort()), 1000); + OutputStream output = socket.getOutputStream(); + output.write(requestBytes); + output.flush(); + + socket.setSoTimeout(5000); + InputStream input = socket.getInputStream(); + HttpTester.Response response = HttpTester.parseResponse(input); + assertNotNull(response); + assertEquals(HttpStatus.BAD_REQUEST_400, response.getStatus()); + } + } + + private static class EmptyServerHandler extends AbstractHandler.ErrorDispatchHandler + { + @Override + protected void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) + { + jettyRequest.setHandled(true); + } + } +} diff --git a/jetty-server/src/test/resources/jetty-logging.properties b/jetty-server/src/test/resources/jetty-logging.properties index 3f8368fa054..21db0759fe3 100644 --- a/jetty-server/src/test/resources/jetty-logging.properties +++ b/jetty-server/src/test/resources/jetty-logging.properties @@ -1,4 +1,5 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog #org.eclipse.jetty.LEVEL=DEBUG +#org.eclipse.jetty.server.LEVEL=DEBUG #org.eclipse.jetty.server.ConnectionLimit.LEVEL=DEBUG -#org.eclipse.jetty.server.AcceptRateLimit.LEVEL=DEBUG \ No newline at end of file +#org.eclipse.jetty.server.AcceptRateLimit.LEVEL=DEBUG diff --git a/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/DelegatedClientUpgradeRequest.java b/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/DelegatedJavaxClientUpgradeRequest.java similarity index 84% rename from jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/DelegatedClientUpgradeRequest.java rename to jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/DelegatedJavaxClientUpgradeRequest.java index 8b883c86ace..d09d7e0f793 100644 --- a/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/DelegatedClientUpgradeRequest.java +++ b/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/DelegatedJavaxClientUpgradeRequest.java @@ -18,20 +18,21 @@ package org.eclipse.jetty.websocket.javax.client; -import org.eclipse.jetty.websocket.javax.common.UpgradeRequest; - import java.net.URI; import java.security.Principal; +import org.eclipse.jetty.websocket.core.client.ClientUpgradeRequest; +import org.eclipse.jetty.websocket.javax.common.UpgradeRequest; + /** * Representing the Jetty {@link org.eclipse.jetty.client.HttpClient}'s {@link org.eclipse.jetty.client.HttpRequest} * in the {@link UpgradeRequest} interface. */ -public class DelegatedClientUpgradeRequest implements UpgradeRequest +public class DelegatedJavaxClientUpgradeRequest implements UpgradeRequest { - private final org.eclipse.jetty.websocket.core.client.UpgradeRequest delegate; + private final ClientUpgradeRequest delegate; - public DelegatedClientUpgradeRequest(org.eclipse.jetty.websocket.core.client.UpgradeRequest delegate) + public DelegatedJavaxClientUpgradeRequest(ClientUpgradeRequest delegate) { this.delegate = delegate; } diff --git a/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/DelegatedClientUpgradeResponse.java b/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/DelegatedJavaxClientUpgradeResponse.java similarity index 93% rename from jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/DelegatedClientUpgradeResponse.java rename to jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/DelegatedJavaxClientUpgradeResponse.java index f2646dea56c..2709aa88746 100644 --- a/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/DelegatedClientUpgradeResponse.java +++ b/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/DelegatedJavaxClientUpgradeResponse.java @@ -18,24 +18,24 @@ package org.eclipse.jetty.websocket.javax.client; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + import org.eclipse.jetty.client.HttpResponse; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.websocket.core.ExtensionConfig; import org.eclipse.jetty.websocket.javax.common.UpgradeResponse; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - /** * Representing the Jetty {@link org.eclipse.jetty.client.HttpClient}'s {@link HttpResponse} * in the {@link UpgradeResponse} interface. */ -public class DelegatedClientUpgradeResponse implements UpgradeResponse +public class DelegatedJavaxClientUpgradeResponse implements UpgradeResponse { private HttpResponse delegate; - public DelegatedClientUpgradeResponse(HttpResponse response) + public DelegatedJavaxClientUpgradeResponse(HttpResponse response) { this.delegate = response; } diff --git a/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/ClientUpgradeRequestImpl.java b/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/JavaxClientUpgradeRequest.java similarity index 74% rename from jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/ClientUpgradeRequestImpl.java rename to jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/JavaxClientUpgradeRequest.java index e11ef886f69..b3ee91af5dc 100644 --- a/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/ClientUpgradeRequestImpl.java +++ b/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/JavaxClientUpgradeRequest.java @@ -18,51 +18,53 @@ package org.eclipse.jetty.websocket.javax.client; +import java.net.URI; +import java.util.concurrent.CompletableFuture; + +import javax.websocket.Session; + import org.eclipse.jetty.client.HttpResponse; import org.eclipse.jetty.websocket.core.FrameHandler; +import org.eclipse.jetty.websocket.core.client.ClientUpgradeRequest; import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient; import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandler; import org.eclipse.jetty.websocket.javax.common.UpgradeRequest; import org.eclipse.jetty.websocket.javax.common.UpgradeResponse; -import javax.websocket.Session; -import java.net.URI; -import java.util.concurrent.CompletableFuture; - -public class ClientUpgradeRequestImpl extends org.eclipse.jetty.websocket.core.client.UpgradeRequest +public class JavaxClientUpgradeRequest extends ClientUpgradeRequest { private final JavaxWebSocketClientContainer containerContext; private final Object websocketPojo; - private final CompletableFuture futureJavaxSession; + private final CompletableFuture futureSession; - public ClientUpgradeRequestImpl(JavaxWebSocketClientContainer clientContainer, WebSocketCoreClient coreClient, URI requestURI, Object websocketPojo) + public JavaxClientUpgradeRequest(JavaxWebSocketClientContainer clientContainer, WebSocketCoreClient coreClient, URI requestURI, Object websocketPojo) { super(coreClient, requestURI); this.containerContext = clientContainer; this.websocketPojo = websocketPojo; - this.futureJavaxSession = new CompletableFuture<>(); + this.futureSession = new CompletableFuture<>(); } @Override protected void handleException(Throwable failure) { super.handleException(failure); - futureJavaxSession.completeExceptionally(failure); + futureSession.completeExceptionally(failure); } @Override public FrameHandler getFrameHandler(WebSocketCoreClient coreClient, HttpResponse response) { - UpgradeRequest upgradeRequest = new DelegatedClientUpgradeRequest(this); - UpgradeResponse upgradeResponse = new DelegatedClientUpgradeResponse(response); + UpgradeRequest upgradeRequest = new DelegatedJavaxClientUpgradeRequest(this); + UpgradeResponse upgradeResponse = new DelegatedJavaxClientUpgradeResponse(response); - JavaxWebSocketFrameHandler frameHandler = containerContext.newFrameHandler(websocketPojo, upgradeRequest, upgradeResponse, futureJavaxSession); + JavaxWebSocketFrameHandler frameHandler = containerContext.newFrameHandler(websocketPojo, upgradeRequest, upgradeResponse, futureSession); return frameHandler; } public CompletableFuture getFutureSession() { - return futureJavaxSession; + return futureSession; } } diff --git a/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/JavaxWebSocketClientContainer.java b/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/JavaxWebSocketClientContainer.java index e43a2fec36a..9d0b128e01e 100644 --- a/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/JavaxWebSocketClientContainer.java +++ b/jetty-websocket/javax-websocket-client/src/main/java/org/eclipse/jetty/websocket/javax/client/JavaxWebSocketClientContainer.java @@ -125,7 +125,7 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple * @param upgradeRequest the upgrade request information * @return the future for the session, available on success of connect */ - private CompletableFuture connect(ClientUpgradeRequestImpl upgradeRequest) + private CompletableFuture connect(JavaxClientUpgradeRequest upgradeRequest) { CompletableFuture fut = upgradeRequest.getFutureSession(); try @@ -145,7 +145,7 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple Objects.requireNonNull(configuredEndpoint, "WebSocket configured endpoint cannot be null"); Objects.requireNonNull(destURI, "Destination URI cannot be null"); - ClientUpgradeRequestImpl upgradeRequest = new ClientUpgradeRequestImpl(this, getWebSocketCoreClient(), destURI, configuredEndpoint); + JavaxClientUpgradeRequest upgradeRequest = new JavaxClientUpgradeRequest(this, getWebSocketCoreClient(), destURI, configuredEndpoint); EndpointConfig config = configuredEndpoint.getConfig(); if (config != null && config instanceof ClientEndpointConfig) diff --git a/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketContainer.java b/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketContainer.java index ffd283a8cf4..5f91aa9d13c 100644 --- a/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketContainer.java +++ b/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketContainer.java @@ -18,19 +18,20 @@ package org.eclipse.jetty.websocket.javax.common; -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.util.DecoratedObjectFactory; -import org.eclipse.jetty.util.component.ContainerLifeCycle; -import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry; - -import javax.websocket.Extension; -import javax.websocket.Session; -import javax.websocket.WebSocketContainer; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import javax.websocket.Extension; +import javax.websocket.Session; +import javax.websocket.WebSocketContainer; + +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.DecoratedObjectFactory; +import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry; + public abstract class JavaxWebSocketContainer extends ContainerLifeCycle implements javax.websocket.WebSocketContainer { private long defaultAsyncSendTimeout = -1; @@ -105,7 +106,7 @@ public abstract class JavaxWebSocketContainer extends ContainerLifeCycle impleme public JavaxWebSocketFrameHandler newFrameHandler(Object websocketPojo, UpgradeRequest upgradeRequest, UpgradeResponse upgradeResponse, CompletableFuture futureSession) { - return getFrameHandlerFactory().newJavaxFrameHandler(websocketPojo, upgradeRequest, upgradeResponse, futureSession); + return getFrameHandlerFactory().newJavaxWebSocketFrameHandler(websocketPojo, upgradeRequest, upgradeResponse, futureSession); } @Override diff --git a/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandler.java b/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandler.java index 7cf65580df8..1e11426fe81 100644 --- a/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandler.java +++ b/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandler.java @@ -29,6 +29,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; + import javax.websocket.CloseReason; import javax.websocket.Decoder; import javax.websocket.EndpointConfig; @@ -229,16 +230,14 @@ public class JavaxWebSocketFrameHandler implements FrameHandler openHandle.invoke(); container.addBean(session, true); - futureSession.complete(session); callback.succeeded(); + futureSession.complete(session); } catch (Throwable cause) { Exception wse = new WebSocketException(endpointInstance.getClass().getName() + " OPEN method error: " + cause.getMessage(), cause); - - // TODO This feels like double handling of the exception? Review need for futureSession - futureSession.completeExceptionally(wse); callback.failed(wse); + futureSession.completeExceptionally(wse); } } diff --git a/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandlerFactory.java b/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandlerFactory.java index 6692a5d6a06..778b3a3d695 100644 --- a/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandlerFactory.java +++ b/jetty-websocket/javax-websocket-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandlerFactory.java @@ -18,6 +18,32 @@ package org.eclipse.jetty.websocket.javax.common; +import java.io.InputStream; +import java.io.Reader; +import java.lang.annotation.Annotation; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; + +import javax.websocket.CloseReason; +import javax.websocket.Decoder; +import javax.websocket.EndpointConfig; +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.PongMessage; +import javax.websocket.Session; + import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec; import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders; import org.eclipse.jetty.websocket.javax.common.messages.ByteArrayMessageSink; @@ -37,31 +63,6 @@ import org.eclipse.jetty.websocket.javax.common.util.InvalidSignatureException; import org.eclipse.jetty.websocket.javax.common.util.InvokerUtils; import org.eclipse.jetty.websocket.javax.common.util.ReflectUtils; -import javax.websocket.CloseReason; -import javax.websocket.Decoder; -import javax.websocket.EndpointConfig; -import javax.websocket.OnClose; -import javax.websocket.OnError; -import javax.websocket.OnMessage; -import javax.websocket.OnOpen; -import javax.websocket.PongMessage; -import javax.websocket.Session; -import java.io.InputStream; -import java.io.Reader; -import java.lang.annotation.Annotation; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; - import static java.nio.charset.StandardCharsets.UTF_8; import static org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerMetadata.MessageMetadata; @@ -107,8 +108,9 @@ public abstract class JavaxWebSocketFrameHandlerFactory public abstract JavaxWebSocketFrameHandlerMetadata createMetadata(Class endpointClass, EndpointConfig endpointConfig); - public JavaxWebSocketFrameHandler newJavaxFrameHandler(Object endpointInstance, UpgradeRequest upgradeRequest, UpgradeResponse upgradeResponse, - CompletableFuture futureSession) + public JavaxWebSocketFrameHandler newJavaxWebSocketFrameHandler(Object endpointInstance, UpgradeRequest upgradeRequest, + UpgradeResponse upgradeResponse, + CompletableFuture futureSession) { Object endpoint; EndpointConfig config; diff --git a/jetty-websocket/javax-websocket-common/src/test/java/org/eclipse/jetty/websocket/javax/common/AbstractJavaxWebSocketFrameHandlerTest.java b/jetty-websocket/javax-websocket-common/src/test/java/org/eclipse/jetty/websocket/javax/common/AbstractJavaxWebSocketFrameHandlerTest.java index f847260c592..02a7b22bbf1 100644 --- a/jetty-websocket/javax-websocket-common/src/test/java/org/eclipse/jetty/websocket/javax/common/AbstractJavaxWebSocketFrameHandlerTest.java +++ b/jetty-websocket/javax-websocket-common/src/test/java/org/eclipse/jetty/websocket/javax/common/AbstractJavaxWebSocketFrameHandlerTest.java @@ -69,7 +69,7 @@ public abstract class AbstractJavaxWebSocketFrameHandlerTest UpgradeRequest upgradeRequest = new UpgradeRequestAdapter(); UpgradeResponse upgradeResponse = new UpgradeResponseAdapter(); - JavaxWebSocketFrameHandler localEndpoint = factory.newJavaxFrameHandler(endpoint, + JavaxWebSocketFrameHandler localEndpoint = factory.newJavaxWebSocketFrameHandler(endpoint, upgradeRequest, upgradeResponse, new CompletableFuture<>()); return localEndpoint; diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerFrameHandlerFactory.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerFrameHandlerFactory.java index 71e68d39efa..12d7746ae20 100644 --- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerFrameHandlerFactory.java +++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/JavaxWebSocketServerFrameHandlerFactory.java @@ -18,23 +18,24 @@ package org.eclipse.jetty.websocket.javax.server; -import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec; -import org.eclipse.jetty.websocket.core.FrameHandler; -import org.eclipse.jetty.websocket.javax.server.internal.PathParamIdentifier; -import org.eclipse.jetty.websocket.javax.server.internal.UpgradeRequestAdapter; -import org.eclipse.jetty.websocket.javax.server.internal.UpgradeResponseAdapter; -import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketContainer; -import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory; -import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerMetadata; -import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; -import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse; -import org.eclipse.jetty.websocket.servlet.FrameHandlerFactory; +import java.util.concurrent.CompletableFuture; import javax.websocket.Endpoint; import javax.websocket.EndpointConfig; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; -import java.util.concurrent.CompletableFuture; + +import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec; +import org.eclipse.jetty.websocket.core.FrameHandler; +import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketContainer; +import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory; +import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerMetadata; +import org.eclipse.jetty.websocket.javax.server.internal.DelegatedJavaxServletUpgradeRequest; +import org.eclipse.jetty.websocket.javax.server.internal.PathParamIdentifier; +import org.eclipse.jetty.websocket.javax.server.internal.UpgradeResponseAdapter; +import org.eclipse.jetty.websocket.servlet.FrameHandlerFactory; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse; public class JavaxWebSocketServerFrameHandlerFactory extends JavaxWebSocketFrameHandlerFactory implements FrameHandlerFactory { @@ -68,6 +69,6 @@ public class JavaxWebSocketServerFrameHandlerFactory extends JavaxWebSocketFrame public FrameHandler newFrameHandler(Object websocketPojo, ServletUpgradeRequest upgradeRequest, ServletUpgradeResponse upgradeResponse) { CompletableFuture completableFuture = new CompletableFuture<>(); - return newJavaxFrameHandler(websocketPojo, new UpgradeRequestAdapter(upgradeRequest), new UpgradeResponseAdapter(upgradeResponse), completableFuture); + return newJavaxWebSocketFrameHandler(websocketPojo, new DelegatedJavaxServletUpgradeRequest(upgradeRequest), new UpgradeResponseAdapter(upgradeResponse), completableFuture); } } diff --git a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/UpgradeRequestAdapter.java b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/DelegatedJavaxServletUpgradeRequest.java similarity index 89% rename from jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/UpgradeRequestAdapter.java rename to jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/DelegatedJavaxServletUpgradeRequest.java index ffafa7b4973..c6a2eccde05 100644 --- a/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/UpgradeRequestAdapter.java +++ b/jetty-websocket/javax-websocket-server/src/main/java/org/eclipse/jetty/websocket/javax/server/internal/DelegatedJavaxServletUpgradeRequest.java @@ -18,17 +18,17 @@ package org.eclipse.jetty.websocket.javax.server.internal; -import org.eclipse.jetty.websocket.javax.common.UpgradeRequest; -import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; - import java.net.URI; import java.security.Principal; -public class UpgradeRequestAdapter implements UpgradeRequest +import org.eclipse.jetty.websocket.javax.common.UpgradeRequest; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; + +public class DelegatedJavaxServletUpgradeRequest implements UpgradeRequest { private final ServletUpgradeRequest servletRequest; - public UpgradeRequestAdapter(ServletUpgradeRequest servletRequest) + public DelegatedJavaxServletUpgradeRequest(ServletUpgradeRequest servletRequest) { this.servletRequest = servletRequest; } diff --git a/jetty-websocket/javax-websocket-tests/src/main/java/org/eclipse/jetty/websocket/javax/tests/NetworkFuzzer.java b/jetty-websocket/javax-websocket-tests/src/main/java/org/eclipse/jetty/websocket/javax/tests/NetworkFuzzer.java index 5238b8882c2..6d9061280f2 100644 --- a/jetty-websocket/javax-websocket-tests/src/main/java/org/eclipse/jetty/websocket/javax/tests/NetworkFuzzer.java +++ b/jetty-websocket/javax-websocket-tests/src/main/java/org/eclipse/jetty/websocket/javax/tests/NetworkFuzzer.java @@ -38,7 +38,7 @@ import org.eclipse.jetty.websocket.core.Behavior; import org.eclipse.jetty.websocket.core.CloseStatus; import org.eclipse.jetty.websocket.core.Frame; import org.eclipse.jetty.websocket.core.FrameHandler; -import org.eclipse.jetty.websocket.core.client.UpgradeRequest; +import org.eclipse.jetty.websocket.core.client.ClientUpgradeRequest; import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient; import org.eclipse.jetty.websocket.core.internal.Generator; @@ -184,7 +184,7 @@ public class NetworkFuzzer extends Fuzzer.Adapter implements Fuzzer, AutoCloseab } } - public static class RawUpgradeRequest extends UpgradeRequest + public static class RawUpgradeRequest extends ClientUpgradeRequest { private final CompletableFuture futureCapture; private EndPoint endPoint; diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/client/SessionAddMessageHandlerTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/client/SessionAddMessageHandlerTest.java index c2344a5e270..ebee871ac30 100644 --- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/client/SessionAddMessageHandlerTest.java +++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/client/SessionAddMessageHandlerTest.java @@ -84,7 +84,7 @@ public class SessionAddMessageHandlerTest JavaxWebSocketFrameHandlerFactory frameHandlerFactory = new JavaxWebSocketClientFrameHandlerFactory(container); CompletableFuture futureSession = new CompletableFuture<>(); - frameHandler = frameHandlerFactory.newJavaxFrameHandler(ei, handshakeRequest, handshakeResponse, futureSession); + frameHandler = frameHandlerFactory.newJavaxWebSocketFrameHandler(ei, handshakeRequest, handshakeResponse, futureSession); frameHandler.onOpen(new FrameHandler.CoreSession.Empty(), Callback.NOOP); // Session diff --git a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/ConfiguratorTest.java b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/ConfiguratorTest.java index 3be59d1e298..9dae9ac822d 100644 --- a/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/ConfiguratorTest.java +++ b/jetty-websocket/javax-websocket-tests/src/test/java/org/eclipse/jetty/websocket/javax/tests/server/ConfiguratorTest.java @@ -18,37 +18,6 @@ package org.eclipse.jetty.websocket.javax.tests.server; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.core.Frame; -import org.eclipse.jetty.websocket.core.FrameHandler; -import org.eclipse.jetty.websocket.core.OpCode; -import org.eclipse.jetty.websocket.core.client.UpgradeRequest; -import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient; -import org.eclipse.jetty.websocket.javax.server.internal.JavaxWebSocketCreator; -import org.eclipse.jetty.websocket.javax.tests.LocalServer; -import org.eclipse.jetty.websocket.javax.tests.Timeouts; -import org.eclipse.jetty.websocket.javax.tests.framehandlers.FrameHandlerTracker; -import org.hamcrest.Matcher; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import javax.websocket.DecodeException; -import javax.websocket.Decoder; -import javax.websocket.EndpointConfig; -import javax.websocket.Extension; -import javax.websocket.HandshakeResponse; -import javax.websocket.OnMessage; -import javax.websocket.Session; -import javax.websocket.server.HandshakeRequest; -import javax.websocket.server.ServerContainer; -import javax.websocket.server.ServerEndpoint; -import javax.websocket.server.ServerEndpointConfig; import java.io.PrintWriter; import java.io.StringWriter; import java.net.InetSocketAddress; @@ -69,6 +38,38 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; +import javax.websocket.DecodeException; +import javax.websocket.Decoder; +import javax.websocket.EndpointConfig; +import javax.websocket.Extension; +import javax.websocket.HandshakeResponse; +import javax.websocket.OnMessage; +import javax.websocket.Session; +import javax.websocket.server.HandshakeRequest; +import javax.websocket.server.ServerContainer; +import javax.websocket.server.ServerEndpoint; +import javax.websocket.server.ServerEndpointConfig; + +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.websocket.core.Frame; +import org.eclipse.jetty.websocket.core.FrameHandler; +import org.eclipse.jetty.websocket.core.OpCode; +import org.eclipse.jetty.websocket.core.client.ClientUpgradeRequest; +import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient; +import org.eclipse.jetty.websocket.javax.server.internal.JavaxWebSocketCreator; +import org.eclipse.jetty.websocket.javax.tests.LocalServer; +import org.eclipse.jetty.websocket.javax.tests.Timeouts; +import org.eclipse.jetty.websocket.javax.tests.framehandlers.FrameHandlerTracker; +import org.hamcrest.Matcher; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; @@ -430,7 +431,7 @@ public class ConfiguratorTest URI wsUri = server.getWsUri().resolve("/capture-request-headers"); FrameHandlerTracker clientSocket = new FrameHandlerTracker(); - UpgradeRequest upgradeRequest = UpgradeRequest.from(client, wsUri, clientSocket); + ClientUpgradeRequest upgradeRequest = ClientUpgradeRequest.from(client, wsUri, clientSocket); upgradeRequest.addExtensions("identity"); Future clientConnectFuture = client.connect(upgradeRequest); @@ -454,7 +455,7 @@ public class ConfiguratorTest URI wsUri = server.getWsUri().resolve("/no-extensions"); FrameHandlerTracker clientSocket = new FrameHandlerTracker(); - UpgradeRequest upgradeRequest = UpgradeRequest.from(client, wsUri, clientSocket); + ClientUpgradeRequest upgradeRequest = ClientUpgradeRequest.from(client, wsUri, clientSocket); upgradeRequest.addExtensions("identity"); Future clientConnectFuture = client.connect(upgradeRequest); @@ -478,7 +479,7 @@ public class ConfiguratorTest URI wsUri = server.getWsUri().resolve("/capture-request-headers"); FrameHandlerTracker clientSocket = new FrameHandlerTracker(); - UpgradeRequest upgradeRequest = UpgradeRequest.from(client, wsUri, clientSocket); + ClientUpgradeRequest upgradeRequest = ClientUpgradeRequest.from(client, wsUri, clientSocket); upgradeRequest.header("X-Dummy", "Bogus"); Future clientConnectFuture = client.connect(upgradeRequest); @@ -503,7 +504,7 @@ public class ConfiguratorTest // First Request FrameHandlerTracker clientSocket = new FrameHandlerTracker(); - UpgradeRequest upgradeRequest = UpgradeRequest.from(client, wsUri, clientSocket); + ClientUpgradeRequest upgradeRequest = ClientUpgradeRequest.from(client, wsUri, clientSocket); Future clientConnectFuture = client.connect(upgradeRequest); FrameHandler.CoreSession channel = clientConnectFuture.get(Timeouts.CONNECT_MS, TimeUnit.MILLISECONDS); @@ -522,7 +523,7 @@ public class ConfiguratorTest // Second request clientSocket = new FrameHandlerTracker(); - upgradeRequest = UpgradeRequest.from(client, wsUri, clientSocket); + upgradeRequest = ClientUpgradeRequest.from(client, wsUri, clientSocket); clientConnectFuture = client.connect(upgradeRequest); channel = clientConnectFuture.get(Timeouts.CONNECT_MS, TimeUnit.MILLISECONDS); @@ -550,7 +551,7 @@ public class ConfiguratorTest URI wsUri = server.getWsUri().resolve("/addr"); FrameHandlerTracker clientSocket = new FrameHandlerTracker(); - UpgradeRequest upgradeRequest = UpgradeRequest.from(client, wsUri, clientSocket); + ClientUpgradeRequest upgradeRequest = ClientUpgradeRequest.from(client, wsUri, clientSocket); Future clientConnectFuture = client.connect(upgradeRequest); FrameHandler.CoreSession channel = clientConnectFuture.get(Timeouts.CONNECT_MS, TimeUnit.MILLISECONDS); @@ -591,7 +592,7 @@ public class ConfiguratorTest ProtocolsConfigurator.seenProtocols.set(null); FrameHandlerTracker clientSocket = new FrameHandlerTracker(); - UpgradeRequest upgradeRequest = UpgradeRequest.from(client, wsUri, clientSocket); + ClientUpgradeRequest upgradeRequest = ClientUpgradeRequest.from(client, wsUri, clientSocket); upgradeRequest.setSubProtocols("status"); Future clientConnectFuture = client.connect(upgradeRequest); @@ -610,7 +611,7 @@ public class ConfiguratorTest ProtocolsConfigurator.seenProtocols.set(null); FrameHandlerTracker clientSocket = new FrameHandlerTracker(); - UpgradeRequest upgradeRequest = UpgradeRequest.from(client, wsUri, clientSocket); + ClientUpgradeRequest upgradeRequest = ClientUpgradeRequest.from(client, wsUri, clientSocket); upgradeRequest.setSubProtocols("echo", "chat", "status"); Future clientConnectFuture = client.connect(upgradeRequest); @@ -629,7 +630,7 @@ public class ConfiguratorTest ProtocolsConfigurator.seenProtocols.set(null); FrameHandlerTracker clientSocket = new FrameHandlerTracker(); - UpgradeRequest upgradeRequest = UpgradeRequest.from(client, wsUri, clientSocket); + ClientUpgradeRequest upgradeRequest = ClientUpgradeRequest.from(client, wsUri, clientSocket); upgradeRequest.header("sec-websocket-protocol", "echo, chat, status"); Future clientConnectFuture = client.connect(upgradeRequest); @@ -648,7 +649,7 @@ public class ConfiguratorTest ProtocolsConfigurator.seenProtocols.set(null); FrameHandlerTracker clientSocket = new FrameHandlerTracker(); - UpgradeRequest upgradeRequest = UpgradeRequest.from(client, wsUri, clientSocket); + ClientUpgradeRequest upgradeRequest = ClientUpgradeRequest.from(client, wsUri, clientSocket); // header name is not to spec (case wise) upgradeRequest.header("Sec-Websocket-Protocol", "echo, chat, status"); Future clientConnectFuture = client.connect(upgradeRequest); @@ -682,7 +683,7 @@ public class ConfiguratorTest URI wsUri = server.getWsUri().resolve("/timedecoder"); FrameHandlerTracker clientSocket = new FrameHandlerTracker(); - UpgradeRequest upgradeRequest = UpgradeRequest.from(client, wsUri, clientSocket); + ClientUpgradeRequest upgradeRequest = ClientUpgradeRequest.from(client, wsUri, clientSocket); upgradeRequest.setSubProtocols("gmt"); Future clientConnectFuture = client.connect(upgradeRequest); diff --git a/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java b/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java index a9267c39c13..8d6b0f66841 100644 --- a/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java +++ b/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java @@ -40,7 +40,7 @@ import org.eclipse.jetty.websocket.api.UpgradeRequest; import org.eclipse.jetty.websocket.api.UpgradeResponse; import org.eclipse.jetty.websocket.api.WebSocketBehavior; import org.eclipse.jetty.websocket.api.WebSocketPolicy; -import org.eclipse.jetty.websocket.client.impl.ClientUpgradeRequestImpl; +import org.eclipse.jetty.websocket.client.impl.JettyClientUpgradeRequest; import org.eclipse.jetty.websocket.common.JettyWebSocketFrameHandler; import org.eclipse.jetty.websocket.common.JettyWebSocketFrameHandlerFactory; import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry; @@ -107,7 +107,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketPoli */ public CompletableFuture connect(Object websocket, URI toUri, UpgradeRequest request) throws IOException { - ClientUpgradeRequestImpl upgradeRequest = new ClientUpgradeRequestImpl(this, coreClient, request, toUri, websocket); + JettyClientUpgradeRequest upgradeRequest = new JettyClientUpgradeRequest(this, coreClient, request, toUri, websocket); coreClient.connect(upgradeRequest); return upgradeRequest.getFutureSession(); } diff --git a/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/DelegatedClientUpgradeRequest.java b/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/DelegatedJettyClientUpgradeRequest.java similarity index 95% rename from jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/DelegatedClientUpgradeRequest.java rename to jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/DelegatedJettyClientUpgradeRequest.java index 5c18b6a9f36..9df6187f8ae 100644 --- a/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/DelegatedClientUpgradeRequest.java +++ b/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/DelegatedJettyClientUpgradeRequest.java @@ -18,14 +18,6 @@ package org.eclipse.jetty.websocket.client.impl; -import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.util.MultiMap; -import org.eclipse.jetty.util.UrlEncoded; -import org.eclipse.jetty.websocket.api.UpgradeRequest; -import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; - import java.net.HttpCookie; import java.net.SocketAddress; import java.net.URI; @@ -35,19 +27,28 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.util.MultiMap; +import org.eclipse.jetty.util.UrlEncoded; +import org.eclipse.jetty.websocket.api.UpgradeRequest; +import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; +import org.eclipse.jetty.websocket.core.client.ClientUpgradeRequest; + import static java.nio.charset.StandardCharsets.UTF_8; /** * Representing the Jetty {@link org.eclipse.jetty.client.HttpClient}'s {@link org.eclipse.jetty.client.HttpRequest} * in the {@link UpgradeRequest} interface. */ -public class DelegatedClientUpgradeRequest implements UpgradeRequest +public class DelegatedJettyClientUpgradeRequest implements UpgradeRequest { - private final org.eclipse.jetty.websocket.core.client.UpgradeRequest delegate; + private final ClientUpgradeRequest delegate; private SocketAddress localSocketAddress; private SocketAddress remoteSocketAddress; - public DelegatedClientUpgradeRequest(org.eclipse.jetty.websocket.core.client.UpgradeRequest delegate) + public DelegatedJettyClientUpgradeRequest(ClientUpgradeRequest delegate) { this.delegate = delegate; } diff --git a/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/DelegatedClientUpgradeResponse.java b/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/DelegatedJettyClientUpgradeResponse.java similarity index 95% rename from jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/DelegatedClientUpgradeResponse.java rename to jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/DelegatedJettyClientUpgradeResponse.java index 6fd75b00d5e..44bc2a3563d 100644 --- a/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/DelegatedClientUpgradeResponse.java +++ b/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/DelegatedJettyClientUpgradeResponse.java @@ -18,11 +18,6 @@ package org.eclipse.jetty.websocket.client.impl; -import org.eclipse.jetty.client.HttpResponse; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.websocket.api.UpgradeResponse; -import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; - import java.io.IOException; import java.util.Collections; import java.util.List; @@ -30,15 +25,20 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.eclipse.jetty.client.HttpResponse; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.websocket.api.UpgradeResponse; +import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; + /** * Representing the Jetty {@link org.eclipse.jetty.client.HttpClient}'s {@link org.eclipse.jetty.client.HttpResponse} * in the {@link UpgradeResponse} interface. */ -public class DelegatedClientUpgradeResponse implements UpgradeResponse +public class DelegatedJettyClientUpgradeResponse implements UpgradeResponse { private HttpResponse delegate; - public DelegatedClientUpgradeResponse(HttpResponse response) + public DelegatedJettyClientUpgradeResponse(HttpResponse response) { this.delegate = response; } diff --git a/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/ClientUpgradeRequestImpl.java b/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/JettyClientUpgradeRequest.java similarity index 80% rename from jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/ClientUpgradeRequestImpl.java rename to jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/JettyClientUpgradeRequest.java index 9e7e98d8834..de112f4d05a 100644 --- a/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/ClientUpgradeRequestImpl.java +++ b/jetty-websocket/jetty-websocket-client/src/main/java/org/eclipse/jetty/websocket/client/impl/JettyClientUpgradeRequest.java @@ -18,41 +18,39 @@ package org.eclipse.jetty.websocket.client.impl; +import java.net.HttpCookie; +import java.net.URI; +import java.util.List; +import java.util.concurrent.CompletableFuture; + import org.eclipse.jetty.client.HttpResponse; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.api.UpgradeRequest; import org.eclipse.jetty.websocket.api.UpgradeResponse; import org.eclipse.jetty.websocket.client.WebSocketClient; import org.eclipse.jetty.websocket.common.JettyWebSocketFrameHandler; import org.eclipse.jetty.websocket.core.FrameHandler; -import org.eclipse.jetty.websocket.core.client.UpgradeRequest; +import org.eclipse.jetty.websocket.core.client.ClientUpgradeRequest; import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient; -import java.net.HttpCookie; -import java.net.URI; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -public class ClientUpgradeRequestImpl extends UpgradeRequest +public class JettyClientUpgradeRequest extends ClientUpgradeRequest { private final WebSocketClient containerContext; private final Object websocketPojo; - private final CompletableFuture onOpenFuture; private final CompletableFuture futureSession; - private final DelegatedClientUpgradeRequest handshakeRequest; + private final DelegatedJettyClientUpgradeRequest handshakeRequest; - public ClientUpgradeRequestImpl(WebSocketClient clientContainer, WebSocketCoreClient coreClient, org.eclipse.jetty.websocket.api.UpgradeRequest request, - URI requestURI, Object websocketPojo) + public JettyClientUpgradeRequest(WebSocketClient clientContainer, WebSocketCoreClient coreClient, UpgradeRequest request, + URI requestURI, Object websocketPojo) { super(coreClient, requestURI); this.containerContext = clientContainer; this.websocketPojo = websocketPojo; - - this.onOpenFuture = new CompletableFuture<>(); - this.futureSession = super.futureCoreSession.thenCombine(onOpenFuture, (channel, session) -> session); + this.futureSession = new CompletableFuture<>(); if (request != null) { @@ -89,7 +87,7 @@ public class ClientUpgradeRequestImpl extends UpgradeRequest version(HttpVersion.fromString(request.getHttpVersion())); } - handshakeRequest = new DelegatedClientUpgradeRequest(this); + handshakeRequest = new DelegatedJettyClientUpgradeRequest(this); } @Override @@ -102,16 +100,16 @@ public class ClientUpgradeRequestImpl extends UpgradeRequest protected void handleException(Throwable failure) { super.handleException(failure); - onOpenFuture.completeExceptionally(failure); + futureSession.completeExceptionally(failure); } @Override public FrameHandler getFrameHandler(WebSocketCoreClient coreClient, HttpResponse response) { - UpgradeResponse upgradeResponse = new DelegatedClientUpgradeResponse(response); + UpgradeResponse upgradeResponse = new DelegatedJettyClientUpgradeResponse(response); JettyWebSocketFrameHandler frameHandler = containerContext.newFrameHandler(websocketPojo, - handshakeRequest, upgradeResponse, onOpenFuture); + handshakeRequest, upgradeResponse, futureSession); return frameHandler; } diff --git a/jetty-websocket/jetty-websocket-common/src/main/java/org/eclipse/jetty/websocket/common/JettyWebSocketFrameHandler.java b/jetty-websocket/jetty-websocket-common/src/main/java/org/eclipse/jetty/websocket/common/JettyWebSocketFrameHandler.java index 91d8a1d2485..a1a3e224e0f 100644 --- a/jetty-websocket/jetty-websocket-common/src/main/java/org/eclipse/jetty/websocket/common/JettyWebSocketFrameHandler.java +++ b/jetty-websocket/jetty-websocket-common/src/main/java/org/eclipse/jetty/websocket/common/JettyWebSocketFrameHandler.java @@ -141,13 +141,13 @@ public class JettyWebSocketFrameHandler implements FrameHandler if (openHandle != null) openHandle.invoke(); - futureSession.complete(session); callback.succeeded(); + futureSession.complete(session); } catch (Throwable cause) { - // TODO should futureSession be failed here? callback.failed(new WebSocketException(endpointInstance.getClass().getName() + " OPEN method error: " + cause.getMessage(), cause)); + futureSession.completeExceptionally(cause); } } @@ -236,7 +236,10 @@ public class JettyWebSocketFrameHandler implements FrameHandler { // No message sink is active if (activeMessageSink == null) + { + callback.succeeded(); return; + } // Accept the payload into the message sink activeMessageSink.accept(frame, callback); diff --git a/jetty-websocket/jetty-websocket-common/src/main/java/org/eclipse/jetty/websocket/common/JettyWebSocketFrameHandlerFactory.java b/jetty-websocket/jetty-websocket-common/src/main/java/org/eclipse/jetty/websocket/common/JettyWebSocketFrameHandlerFactory.java index e1f26a58bd0..a06d5fce560 100644 --- a/jetty-websocket/jetty-websocket-common/src/main/java/org/eclipse/jetty/websocket/common/JettyWebSocketFrameHandlerFactory.java +++ b/jetty-websocket/jetty-websocket-common/src/main/java/org/eclipse/jetty/websocket/common/JettyWebSocketFrameHandlerFactory.java @@ -61,7 +61,6 @@ import org.eclipse.jetty.websocket.common.message.PartialTextMessageSink; import org.eclipse.jetty.websocket.common.message.ReaderMessageSink; import org.eclipse.jetty.websocket.common.message.StringMessageSink; import org.eclipse.jetty.websocket.common.util.ReflectUtils; -import org.eclipse.jetty.websocket.core.Frame; /** * Factory to create {@link JettyWebSocketFrameHandler} instances suitable for @@ -351,7 +350,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle { assertSignatureValid(endpointClass, onmethod, OnWebSocketFrame.class); final InvokerUtils.Arg SESSION = new InvokerUtils.Arg(Session.class); - final InvokerUtils.Arg FRAME = new InvokerUtils.Arg(Frame.class).required(); + final InvokerUtils.Arg FRAME = new InvokerUtils.Arg(org.eclipse.jetty.websocket.api.extensions.Frame.class).required(); MethodHandle methodHandle = InvokerUtils.mutatedInvoker(endpointClass, onmethod, SESSION, FRAME); metadata.setFrameHandler(methodHandle, onmethod); } diff --git a/jetty-websocket/jetty-websocket-common/src/test/java/org/eclipse/jetty/websocket/common/endpoints/annotated/FrameSocket.java b/jetty-websocket/jetty-websocket-common/src/test/java/org/eclipse/jetty/websocket/common/endpoints/annotated/FrameSocket.java index 90687dd21c6..3d7e97ed992 100644 --- a/jetty-websocket/jetty-websocket-common/src/test/java/org/eclipse/jetty/websocket/common/endpoints/annotated/FrameSocket.java +++ b/jetty-websocket/jetty-websocket-common/src/test/java/org/eclipse/jetty/websocket/common/endpoints/annotated/FrameSocket.java @@ -20,7 +20,7 @@ package org.eclipse.jetty.websocket.common.endpoints.annotated; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame; import org.eclipse.jetty.websocket.api.annotations.WebSocket; -import org.eclipse.jetty.websocket.core.Frame; +import org.eclipse.jetty.websocket.api.extensions.Frame; @WebSocket public class FrameSocket diff --git a/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyServerFrameHandlerFactory.java b/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyServerFrameHandlerFactory.java index 47bbd03d4e6..4c800db2389 100644 --- a/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyServerFrameHandlerFactory.java +++ b/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/JettyServerFrameHandlerFactory.java @@ -29,7 +29,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.websocket.common.JettyWebSocketFrameHandlerFactory; import org.eclipse.jetty.websocket.core.FrameHandler; -import org.eclipse.jetty.websocket.server.internal.UpgradeRequestAdapter; +import org.eclipse.jetty.websocket.server.internal.DelegatedJettyServletUpgradeRequest; import org.eclipse.jetty.websocket.server.internal.UpgradeResponseAdapter; import org.eclipse.jetty.websocket.servlet.FrameHandlerFactory; import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; @@ -67,7 +67,7 @@ public class JettyServerFrameHandlerFactory @Override public FrameHandler newFrameHandler(Object websocketPojo, ServletUpgradeRequest upgradeRequest, ServletUpgradeResponse upgradeResponse) { - return super.newJettyFrameHandler(websocketPojo, new UpgradeRequestAdapter(upgradeRequest), new UpgradeResponseAdapter(upgradeResponse), + return super.newJettyFrameHandler(websocketPojo, new DelegatedJettyServletUpgradeRequest(upgradeRequest), new UpgradeResponseAdapter(upgradeResponse), new CompletableFuture<>()); } diff --git a/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/internal/UpgradeRequestAdapter.java b/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/internal/DelegatedJettyServletUpgradeRequest.java similarity index 97% rename from jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/internal/UpgradeRequestAdapter.java rename to jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/internal/DelegatedJettyServletUpgradeRequest.java index b7e74c93cf7..b2d17f0873a 100644 --- a/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/internal/UpgradeRequestAdapter.java +++ b/jetty-websocket/jetty-websocket-server/src/main/java/org/eclipse/jetty/websocket/server/internal/DelegatedJettyServletUpgradeRequest.java @@ -18,10 +18,6 @@ package org.eclipse.jetty.websocket.server.internal; -import org.eclipse.jetty.websocket.api.UpgradeRequest; -import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; -import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; - import java.net.HttpCookie; import java.net.URI; import java.security.Principal; @@ -29,11 +25,15 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -public class UpgradeRequestAdapter implements UpgradeRequest +import org.eclipse.jetty.websocket.api.UpgradeRequest; +import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; +import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest; + +public class DelegatedJettyServletUpgradeRequest implements UpgradeRequest { private final ServletUpgradeRequest servletRequest; - public UpgradeRequestAdapter(ServletUpgradeRequest servletRequest) + public DelegatedJettyServletUpgradeRequest(ServletUpgradeRequest servletRequest) { this.servletRequest = servletRequest; } diff --git a/jetty-websocket/jetty-websocket-tests/pom.xml b/jetty-websocket/jetty-websocket-tests/pom.xml index ed5b8ea0e61..1c0f7120e92 100644 --- a/jetty-websocket/jetty-websocket-tests/pom.xml +++ b/jetty-websocket/jetty-websocket-tests/pom.xml @@ -13,7 +13,7 @@ Jetty :: Websocket :: org.eclipse.jetty.websocket :: Tests - ${project.groupId}.jetty.tests + ${project.groupId}.jetty.websocket.tests @@ -32,6 +32,11 @@ jetty-websocket-server ${project.version} + + org.eclipse.jetty.tests + jetty-http-tools + ${project.version} + org.eclipse.jetty.toolchain jetty-test-helper @@ -42,27 +47,21 @@ - org.apache.maven.plugins - maven-enforcer-plugin + org.apache.felix + maven-bundle-plugin + true - ban-java-servlet-api - enforce + manifest - - - - javax.servlet - servletapi - org.eclipse.jetty.orbit:javax.servlet - org.mortbay.jetty:servlet-api - jetty:servlet-api - jetty-servlet-api - - - + + jetty.websocket Integration Tests + + org.eclipse.jetty.websocket.jetty.tests.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}" + + diff --git a/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebSocketTest.java similarity index 99% rename from jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java rename to jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebSocketTest.java index 42bbf1b10c1..9f3f69adca7 100644 --- a/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebsocketTest.java +++ b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebSocketTest.java @@ -40,7 +40,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertTrue; -public class JettyWebsocketTest +public class JettyWebSocketTest { @WebSocket diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/FrameHandler.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/FrameHandler.java index cb54e59fadb..ccb1136ee52 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/FrameHandler.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/FrameHandler.java @@ -27,7 +27,7 @@ import java.util.Map; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.websocket.core.client.UpgradeRequest; +import org.eclipse.jetty.websocket.core.client.ClientUpgradeRequest; import org.eclipse.jetty.websocket.core.server.Negotiation; /** @@ -42,8 +42,8 @@ import org.eclipse.jetty.websocket.core.server.Negotiation; *
  • On the server, the application layer must provide a {@link org.eclipse.jetty.websocket.core.server.WebSocketNegotiator} instance * to negotiate and accept websocket connections, which will return the FrameHandler instance to use from * {@link org.eclipse.jetty.websocket.core.server.WebSocketNegotiator#negotiate(Negotiation)}.
  • - *
  • On the client, the application returns the FrameHandler instance to user from the {@link UpgradeRequest} - * instance that it passes to the {@link org.eclipse.jetty.websocket.core.client.WebSocketCoreClient#connect(UpgradeRequest)} method/
  • + *
  • On the client, the application returns the FrameHandler instance to user from the {@link ClientUpgradeRequest} + * instance that it passes to the {@link org.eclipse.jetty.websocket.core.client.WebSocketCoreClient#connect(ClientUpgradeRequest)} method/
  • * *

    * Once instantiated the FrameHandler follows is used as follows: diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/UpgradeRequest.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/ClientUpgradeRequest.java similarity index 96% rename from jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/UpgradeRequest.java rename to jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/ClientUpgradeRequest.java index 183a6df6b88..42b0a485b55 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/UpgradeRequest.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/ClientUpgradeRequest.java @@ -64,11 +64,11 @@ import org.eclipse.jetty.websocket.core.internal.WebSocketChannel; import org.eclipse.jetty.websocket.core.internal.WebSocketConnection; import org.eclipse.jetty.websocket.core.internal.WebSocketCore; -public abstract class UpgradeRequest extends HttpRequest implements Response.CompleteListener, HttpConnectionUpgrader +public abstract class ClientUpgradeRequest extends HttpRequest implements Response.CompleteListener, HttpConnectionUpgrader { - public static UpgradeRequest from(WebSocketCoreClient webSocketClient, URI requestURI, FrameHandler frameHandler) + public static ClientUpgradeRequest from(WebSocketCoreClient webSocketClient, URI requestURI, FrameHandler frameHandler) { - return new UpgradeRequest(webSocketClient, requestURI) + return new ClientUpgradeRequest(webSocketClient, requestURI) { @Override public FrameHandler getFrameHandler(WebSocketCoreClient coreClient, HttpResponse response) @@ -78,7 +78,7 @@ public abstract class UpgradeRequest extends HttpRequest implements Response.Com }; } - private static final Logger LOG = Log.getLogger(UpgradeRequest.class); + private static final Logger LOG = Log.getLogger(ClientUpgradeRequest.class); protected final CompletableFuture futureCoreSession; private final WebSocketCoreClient wsClient; private List upgradeListeners = new ArrayList<>(); @@ -91,7 +91,7 @@ public abstract class UpgradeRequest extends HttpRequest implements Response.Com */ private List subProtocols = new ArrayList<>(); - public UpgradeRequest(WebSocketCoreClient webSocketClient, URI requestURI) + public ClientUpgradeRequest(WebSocketCoreClient webSocketClient, URI requestURI) { super(webSocketClient.getHttpClient(), new HttpConversation(), requestURI); @@ -347,11 +347,12 @@ public abstract class UpgradeRequest extends HttpRequest implements Response.Com try { endp.upgrade(wsConnection); - } - finally - { futureCoreSession.complete(wsChannel); } + catch (Throwable t) + { + futureCoreSession.completeExceptionally(t); + } } /** diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/WebSocketCoreClient.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/WebSocketCoreClient.java index 58fae3df9f2..3d247f3414f 100644 --- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/WebSocketCoreClient.java +++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/client/WebSocketCoreClient.java @@ -83,11 +83,11 @@ public class WebSocketCoreClient extends ContainerLifeCycle implements FrameHand public CompletableFuture connect(FrameHandler frameHandler, URI wsUri) throws IOException { - UpgradeRequest request = UpgradeRequest.from(this, wsUri, frameHandler); + ClientUpgradeRequest request = ClientUpgradeRequest.from(this, wsUri, frameHandler); return connect(request); } - public CompletableFuture connect(UpgradeRequest request) throws IOException + public CompletableFuture connect(ClientUpgradeRequest request) throws IOException { if (!isStarted()) { diff --git a/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/core/chat/ChatWebSocketClient.java b/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/core/chat/ChatWebSocketClient.java index ea0344a654f..565a481f4c6 100644 --- a/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/core/chat/ChatWebSocketClient.java +++ b/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/core/chat/ChatWebSocketClient.java @@ -18,13 +18,6 @@ package org.eclipse.jetty.websocket.core.chat; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.core.MessageHandler; -import org.eclipse.jetty.websocket.core.client.UpgradeRequest; -import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient; - import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URI; @@ -34,6 +27,13 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.websocket.core.MessageHandler; +import org.eclipse.jetty.websocket.core.client.ClientUpgradeRequest; +import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient; + public class ChatWebSocketClient { private static Logger LOG = Log.getLogger(ChatWebSocketClient.class); @@ -51,7 +51,7 @@ public class ChatWebSocketClient URI wsUri = baseWebsocketUri.resolve("/chat"); handler = MessageHandler.from(this::onText, null); - UpgradeRequest request = UpgradeRequest.from(client, wsUri, handler); + ClientUpgradeRequest request = ClientUpgradeRequest.from(client, wsUri, handler); request.setSubProtocols("chat"); client.connect(request).get(5, TimeUnit.SECONDS); handler.sendText("[" + name + ": has joined the room]", Callback.NOOP, false); diff --git a/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/core/client/WebSocketClientServerTest.java b/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/core/client/WebSocketClientServerTest.java index bf642358376..46fd2210de9 100644 --- a/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/core/client/WebSocketClientServerTest.java +++ b/jetty-websocket/websocket-core/src/test/java/org/eclipse/jetty/websocket/core/client/WebSocketClientServerTest.java @@ -179,7 +179,7 @@ public class WebSocketClientServerTest public void start() throws Exception { - UpgradeRequest request = UpgradeRequest.from(client, baseWebSocketUri.resolve("/test"), handler); + ClientUpgradeRequest request = ClientUpgradeRequest.from(client, baseWebSocketUri.resolve("/test"), handler); request.setSubProtocols("test"); this.client.start(); Future response = client.connect(request);