dotnet/aspnetcore

Inconsistency between IIS and Kestrel for websocket connect operation with duplicate 'Upgrade: websocket, websocket' header

Open

#50 364 ouverte le 28 août 2023

Voir sur GitHub
 (2 commentaires) (2 réactions) (2 assignés)C# (10 653 forks)batch import
area-networkingbugfeature-iisfeature-websocketshelp wanted

Métriques du dépôt

Stars
 (37 933 stars)
Métriques de merge PR
 (Merge moyen 16j 9h) (258 PRs mergées en 30 j)

Description

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Accidentally I've sent a websocket connect request with duplicate websocket header like here: image

It worked on a Kestrel based app: websocket connection was established, and I could send \ receive messages and gracefully terminate a connection.

  • It failed on IIS hosted app: after calling context.WebSockets.AcceptWebSocketAsync() websocket.State is Open image
  • but client immediately disconnected:
Could not connect to ws://localhost:21156
12:00:24
Error: Unexpected server response: 101
Handshake Details
Request URL: http://localhost:21156/
Request Method: GET
Status Code: 101 Switching Protocols
Request Headers
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: gCyKijP/CPAUtW3Cjyf8gA==
Connection: Upgrade
Upgrade: websocket, websocket
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Host: localhost:21156
Response Headers
Transfer-Encoding: chunked
Upgrade: websocket
Server: Microsoft-IIS/10.0
Sec-WebSocket-Accept: fiwTshwZAtNTY2V2+ynOPK4kFNk=
X-Powered-By: ASP.NET
Date: Mon, 28 Aug 2023 10:00:24 GMT

Expected Behavior

As per my understanding, either Kestrel implementation should fail as well, or IIS should handle duplicate Upgrade: websocket, websocket header. Let me know, if I am doing something wrong.

Steps To Reproduce

repro is as simple as creating an ASP.NET core project and using such setup in Program.cs:

app.UseWebSockets();
app.Use(async (context, next) =>
{
    if (context.WebSockets.IsWebSocketRequest)
    {
        using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
        await Echo(webSocket);
    }
    else
    {
        await next(context);
    }
});

app.Run();

and make a websocket connect call with Upgrade: websocket, websocket header.

if you need a repro in a repository:

Exceptions (if any)

Unhandled exception. System.Net.WebSockets.WebSocketException (203): The server's response was missing the required header 'Connection'.
   at System.Net.WebSockets.WebSocketHandle.ValidateHeader(HttpHeaders headers, String name, String expectedValue)
   at System.Net.WebSockets.WebSocketHandle.ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options)
   at System.Net.WebSockets.ClientWebSocket.ConnectAsyncCore(Uri uri, CancellationToken cancellationToken)
   at Program.<Main>$(String[] args) in C:\code\personal\repro-1\WebApp\Client\Program.cs:line 10
   at Program.<Main>(String[] args)

.NET Version

net6.0 (local 6.0.316)

Anything else?

No response

Guide contributeur