Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[browser][websocket] WebSocket hang for messages without ever signaling "end of message" #46982

Closed
kjpou1 opened this issue Jan 14, 2021 · 2 comments
Labels
arch-wasm WebAssembly architecture area-System.Net
Milestone

Comments

@kjpou1
Copy link
Contributor

kjpou1 commented Jan 14, 2021

The javascript websocket implementation does not support partial message without end of message sent.

The following code that specifies that the end of message should be sent:

                    await socket.SendAsync(
                            new ArraySegment<byte>(receiveBuffer, 0, offset),
                            receiveResult.MessageType,
                            false,  // end of message
                            CancellationToken.None);

When executed it leaves the network request in a pending state and never fires the onMessage event. This can be viewed from the network status page of a browser.

The test code that runs the websocket echo server for tests can be viewed here: EchoWebSocket.ashx.cs

The lines have to do with the _replyWithPartialMessages.

Javascript test file attached named index.html.

This connects to the default address wss://corefx-net-http11.azurewebsites.net:443/WebSocket/EchoWebSocket.ashx and passes ?replyWithPartialMessages for partial messages.

The test that concerns this is SendReceive_PartialMessageBeforeCompleteMessageArrives_Success which describes the test as Ask the remote server to echo back received messages without ever signaling "end of message".

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Security-Policy" content="connect-src * 'unsafe-inline';">
    <style>
        table {
            border: 2px solid black;
        }
        input {
            width: 300px;
        }
        select {
            width: 300px;
        }
        textarea {
            width: 513px;
            border: 2px solid black;
        }
    </style>

</head>
    <body>
        <div id="main-body">
            <h1>WebSocket Client</h1>
            <!-- WebSocket Connection Parameters Table -->
            <table>
                <tr>
                    <td width="200px">WS Protocol</td>
                    <td>
                        <select id="protocol">
                            <option value="ws" >ws</option>
                            <option value="wss" selected="selected">wss</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>WS Hostname</td>
                    <td><input type="text" id="hostname" value="corefx-net-http11.azurewebsites.net"/></td>
                </tr>
                <tr>
                    <td>WS Port</td>
                    <td><input type="text" id="port" value="443"/></td>
                </tr>
                <tr>
                    <td>WS Endpoint</td>
                    <td><input type="text" id="endpoint" value="/WebSocket/EchoWebSocket.ashx"/></td>
                </tr>
            </table><br/>
            <!-- Send Message Table -->
            <table>
                <tr>
                    <td width="200px">Message</td>
                    <td><input type="text" id="message"/></td>
                </tr>
                <tr>
                    <td></td>
                    <td>
                        <input id="btnSendBinPartialJS" type="button" value="Send Partial Message javascript" onclick="App.onSendBinPartialJSClick()">&nbsp;&nbsp;
                    </td>
                </tr>
                <tr>
                    <td></td>
                    <td>
                        <input id="btnonSendBinNoPartialJS" type="button" value="Send Message javascript" onclick="App.onSendBinNoPartialJSClick()">
                    </td>
                </tr>
            </table><br/>
            <textarea id="incomingMsgOutput" rows="10" cols="20" disabled="disabled"></textarea>
        </div>

        <script type="text/javascript">

             var App = {
                onSendBinPartialJSClick: function () {

                    var ws_protocol = document.getElementById("protocol").value;
                    var ws_hostname = document.getElementById("hostname").value;
                    var ws_port     = document.getElementById("port").value;
                    var ws_endpoint = document.getElementById("endpoint").value;

                    var webSocketURL = ws_protocol + "://" + ws_hostname + ":" + ws_port + ws_endpoint + "?replyWithPartialMessages";

                    LogIt("onSendBinPartialJS: " + webSocketURL);

                    DoSocketStuff(webSocketURL);
                },
                onSendBinNoPartialJSClick: function () {

                    var ws_protocol = document.getElementById("protocol").value;
                    var ws_hostname = document.getElementById("hostname").value;
                    var ws_port     = document.getElementById("port").value;
                    var ws_endpoint = document.getElementById("endpoint").value;

                    var webSocketURL = ws_protocol + "://" + ws_hostname + ":" + ws_port + ws_endpoint;

                    LogIt("onSendBinNoPartialJS: " + webSocketURL);
                    DoSocketStuff(webSocketURL);

                }
                //ws://corefx-net-http11.azurewebsites.net:80/WebSocket/EchoWebSocket.ashx?replyWithPartialMessages
                //wss://corefx-net-http11.azurewebsites.net:443/WebSocket/EchoWebSocket.ashx?replyWithPartialMessages

            };

            function DoSocketStuff (webSocketURL)
            {
                // Create WebSocket connection.
                const socket = new WebSocket(webSocketURL);
                socket.binaryType = "arraybuffer";
                // Connection opened
                socket.addEventListener('open', function (event) {
                    var bytearray = new Uint8Array( 65000 );
                    for ( var i = 0; i < 65000; ++i ) {
                        bytearray[i] = 255;
                    }
                    LogIt('Sending to server: ' + bytearray + " count: " + bytearray.buffer.byteLength);
                    socket.send(bytearray.buffer);
                });

                // Listen for messages
                socket.addEventListener('message', function (event) {
                    var bytearray = new Uint8Array( event.data );
                    LogIt('Message from server: ' + bytearray + " count: " + bytearray.buffer.byteLength);
                    socket.close(4000, 'Hic sunt Dracones');
                });

            }

            function LogIt (message)
            {
                document.getElementById("incomingMsgOutput").value += '\n---------\n' + message + '\n---------';
                console.log(message);
            }
            </script>
    </body>
