After moving from quarkus-websocket
to quarkus-websockets-next
, any HTTP GET to a @WebSocket
path now errors with
"Connection" header must be "Upgrade"
This is because the new extension intercepts every matching request and treats it as a WebSocket handshake.
In the old quarkus-websocket
model, @ServerEndpoint
only handled true WebSocket upgrades; plain GETs to the same URL would fall through to JAX-RS resources.
With quarkus-websockets-next
, @WebSocket(path="/…")
installs a single Vert.x handler for all HTTP methods on that path. A standard GET—lacking the required Connection: Upgrade header—gets caught and rejected before any REST logic can run.
Below is a minimal Quarkus project showing:
Legacy (quarkus-websockets
):
@GET /chat
endpoint@ServerEndpoint("/chat")
200 OK
), WS worksNext (quarkus-websockets-next
):
@WebSocket(path = "/chat")
GET /chat
now fails with"Connection" header must be "Upgrade"
Sample reproduction using:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-websockets</artifactId>
</dependency>
ChatResource.java
:
@Path("/chat")
@ApplicationScoped
public class ChatResource {
@GET
public String hello() {
return "Hello from REST!";
}
}
ChatEndpoint.java
:
@ServerEndpoint("/chat")
@ApplicationScoped
public class ChatEndpoint {
@OnOpen
public void onOpen(Session session) { /*...*/ }
@OnMessage
public void onMessage(Session session, String msg) {
session.getAsyncRemote().sendText("Echo:" + msg);
}
}
Behavior
GET http://localhost:8080/chat → 200 OK with “Hello from REST!”
ws://localhost:8080/chat → WebSocket handshake succeeds
With the new quarkus-websockets-next
:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-websockets-next</artifactId>
</dependency>
ChatResource.java (unchanged)
:
@Path("/chat")
@ApplicationScoped
public class ChatResource {
@GET
public String hello() {
return "Hello from REST!";
}
}
ChatSocket.java
:
@WebSocket(path = "/chat")
@ApplicationScoped
public class ChatSocket {
@OnOpen
public void onOpen(WebSocketConnection conn) { /*...*/ }
@OnMessage
public void onMessage(WebSocketConnection conn, String msg) {
conn.sendText("Echo:" + msg).subscribe().with(r -> {}, t -> {});
}
}
Behavior
GET http://localhost:8080/chat → fails with
"Connection" header must be "Upgrade"
ws://localhost:8080/chat → WebSocket handshake succeeds
Is this expected from the quarkus-websockets-next
or is this a bug? Because I am implementing some endpoints for a standard specification where I can have the endpoints something like this:
/queries/{queryName}/events
As per the specification, it should do the following:
Returns all events that match the query or creates a new Websocket subscription.
This was working with the quarkus-websockets
and now failing the GET request with quarkus-websockets-next
so bit confusing if this is an issue that needs a fix.
It's a bug in WebSockets Next. We tried to fix this problem in https://github.com/quarkusio/quarkus/pull/43439 (Quarkus 3.15.2+) but the fix is not quite correct, in the sense that the next route is used but WS Next still attempts to upgrade the request at some point; i.e. it's a timing issue.
The problem should be fixed in https://github.com/quarkusio/quarkus/pull/47583.
In any case, I also checked the RFC 6455 and it states that the opening handshake must be HTTP GET with specific headers (e.g. Upgrade: websocket
and Connection: Upgrade
) and the server should return an HTTP response with an appropriate error code (such as 400) if the handshake violates the requiremenets. So I'm not really sure if the required behavior (ignoring non-websocket requests) is guaranteed for other implementations...