This is an automated email from the ASF dual-hosted git repository.

markt-asf pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/9.0.x by this push:
     new 35d9299bcf Include the Upgrade header field in WebSocket 426 responses 
(#1116)
35d9299bcf is described below

commit 35d9299bcf6b18f2d7f2cd78e76f3766f635e94a
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        | 71 ++++++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/java/org/apache/tomcat/websocket/server/UpgradeUtil.java 
b/java/org/apache/tomcat/websocket/server/UpgradeUtil.java
index 13c6b26676..6c80501123 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(426);
+            // 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..ccc327915c
--- /dev/null
+++ b/test/org/apache/tomcat/websocket/server/TestUpgradeRequiredResponse.java
@@ -0,0 +1,71 @@
+/*
+ * 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 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(426, 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]

Reply via email to