</html>
@kjpou1 kjpou1 added arch-wasm WebAssembly architecture area-System.Net labels Jan 14, 2021
@kjpou1 kjpou1 added this to the Future milestone Jan 14, 2021
@ghost
Copy link

ghost commented Jan 14, 2021

Tagging subscribers to 'arch-wasm': @lewing
See info in area-owners.md if you want to be subscribed.

Issue Details

The javascript websocket implementation does not support partial message without end of message sent.

The following code that specifies that the end of message should be sent:

                    await socket.SendAsync(
                            new ArraySegment<byte>(receiveBuffer, 0, offset),
                            receiveResult.MessageType,
                            false,  // end of message
                            CancellationToken.None);

When executed it leaves the network request in a pending state and never fires the onMessage event. This can be viewed from the network status page of a browser.

The test code that runs the websocket echo server for tests can be viewed here: EchoWebSocket.ashx.cs

The lines have to do with the _replyWithPartialMessages.

Javascript test file attached named index.html.

This connects to the default address wss://corefx-net-http11.azurewebsites.net:443/WebSocket/EchoWebSocket.ashx and passes ?replyWithPartialMessages for partial messages.

The test that concerns this is SendReceive_PartialMessageBeforeCompleteMessageArrives_Success which describes the test as Ask the remote server to echo back received messages without ever signaling "end of message".

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Security-Policy" content="connect-src * 'unsafe-inline';">
    <style>
        table {
            border: 2px solid black;
        }
        input {
            width: 300px;
        }
        select {
            width: 300px;
        }
        textarea {
            width: 513px;
            border: 2px solid black;
        }
    </style>

