diff --git a/java/org/apache/tomcat/util/compat/Jre8Compat.java b/java/org/apache/tomcat/util/compat/Jre8Compat.java index 08da1578feb0..301c8d9ac0be 100644 --- a/java/org/apache/tomcat/util/compat/Jre8Compat.java +++ b/java/org/apache/tomcat/util/compat/Jre8Compat.java @@ -27,16 +27,19 @@ class Jre8Compat extends Jre7Compat { private static final Method getSSLParametersMethod; private static final Method setUseCipherSuitesOrderMethod; + private static final Method setSSLParametersMethod; static { Method m1 = null; Method m2 = null; + Method m3 = null; try { // Get this class first since it is Java 8+ only Class c2 = Class.forName("javax.net.ssl.SSLParameters"); m1 = SSLServerSocket.class.getMethod("getSSLParameters"); m2 = c2.getMethod("setUseCipherSuitesOrder", boolean.class); + m3 = SSLServerSocket.class.getMethod("setSSLParameters", c2); } catch (SecurityException e) { // Should never happen } catch (NoSuchMethodException e) { @@ -46,6 +49,7 @@ class Jre8Compat extends Jre7Compat { } getSSLParametersMethod = m1; setUseCipherSuitesOrderMethod = m2; + setSSLParametersMethod = m3; } @@ -61,6 +65,7 @@ public void setUseServerCipherSuitesOrder(SSLServerSocket socket, Object sslParameters = getSSLParametersMethod.invoke(socket); setUseCipherSuitesOrderMethod.invoke( sslParameters, Boolean.valueOf(useCipherSuitesOrder)); + setSSLParametersMethod.invoke(socket, sslParameters); return; } catch (IllegalArgumentException e) { throw new UnsupportedOperationException(e); @@ -78,6 +83,7 @@ public void setUseServerCipherSuitesOrder(SSLEngine engine, SSLParameters sslParameters = engine.getSSLParameters(); try { setUseCipherSuitesOrderMethod.invoke(sslParameters, Boolean.valueOf(useCipherSuitesOrder)); + engine.setSSLParameters(sslParameters); } catch (IllegalArgumentException e) { throw new UnsupportedOperationException(e); } catch (IllegalAccessException e) { diff --git a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java index 6620859af141..77d2362b54c9 100644 --- a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java +++ b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java @@ -522,7 +522,10 @@ private ByteBuffer createRequest(URI uri, // Request line result.put("GET ".getBytes(StandardCharsets.ISO_8859_1)); - result.put(uri.getRawPath().getBytes(StandardCharsets.ISO_8859_1)); + byte[] path = (null == uri.getPath() || "".equals(uri.getPath())) + ? "/".getBytes(StandardCharsets.ISO_8859_1) + : uri.getRawPath().getBytes(StandardCharsets.ISO_8859_1); + result.put(path); String query = uri.getRawQuery(); if (query != null) { result.put((byte) '?'); diff --git a/test/org/apache/tomcat/websocket/TestWebSocketFrameClient.java b/test/org/apache/tomcat/websocket/TestWebSocketFrameClient.java index 40b7ed06c0a1..c188775fd16d 100644 --- a/test/org/apache/tomcat/websocket/TestWebSocketFrameClient.java +++ b/test/org/apache/tomcat/websocket/TestWebSocketFrameClient.java @@ -80,4 +80,57 @@ public void testConnectToServerEndpoint() throws Exception { Assert.assertEquals(TesterFirehoseServer.MESSAGE, message); } } + @Test + public void testConnectToRootEndpoint() throws Exception { + + Tomcat tomcat = getTomcatInstance(); + // No file system docBase required + Context ctx = + tomcat.addContext("", System.getProperty("java.io.tmpdir")); + ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); + Context ctx2 = + tomcat.addContext("/foo", System.getProperty("java.io.tmpdir")); + ctx2.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx2, "default", new DefaultServlet()); + ctx2.addServletMapping("/", "default"); + + tomcat.start(); + + echoTester(""); + echoTester("/"); + // FIXME: The ws client doesn't handle any response other than the upgrade, + // which may or may not be allowed. In that case, the server will return + // a redirect to the root of the webapp to avoid possible broken relative + // paths. + // echoTester("/foo"); + echoTester("/foo/"); + } + + public void echoTester(String path) throws Exception { + WebSocketContainer wsContainer = + ContainerProvider.getWebSocketContainer(); + ClientEndpointConfig clientEndpointConfig = + ClientEndpointConfig.Builder.create().build(); + Session wsSession = wsContainer.connectToServer( + TesterProgrammaticEndpoint.class, + clientEndpointConfig, + new URI("ws://localhost:" + getPort() + path)); + CountDownLatch latch = + new CountDownLatch(1); + BasicText handler = new BasicText(latch); + wsSession.addMessageHandler(handler); + wsSession.getBasicRemote().sendText("Hello"); + + handler.getLatch().await(100, TimeUnit.MILLISECONDS); + + Queue messages = handler.getMessages(); + Assert.assertEquals(1, messages.size()); + for (String message : messages) { + Assert.assertEquals("Hello", message); + } + wsSession.close(); + } + } diff --git a/test/org/apache/tomcat/websocket/TesterEchoServer.java b/test/org/apache/tomcat/websocket/TesterEchoServer.java index 406d3a886780..e8126e8b4bcf 100644 --- a/test/org/apache/tomcat/websocket/TesterEchoServer.java +++ b/test/org/apache/tomcat/websocket/TesterEchoServer.java @@ -49,6 +49,7 @@ public void contextInitialized(ServletContextEvent sce) { sc.addEndpoint(Basic.class); sc.addEndpoint(BasicLimitLow.class); sc.addEndpoint(BasicLimitHigh.class); + sc.addEndpoint(RootEcho.class); } catch (DeploymentException e) { throw new IllegalStateException(e); } @@ -186,4 +187,21 @@ public void echoBinaryMessage(Session session, ByteBuffer msg) { } } + + @ServerEndpoint("/") + public static class RootEcho { + + @OnMessage + public void echoTextMessage(Session session, @SuppressWarnings("unused") String msg) { + try { + session.getBasicRemote().sendText(msg); + } catch (IOException e) { + try { + session.close(); + } catch (IOException e1) { + // Ignore + } + } + } + } } diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 87da1cd9c4e5..7e7ce09baee3 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -59,8 +59,18 @@ - Correct the check used for Java 8 JSSE server-preferred TLS cipher - suite ordering. Patch provided by Ognjen Blagojevic. (violetagg) + 55988: Correct the check used for Java 8 JSSE + server-preferred TLS cipher suite ordering. Ensure that SSL parameters + are provided to SSLServerSocket and SSLEngine. + Patch provided by Ognjen Blagojevic. (violetagg) + + + + + + + 57761: Ensure that the opening HTTP request is correctly + formatted when the WebSocket client connects to a server root. (remm)