WebSocketConnection does not answer a client close frame

Aperta Adatta ai principianti
#52 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
80/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
csharp

Direzione di ricerca

Inizia in MaxLib.WebServer/WebSocket/WebSocketConnection.cs intorno alle righe 237-250, dove un close frame in arrivo imposta solo ReceivedCloseSignal e chiama ReceiveClose, e confrontalo con il percorso Close() esistente, che invia già la risposta che l'issue si aspetta. Traccia come il ciclo di ping e l'evento Closed vengono smontati in modo che la classe base possa chiudere la connessione da sola. Riproduci con il repro.csproj/Program.cs dell'issue (dotnet run, poi dotnet run -- reply); done significa che "close reply received: NormalClosure" e "Closed event raised" appaiono nell'esecuzione predefinita.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

bug security severity:medium

When a client sends a close frame, WebSocketConnection only sets ReceivedCloseSignal and calls ReceiveClose
(WebSocketConnection.cs#L237-L250).
It never sends a close frame back, which RFC 6455 §5.5.1 requires.

As a result, the ping loop keeps running, Closed never fires, and WebSocketEndpoint<T> never removes or disposes the connection.
Every normal client disconnect leaks a connection unless the subclass calls Close() from its ReceiveClose override.

Expected: the library replies to the close frame itself and the connection shuts down.

Reproduction

repro.csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="MaxLib.WebServer" Version="5.0.0" />
  </ItemGroup>
</Project>

Program.cs:

using System.Net.WebSockets;
using MaxLib.WebServer;
using MaxLib.WebServer.WebSocket;

// Pass "reply" to call Close() from ReceiveClose (the workaround) for comparison.
var reply = args.Contains("reply");
var closed = new TaskCompletionSource();

using var server = new Server(new WebServerSettings(8099, 5000));
server.InitialDefault();
var ws = new WebSocketService();
ws.Add(new Endpoint(closed, reply));
server.AddWebService(ws);
server.Start();

using var client = new ClientWebSocket();
await client.ConnectAsync(new Uri("ws://127.0.0.1:8099/"), default);
await client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, null, default);

var receive = client.ReceiveAsync(new byte[1024], default);
var first = await Task.WhenAny(receive, Task.Delay(TimeSpan.FromSeconds(5)));
Console.WriteLine(first == receive
    ? $"close reply received: {receive.Result.CloseStatus}"
    : "no close reply within 5 s");

first = await Task.WhenAny(closed.Task, Task.Delay(TimeSpan.FromSeconds(30)));
Console.WriteLine(first == closed.Task
    ? "Closed event raised"
    : "Closed event not raised within 30 s");

server.Stop();

class Endpoint(TaskCompletionSource closed, bool reply) : WebSocketEndpoint<Connection>
{
    public override string? Protocol => null;

    protected override Connection? CreateConnection(Stream stream, HttpRequestHeader header)
    {
        var connection = new Connection(stream, reply);
        connection.Closed += (_, _) => closed.TrySetResult();
        return connection;
    }
}

class Connection(Stream stream, bool reply) : WebSocketConnection(stream)
{
    protected override Task ReceiveClose(CloseReason? reason, string? info)
        => reply ? Close() : Task.CompletedTask;

    protected override Task ReceivedFrame(Frame frame) => Task.CompletedTask;
}

Output of dotnet run:

no close reply within 5 s
Closed event not raised within 30 s

Output of dotnet run -- reply:

close reply received: NormalClosure
Closed event raised
Lingua principale
C#
Stelle
1
Fork
3
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di Garados007/MaxLib.WebServer

Tutte le issue di Garados007/MaxLib.WebServer

Issue simili

Altre issue su C#

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.