This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/11.0.x by this push:
new ba5f7e4f50 Include the Upgrade header field in WebSocket 426 responses
(#1116)
ba5f7e4f50 is described below
commit ba5f7e4f506665dd78950d2a7683fbf4f2dfe8c4
Author: Arturo Bernal <[email protected]>
AuthorDate: Thu Nov 5 20:56:14 2026 +0100
Include the Upgrade header field in WebSocket 426 responses (#1116)
RFC 9110, section 15.5.22 requires a 426 (Upgrade Required) response to
include an Upgrade header field naming the required protocol and section
7.8 requires the corresponding Connection option. The response sent when
the Sec-WebSocket-Version of the opening handshake is not supported only
included the Sec-WebSocket-Version header field so a client was not told
which protocol to use.
---
.../tomcat/websocket/server/UpgradeUtil.java | 4 ++
.../server/TestUpgradeRequiredResponse.java | 73 ++++++++++++++++++++++
2 files changed, 77 insertions(+)
diff --git a/java/org/apache/tomcat/websocket/server/UpgradeUtil.java
b/java/org/apache/tomcat/websocket/server/UpgradeUtil.java
index 925717ce7f..13522f01fd 100644
--- a/java/org/apache/tomcat/websocket/server/UpgradeUtil.java
+++ b/java/org/apache/tomcat/websocket/server/UpgradeUtil.java
@@ -124,6 +124,10 @@ public class UpgradeUtil {
String version = req.getHeader(Constants.WS_VERSION_HEADER_NAME);
if (version == null ||
!Constants.WS_VERSION_HEADER_VALUE.equals(version.trim())) {
resp.setStatus(HttpServletResponse.SC_UPGRADE_REQUIRED);
+ // RFC 9110, sections 7.8 and 15.5.22: a 426 response must include
the Upgrade header field and the
+ // associated Connection option
+ resp.setHeader(Constants.UPGRADE_HEADER_NAME,
Constants.UPGRADE_HEADER_VALUE);
+ resp.setHeader(Constants.CONNECTION_HEADER_NAME,
Constants.CONNECTION_HEADER_VALUE);
resp.setHeader(Constants.WS_VERSION_HEADER_NAME,
Constants.WS_VERSION_HEADER_VALUE);
return;
}
diff --git
a/test/org/apache/tomcat/websocket/server/TestUpgradeRequiredResponse.java
b/test/org/apache/tomcat/websocket/server/TestUpgradeRequiredResponse.java
new file mode 100644
index 0000000000..55dd9c8959
--- /dev/null
+++ b/test/org/apache/tomcat/websocket/server/TestUpgradeRequiredResponse.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.websocket.server;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.tomcat.websocket.TesterEchoServer;
+import org.apache.tomcat.websocket.WebSocketBaseTest;
+
+/**
+ * RFC 9110, sections 7.8 and 15.5.22: a 426 response must include an Upgrade
header field naming the required protocol
+ * and the corresponding Connection option. RFC 6455, section 4.4: it also
lists the supported WebSocket versions.
+ */
+public class TestUpgradeRequiredResponse extends WebSocketBaseTest {
+
+ @Test
+ public void testUnsupportedVersion() throws Exception {
+ startServer(TesterEchoServer.Config.class);
+
+ String request = "GET " + TesterEchoServer.Config.PATH_BASIC + "
HTTP/1.1\r\n" +
+ "Host: localhost:" + getPort() + "\r\n" +
+ "Upgrade: websocket\r\n" +
+ "Connection: upgrade\r\n" +
+ "Sec-WebSocket-Version: 8\r\n" +
+ "Sec-WebSocket-Key: MDEyMzQ1Njc4OTAxMjM0NQ==\r\n" +
+ "\r\n";
+
+ Map<String,String> headers = new HashMap<>();
+ int status;
+ try (Socket socket = new Socket("localhost", getPort())) {
+
socket.getOutputStream().write(request.getBytes(StandardCharsets.ISO_8859_1));
+ BufferedReader in = new BufferedReader(
+ new InputStreamReader(socket.getInputStream(),
StandardCharsets.ISO_8859_1));
+ status = Integer.parseInt(in.readLine().substring(9, 12));
+ String line = in.readLine();
+ while (line != null && !line.isEmpty()) {
+ int colon = line.indexOf(':');
+ headers.put(line.substring(0,
colon).toLowerCase(Locale.ENGLISH), line.substring(colon + 1).trim());
+ line = in.readLine();
+ }
+ }
+
+ Assert.assertEquals(HttpServletResponse.SC_UPGRADE_REQUIRED, status);
+ Assert.assertEquals("websocket", headers.get("upgrade"));
+ Assert.assertEquals("upgrade", headers.get("connection"));
+ Assert.assertEquals("13", headers.get("sec-websocket-version"));
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]