Websocket handshake response missing added headers
Describe the bug spring-boot-dependencies:2.5.2 spring-cloud-dependencies:2020.0.4 (spring-cloud-gateway-server:3.0.4)
We are using SCG to front a set of web applications implemented in Streamlit. Streamlit applications establish a websocket connection which is used to dynamically return data to the page. When the websocket connection is estabished, the streamlit server returns a Set-Cookie header that contains an XSRF token. This token is then used for operations such as file upload.
After placing this app behind SCG, we noticed that we are no longer receiving the "additional" response headers. They are being lost as the response transits through the gateway.
I have put together a basic setup that replicates the issue using a simple Node.js websocket server, a client HTML page, and the SCG setup.
Steps to Reproduce
- Run the node
server.mjsfile:
// install the one dependency:
// npm install ws
import { WebSocketServer } from 'ws';
const wss = new WebSocketServer({ port: 5678 });
wss.on('headers', (headers) => {
headers.push('Set-Cookie: _xsrf=1234599');
headers.push('X-Other-Header: hello');
});
wss.on('connection', function connection(ws) {
console.log('Connection')
ws.send('hi from the server');
});
- Open the
client.htmlin your browser. It should establish a connection to the websocket server and displayhi from the serveron the page.
<!DOCTYPE html>
<html lang="en">
<head>
<title>WebSocket demo</title>
</head>
<body>
<script>
port = "5678" // Go direct to server
//port = "6600" // Go through gateway
let ws = new WebSocket("ws://127.0.0.1:" + port + "/"), messages = document.createElement('ul');
ws.onmessage = function (event) {
let messages = document.getElementsByTagName('ul')[0],
message = document.createElement('li'),
content = document.createTextNode(event.data);
message.appendChild(content);
messages.appendChild(message);
};
document.body.appendChild(messages);
</script>
</body>
</html>
- Open up the network tab, and you should also observe that the browser received two response headers (
Set-CookieandX-Other-Header).
- Now configure and start up a gateway to front this server:
# Spring Cloud Gateway Config
spring:
cloud:
gateway:
routes:
- id: websocket
uri: http://localhost:5678
predicates:
- Host=**
server:
port: 6600
logging:
level:
org:
springframework:
cloud:
gateway: TRACE
- The
client.htmlpage needs to be updated to go through the gateway. This is done by changing the port number from 5678 to 6600.
<script>
//port = "5678" // Go direct to server
port = "6600" // Go through gateway
- Go back to the browser and refresh the
client.htmlpage. You should one again seehi from the serveron the page. Now examine the network tab and notice our two added headers are absent from the server response.
Setting a breakpoint in WebsocketRoutingFilter.java, I can see the missing response headers in the proxySession.handshakeinfo.headers map.
But how to get them into the response back to the browser... 🤔. I would appreciate any tips and/or hacks to get these headers through the gateway! Thanks.
Related to https://github.com/spring-cloud/spring-cloud-gateway/issues/2225
@andrewkcarter Hi, hope you are doing well. did you mange to find a solution for this issue?
Not through SCG. We had to put that websocket application behind nginx instead.
Still not fixed. Is there any workaround to this issue other than implementing WebSocketRoutingFilter ourselves?