Tcl Library Source Code

View Ticket
Login
Ticket UUID: 631a44ed66fbb33373f1d5342a0ae5d1ba6dd38b
Title: WebSocket clients can block server
Type: Bug Version: 1.4
Submitter: anonymous Created on: 2015-04-16 09:35:12
Subsystem: websocket Assigned To: emmanuel
Priority: 5 Medium Severity: Critical
Status: Open Last Modified: 2015-04-17 06:48:13
Resolution: None Closed By: nobody
    Closed on:
Description:
::websocket server socket is set to *blocking* mode.  As a
consequence, misbehaving clients can completely block the server if they
refuse to read or write a complete message.

The following recipe (*nix only) reproduces the issue.  Two shells are
needed, one to run a ::websocket server, the other to create a
misbehaving client.

In the first shell run the Tcl script below.  The script creates a
WebSocket server (handshake ommited) and prints a message at regular
intervals; this message will stop being printed when the client blocks
the server.

---------------->8----------------
package require websocket;
namespace eval ::s {};
proc ::s::accept {sock args} {
    puts "server: new connection $args";
    ::websocket::takeover $sock [list ::s::handler] 1 {};
}
proc ::s::handler {sock type args} {
    puts "$sock: $type $args";
}
proc ::s::canary {interval} {
    puts "canary: Still alive...";
    ::after $interval [list ::s::canary $interval];
}

::s::canary 1000;
::socket -server [list ::s::accept] 54321;
::vwait forever;
----------------8<----------------

In the second shell run the following command:

---------------->8----------------
    { echo -n 1; sleep 5s; } | nc localhost 54321
----------------8<----------------

The server is blocked for 5 seconds.
User Comments: anonymous added on 2015-04-17 06:48:13:
A recipe for a client blocking the server by refusing to read:

---------------->8----------------
package require websocket;
namespace eval ::s {};
proc ::s::accept {sock args} {
    puts "server: new connection $args";
    ::websocket::takeover $sock [list ::s::handler] 1 {};
    ::websocket::send $sock text [string repeat "Welcome" 1000000];
}
proc ::s::handler {sock type args} {
    puts "$sock: $type $args";
}
proc ::s::canary {interval} {
    puts "canary: Still alive...";
    ::after $interval [list ::s::canary $interval];
}

::s::canary 1000;
::socket -server [list ::s::accept] 54321;
----------------8<----------------

In the second shell run the following command:

---------------->8----------------
nc localhost 54321 | { sleep 5s; wc; }
----------------8<----------------