Websocket: Invalid Handshake

Hi,

I’m new to gatling and websockets, so please bare with me on my inexperience.

I’m currently having issues getting my websocket to connect successfully. It seems to be due to the websocket handshake key received doesn’t match the expected key.

I have included the logs I’m getting when running my simulation and a snippet of my script.
A basic understanding of my simulation is that I’m trying to simulate a client web application that communicates to the server through signalr.

Here is the debug logs for the websocket connect part of my simulation (I redacted specific information).

`

11:11:40.381 [INFO ] i.g.h.a.w.WsConnect - Opening websocket ‘gatling.http.webSocket’: Scenario ‘RecordedSimulation’, UserId #1
11:11:40.403 [DEBUG] i.n.h.c.c.ZlibCodecFactory - -Dio.netty.noJdkZlibDecoder: false
11:11:40.404 [DEBUG] i.n.h.c.c.ZlibCodecFactory - -Dio.netty.noJdkZlibEncoder: false
11:11:40.451 [DEBUG] i.g.h.c.i.DefaultHttpClient - Installing SslHandler for wss://redacted.service.signalr.net/aspnetclient/connect?transport=webSockets&redactedParameters=1
11:11:40.501 [DEBUG] i.n.h.s.u.InsecureTrustManagerFactory - Accepting a server certificate: CN=*.service.signalr.net
11:11:40.577 [DEBUG] i.n.h.c.h.w.WebSocketClientHandshaker13 - WebSocket version 13 client handshake key: hzyAkxV1KZDGq65w38gxdg==, expected response: yYwx+PfP/pR49ZuwpnXsFoUC9P8=
11:11:40.578 [DEBUG] i.g.h.c.i.WebSocketHandler - ctx.write msg=DefaultFullHttpRequest(decodeResult: success, version: HTTP/1.1, content: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 0))
GET /aspnetclient/connect?transport=webSockets&redactedParameters=1 HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36
Referer: https://redacted.azurewebsites.net/?redactedParameters=1
accept: /
cookie: SIGNALRROUTE=redacted
origin: https://redacted.service.signalr.net
upgrade: websocket
connection: upgrade
sec-websocket-key: hzyAkxV1KZDGq65w38gxdg==
host: redacted.service.signalr.net
sec-websocket-origin: https://redacted.service.signalr.net
sec-websocket-version: 13
11:11:40.581 [DEBUG] i.n.h.s.SslHandler - [id: 0x105a7c19, L:/192.168.1.16:4859 - R:redacted.service.signalr.net/redactedIPaddress] HANDSHAKEN: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
11:11:40.635 [DEBUG] i.g.h.c.i.WebSocketHandler - Read msg=HttpObjectAggregator$AggregatedFullHttpResponse(decodeResult: success, version: HTTP/1.1, content: CompositeByteBuf(ridx: 0, widx: 26, cap: 26, components=1))
HTTP/1.1 404 Not Found
Content-Type: text/plain
Connection: keep-alive
Vary: Accept-Encoding
Vary: Origin
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://redacted.service.signalr.net
Strict-Transport-Security: max-age=15724800; includeSubDomains
content-length: 26
11:11:40.636 [DEBUG] i.g.h.c.i.WebSocketHandler - Crash
io.netty.handler.codec.http.websocketx.WebSocketHandshakeException: Invalid handshake response getStatus: 404 Not Found
at io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker13.verify(WebSocketClientHandshaker13.java:191)
at io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker.finishHandshake(WebSocketClientHandshaker.java:216)
at io.gatling.http.client.impl.WebSocketHandler.channelRead(WebSocketHandler.java:122)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.netty.handler.codec.http.websocketx.extensions.WebSocketClientExtensionHandler.channelRead(WebSocketClientExtensionHandler.java:128)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1429)
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1199)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1243)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:502)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:441)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:278)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:644)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:579)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:496)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Unknown Source)
11:11:40.638 [DEBUG] i.g.h.c.i.WebSocketHandler - channelInactive
11:11:40.644 [DEBUG] i.g.h.c.i.WebSocketHandler - Crash
io.gatling.http.client.impl.WebSocketHandler$1: Premature close
11:11:40.646 [DEBUG] i.g.h.a.w.f.WsActor - Connect failed: None:i.n.h.c.h.w.WebSocketHandshakeException: Invalid handshake response getStatus: 404 Not Found, no remaining tries, going to Crashed state and performing next action

`

Here’s a snippet of my simulation code (I redacted specific information).

`

/* negotiate signalr connection and get required tokens to pass with correlation */
// get signalr service access from website
.exec(http(“request_96”)
.get(“https://redacted.azurewebsites.net”+ “/signalr/negotiate?redactedParameters=1)
.headers(headers_96)
.check(status.is(200))
.check(
jsonPath(”$.Token")
.find
.saveAs(“token”)))
)
// get signalr connection information
.exec(http(“request_99”)
.get(“https:/redacted.service.signalr.net/aspnetclient” + "/negotiate?redactedParameters=1)

.headers(headers_100)
.check(

jsonPath("$.Connection")
.find
.saveAs(“connection”))))
)

// Connect to signalr with websocket
.exec(ws(“Connect WS”)
.connect(session => “wss:/redacted.service.signalr.net/aspnetclient” + "/connect?transport=webSockets&redactedParameters=1)
.headers(ws_headers))
.pause(10)

// start signalr listener
.exec(http(“request_101”)
.get(“https:/redacted.service.signalr.net/aspnetclient” + "/start?transport=webSockets&redactedParameters=1)

.headers(headers_100)
.check(

jsonPath("$.Response")
.find
.is(“started”))
))

//commented out ping for right now
/*
// wait 5 minutes and then ping to keep connection open
.pause(300)

.exec(http(“request_110”)
.get(“https:/redacted.service.signalr.net/aspnetclient” + "/ping?redactedParameters=1)

.headers(headers_100)
*/

.exec(ws(“Close WS”).close)

`

Hi,

Your server responded with 404 to the request Gatling sent for opening the WebSocket.
There’s a chance the url you’re trying to connect to is incorrect.

Thank you for the reply. It seems the issue was related to the signalr server. After an update of the server, Gatling is able to open a websocket connection.