</head>
    <body>
        <div id="main-body">
            <h1>WebSocket Client</h1>
            <!-- WebSocket Connection Parameters Table -->
            <table>
                <tr>
                    <td width="200px">WS Protocol</td>
                    <td>
                        <select id="protocol">
                            <option value="ws" >ws</option>
                            <option value="wss" selected="selected">wss</option>
                        </select>
                    </td>
                </tr>
                <tr>
                    <td>WS Hostname</td>
                    <td><input type="text" id="hostname" value="corefx-net-http11.azurewebsites.net"/></td>
                </tr>
                <tr>
                    <td>WS Port</td>
                    <td><input type="text" id="port" value="443"/></td>
                </tr>
                <tr>
                    <td>WS Endpoint</td>
                    <td><input type="text" id="endpoint" value="/WebSocket/EchoWebSocket.ashx"/></td>
                </tr>
            </table><br/>
            <!-- Send Message Table -->
            <table>
                <tr>
                    <td width="200px">Message</td>
                    <td><input type="text" id="message"/></td>
                </tr>
                <tr>
                    <td></td>
                    <td>
                        <input id="btnSendBinPartialJS" type="button" value="Send Partial Message javascript" onclick="App.onSendBinPartialJSClick()">&nbsp;&nbsp;
                    </td>
                </tr>
                <tr>
                    <td></td>
                    <td>
                        <input id="btnonSendBinNoPartialJS" type="button" value="Send Message javascript" onclick="App.onSendBinNoPartialJSClick()">
                    </td>
                </tr>
            </table><br/>
            <textarea id="incomingMsgOutput" rows="10" cols="20" disabled="disabled"></textarea>
        </div>

        <script type="text/javascript">

             var App = {
                onSendBinPartialJSClick: function () {

                    var ws_protocol = document.getElementById("protocol").value;
                    var ws_hostname = document.getElementById("hostname").value;
                    var ws_port     = document.getElementById("port").value;
                    var ws_endpoint = document.getElementById("endpoint").value;

                    var webSocketURL = ws_protocol + "://" + ws_hostname + ":" + ws_port + ws_endpoint + "?replyWithPartialMessages";

                    LogIt("onSendBinPartialJS: " + webSocketURL);

                    DoSocketStuff(webSocketURL);
                },
                onSendBinNoPartialJSClick: function () {

                    var ws_protocol = document.getElementById("protocol").value;
                    var ws_hostname = document.getElementById("hostname").value;
                    var ws_port     = document.getElementById("port").value;
                    var ws_endpoint = document.getElementById("endpoint").value;

                    var webSocketURL = ws_protocol + "://" + ws_hostname + ":" + ws_port + ws_endpoint;

                    LogIt("onSendBinNoPartialJS: " + webSocketURL);
                    DoSocketStuff(webSocketURL);

                }
                //ws://corefx-net-http11.azurewebsites.net:80/WebSocket/EchoWebSocket.ashx?replyWithPartialMessages
                //wss://corefx-net-http11.azurewebsites.net:443/WebSocket/EchoWebSocket.ashx?replyWithPartialMessages

            };

            function DoSocketStuff (webSocketURL)
            {
                // Create WebSocket connection.
                const socket = new WebSocket(webSocketURL);
                socket.binaryType = "arraybuffer";
                // Connection opened
                socket.addEventListener('open', function (event) {
                    var bytearray = new Uint8Array( 65000 );
                    for ( var i = 0; i < 65000; ++i ) {
                        bytearray[i] = 255;
                    }
                    LogIt('Sending to server: ' + bytearray + " count: " + bytearray.buffer.byteLength);
                    socket.send(bytearray.buffer);
                });

                // Listen for messages
                socket.addEventListener('message', function (event) {
                    var bytearray = new Uint8Array( event.data );
                    LogIt('Message from server: ' + bytearray + " count: " + bytearray.buffer.byteLength);
                    socket.close(4000, 'Hic sunt Dracones');
                });

            }

            function LogIt (message)
            {
                document.getElementById("incomingMsgOutput").value += '\n---------\n' + message + '\n---------';
                console.log(message);
            }
            </script>
    </body>
</html>
Author: kjpou1
Assignees: -
Labels:

arch-wasm, area-System.Net

Milestone: Future

@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged New issue has not been triaged by the area owner label Jan 14, 2021
@kjpou1
Copy link
Contributor Author

kjpou1 commented Jan 15, 2021

duplicate of #46983

@kjpou1 kjpou1 closed this as completed Jan 15, 2021
@karelz karelz modified the milestones: Future, 6.0.0 Jan 25, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Feb 24, 2021
@karelz karelz removed the untriaged New issue has not been triaged by the area owner label Oct 20, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
arch-wasm WebAssembly architecture area-System.Net
Projects
None yet
Development

No branches or pull requests

2 participants