61331

How do I handle a WebSocket close from the client in Yaws?

Question:

I have implemented a simple <em>appmod</em> that handle WebSockets and echo back the messages. But how do I handle an ws.close(); from the JavaScript client? I have tried with the code below, but handle_message({close, Reason}) is never called and ws.onclose = function(evt) {} is never executed on the JavaScript client.

When I use the same JavaScript client code interacting with a node.js websocket, the client receives an onclose event immediately after ws.close();.

Here is the code for my simple <em>appmod</em>:

-module(mywebsocket). -export([handle_message/1]). handle_message({text, Message}) -> {reply, {text, <<Message/binary>>}}; handle_message({close, Reason}) -> io:format("User closed websocket.~n", []), {close, normal}.

Answer1:

Updated answer:

As of github commit 16834c, which will eventually be part of Yaws 1.93, Yaws passes a new callback to your WebSockets callback module when the client sends a close message. The callback is:

{close, Status, Reason}

where Status is either the close status sent by the client, or the numerical value 1000 (specified by RFC 6455 for a normal close) if the client didn't include a status value. Reason is a binary holding any optional reason string passed from the client; it will be an empty binary if the client sent no reason.

Your callback handler for a close message MUST return {close, CloseReason} where CloseReason is either the atom normal for a normal close (which results in the status code 1000 being returned to the client) or another legal numerical status code allowed by RFC 6455. Note that CloseReason is unrelated to any Reason value passed by the client. Technically CloseReason can also be any other Erlang term, in which case Yaws returns status 1000 and passes the term to erlang:exit/1 to exit the Erlang process handling the web socket, but based on RFC 6455 we suggest simply returning the atom normal for CloseReason in all cases.

Original answer, obsoleted by Yaws github commit 16834c:

Yaws never passes a {close, Reason} message to your callback module. Rather, {close, Reason} is a valid return value from handle_message/1 should your callback module decide it wants to close the ws socket.

I modified the websockets_example.yaws file shipped with Yaws (version 1.92) to call this._ws.close() in the client if the user enters the "bye" message on the web page, and added an alert to the _onclose function to show that the onclose event is triggered. In this case the alert occurred, I believe because the "bye" message causes the server to close the ws socket explicitly. But I then modified the example to call this._ws.close() in the client no matter what message the user enters, and in that case no alert for onclose occurred. In this case, a check with lsof showed the ws connection from the browser to Yaws was still present.

So, for now I believe you've hit a bug where the Yaws websockets support isn't detecting the client close and closing its end. I'll see if I can fix it.

Recommend

  • Web server for running PHP+Erlang
  • Non-blocking mlock()
  • using copy in postgresql?
  • General Python socket questions with several answers
  • print float without scientific notation in scala
  • Disable back-page button in browser
  • Refactor native query to JPQL query
  • Call C functions from 64-bit assembly
  • Hide the iframes whose content get blocked by proxy
  • How can I move mouse by detected face and Eye using OpenCV and Python
  • Is there a way to limit the duration of an audio capture in Codename One?
  • CMake with regarding generated files
  • openOptionsMenu() across android versions
  • R: Hide dummies output
  • Conditionally render h:selectOneMenu and h:inputText by ajax depending on h:selectOneRadio selection
  • Extract and add to the data frame the values of sigma from a stan distributional linear model
  • How to implement a callback method within DLL (Delphi / TJVPluginManager + TJvPlugin)
  • Footer appears next to section instead of below
  • How do I use RestSharp to POST a login and password to an API?
  • Ellipsis directive with title
  • NOTE or WARNING from package check when README.md includes images
  • Adding custom message on Thank You page by shipping method
  • can I build CMakeLists.txt from a set of smaller files (to improve the readability and maintainabili
  • Can Node.JS on OpenShift be upgraded?
  • Django REST framework - HyperlinkedRelatedField with additional parameter
  • How to find angle formed by the blades of a wind turbine with respect to a horizontal imaginary axis
  • “Cannot open log for source” - Windows 7 - .NET web service - event log
  • Thumbnails for mxml components in Flex
  • Ajax call on Multiple selection in Select box
  • Regex not working in java 1.5
  • Add font awesome icon to custom add to cart button in Woocommerce 3
  • Dynamic XML Schema Validates Subsection of Document
  • Django, uWSGI & nginx: Process dies for “no reason”
  • Typeahead.js does give me suggestions but doesn't select them
  • Unable to create Access token grant type in wso2 API manager store to test API
  • how to get the location(lat/lng) on google maps v3 from the location(x,y)
  • Send array to next viewcontroller iOs xcode [duplicate]
  • Python Flask - GUI for client