Hi, I’m using K6 (.25 version) to perform load testing on a WSS url. I’m getting the Bad Handshake issue and I coudn’t find much information on whether K6 supports Secure Web Sockets (WSS). Can you please help if there is any workaround to make K6 support WSS
INFO[0003] An unexpected error occured: 0=“websocket: bad handshake”
ERRO[0003] GoError: websocket: bad handshake-
at native
OK, for SignalR with cookie authentication. I had to set the Cookie using a header. The cookie field in the parameters object doesn’t seem to be effective.
It was working locally because my local iis allowed localhost connections unauthenticated.
@woakesd Can you share the output of k6 version, your test script or relevant parts of it, and if there’s a public test instance of the WS server you’re testing against or if there’s anything otherwise peculiar about its implementation?
We need to be able to reproduce your issue to help, and determine whether this is a bug in k6 and its details if so.
I can’t point you at the real site unfortunately but will try to set up something which demonstrates this.
Script:
var res = http.post(`${urlBase}/MatchDispatcher/activitieshub/negotiate`, null, {
"responseType": "text"
}
);
var connectionId = res.json()["connectionId"];
console.log(`Connection Id is ${connectionId}`);
var url = `${webSocketBase}/MatchDispatcher/activitieshub?id=${connectionId}`;
console.log(url);
var response = ws.connect(url, {
headers: {
"Cookie": `authCookieName=${authCookie}`,
"Origin": `https://${site}"`
}
}, function (socket) {
socket.on('open', function open() {
console.log('connected');
});
socket.on('message', function (message) {
console.log(`Received message: ${message}`);
});
socket.on('close', function () {
console.log('disconnected');
});
socket.on('error', function (e) {
if (e.error() != "websocket: close sent") {
console.log('An unexpected error occurred: ', e.error());
}
});
socket.setTimeout(function () {
console.log('60 seconds passed, closing the socket');
socket.close();
}, 60000);
});
check(response, { "status is 101": (r) => r && r.status === 101 });
response.close();
}
Output from K6
Request:
POST /MatchDispatcher/activitieshub/negotiate HTTP/1.1
Host: SSSSSSS
User-Agent: k6/0.25.1 (https://k6.io/)
Content-Length: 0
Cookie: .AspNet.SMAIdentity=XXXXXXXXXXXX
Accept-Encoding: gzip
Response:
HTTP/1.1 200 OK
Content-Length: 252
Content-Type: application/json
Date: Wed, 18 Dec 2019 12:23:34 GMT
Server: Microsoft-IIS/8.5
X-Powered-By: ASP.NET
X-Powered-By: ARR/3.0
X-Powered-By: ASP.NET
INFO[0003] Connection Id is CCCCCID
INFO[0003] wss://SSSSSSS/MatchDispatcher/activitieshub?id=CCCCCID
INFO[0003] connected
INFO[0018] Received message: {"error":"Handshake was canceled."}
INFO[0018] disconnected
INFO[0063] 60 seconds passed, closing the socket
ERRO[0063] TypeError: Cannot read property 'error' of undefined
at file:///C:/Users/P10306702/source/repos/test/load-impact-assessment/test-alert-monitor.js:107:9(3)
at native
at file:///C:/Users/P10306702/source/repos/test/load-impact-assessment/test-alert-monitor.js:114:5(9)
at native
at file:///C:/Users/P10306702/source/repos/test/load-impact-assessment/test-alert-monitor.js:91:15(62)
at native
at file:///C:/Users/P10306702/source/repos/test/load-impact-assessment/test-alert-monitor.js:77:16(59)
R
I will do. I’ve worked out how to make it work. I didn’t quite understand the messages in chrome originally and thought I was only receiving.
Turns out you send a protocol request ‘{“protocol”:“json”,“version”:1})\x1e’ when you connect and then send the handshake ‘{“type”:6}\x1e’ periodically.
@woakesd
Would it be possible for you to share your minimal fully working example? I’m currently fighting with SignalR and raw websockets to write a load test.
group(`page_3 - test websocket`, function() {
// Get the connection id to use in the web socket connect
var res = http.post(`${urlBase}/${huburl}/negotiate`, null, {
"responseType": "text"
}
);
var connectionId = res.json()["connectionId"];
var url = `${webSocketBase}/${huburl}?id=${connectionId}`;
var response = ws.connect(url, {
headers: {
"Cookie": `${authCookieName}=${authCookie}`,
"Origin": `https://${site}`,
}
}, function (socket) {
socket.on('open', function open() {
// Once socket is connected send protocol request
socket.send('{"protocol":"json","version":1})\x1e');
console.log('sent protocol request');
});
socket.on('message', function (message) {
switch (message) {
case '{}\x1e':
// This is the protocol confirmation
break;
case '{"type":6}\x1e':
// Received handshake
break;
default:
// should check that the JSON contains type === 1
console.log(`Received message: ${message}`);
}
});
socket.on('error', function (e) {
if (e.error() != "websocket: close sent") {
console.log('An unexpected error occurred: ', e.error());
}
});
socket.setTimeout(function () {
console.log('60 seconds passed, closing the socket');
socket.close();
}, 60000);
});
check(response, { "status is 101": (r) => r && r.status === 101 });
}
);
The important bits are calling negotiate to get the id to pass to the websocket call and if you need an authorization cookie setting it’s value explicitly and once connected send the protocol message.
@woakesd. Thanks for the solution it worked perfect!!. I was hesitant that this would not work on wss but after I tried this solution, it made my life easy.