title: Websocket 'hard' disconnect not apparent?
body: <p>I'm not sure if I'm experiencing a default time-out (can I set this somewhere?), but maybe I am missing something. When a client's browser establishes a websocket connection, I keep persistence. Then, on disconnect, I delete that persisted object. Simple enough. The disconnect <em>normally</em> gets triggered when a client closes the browser, but <strong>not when the client turns off their wi-fi connection</strong> (testing on a MacBook Pro, not that this should matter).</p>
  <p>In the Scala controller, I am logging every <code>in</code> message, but <strong>nothing</strong> comes through when the wi-fi is turned off (from the <a href="http://www.playframework.org/documentation/2.0/ScalaWebSockets" rel="nofollow noreferrer">docs</a>, I would expect an EOF?).</p>
  <p>I think that this must be a bug, as taken from how I interpret the <a href="https://www.rfc-editor.org/rfc/rfc6455#section-7" rel="nofollow noreferrer">WS protocol</a> <strong>the server MUST <em>Close the WebSocket
  Connection</em>, and SHOULD log the problem.</strong> But the latter doesn't happen.</p>
  <pre><code>val in = Iteratee.foreach[String](x =&gt; {
    logger.info(&quot;Websocket msg: &quot; + x)
     // expect EOF?
     x match {
       case &quot;persist&quot; =&gt; // persist some object
     }
  }).mapDone { x =&gt;
     // delete my persisted object (never happens unless browser/tab closed)
  }
  </code></pre>
  <p>Has anybody experienced this? I've tried both a simple controller and something that matches my configuration. Neither <code>ws3</code> or <code>ws2</code> controllers below do the trick. Play! code below:</p>
  <pre><code>object Application extends Controller {
  
    private def ws(out: PushEnumerator[String]) = {
  
      Logger.logger.info(&quot;ws()&quot;)
  
      val in = Iteratee.foreach[String](x =&gt; {
        Logger.logger.info(&quot;Websocket msg: &quot; + x)
        try {
          x match {
            case &quot;persist&quot; =&gt; Logger.logger.info(&quot;PERSIST&quot;)
          }
        } catch {
          case e: Exception =&gt; {
            Logger.logger.info(&quot;NOT RECOGNIZED COMMAND, NO PERSIST&quot;)
          }
        }
      }).mapDone { x =&gt;
        Logger.logger.info(&quot;STOP PERSIST&quot;)
      }
      in
    }
  
    def ws2() = WebSocket.using[String] { request =&gt;
  
      Logger.logger.info(&quot;ws2()&quot;)
  
      val out = Enumerator.imperative[String]()
      val in = ws(out)
  
      (in, out)
    }
  
    def ws3() = WebSocket.using[String] { request =&gt;
  
      Logger.logger.info(&quot;ws3()&quot;)
  
      val out = Enumerator.imperative[String]()
      val in = Iteratee.foreach[String](x =&gt; {
        Logger.logger.info(&quot;Websocket msg: &quot; + x)
        try {
          x match {
            case &quot;persist&quot; =&gt; Logger.logger.info(&quot;PERSIST&quot;)
          }
        } catch {
          case e: Exception =&gt; {
            Logger.logger.info(&quot;NOT RECOGNIZED COMMAND, NO PERSIST&quot;)
          }
        }
      }).mapDone { x =&gt;
        Logger.logger.info(&quot;STOP PERSIST&quot;)
      }
      (in, out)
    }
  
    def view() = Action { implicit request =&gt;
      Ok(views.html.index.render(&quot;&quot;))
    }
  }
  </code></pre>
  <p>The view is a simple:</p>
  <pre><code>@(message: String) @main(&quot;Welcome to Play 2.0&quot;) {
  
  @play20.welcome(message) }
  
  &lt;script type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;
      var sock = new WebSocket(&quot;ws://192.168.1.120:9001/ws3&quot;);
  
      sock.onopen = function(event) {
          sock.send('persist');
      }
  &lt;/script&gt;
  </code></pre>
  <p>Routes:</p>
  <pre><code>GET     /ws2                          controllers.Application.ws2
  GET     /ws3                          controllers.Application.ws3
  GET     /view                         controllers.Application.view
  </code></pre>