Actions
in GlobalSettings
for WebSockets
? What if we want to refuse a WebSocket connection when certain headers are missing? Something similar to the following code snippet didn't work as expected:override def onRouteRequest(request: RequestHeader): Option[Handler] = { if(request.path.startsWith("/ws")){ Option(controllers.Default.error) } else super.onRouteRequest(request) }
Interrupting WebSocket from the global object does not work as it does for Actions. However, there are other means of doing so: by using the tryAccept
and tryAcceptWithActor
methods. A WebSocket definition can be replaced by the following code:
def wsWithHeader = WebSocket.tryAccept[String] { rh => Future.successful(rh.headers.get("token") match { case Some(x) => var channel: Concurrent.Channel[String] = null val out = Concurrent.unicast[String] { ch => channel = ch } val in = Iteratee.foreach[String] { word => channel.push(word.reverse) } Right(in, out) case _ => Left(Forbidden) }) }
When using an Actor, define a WebSocket with the tryAcceptWithActor
method:
def wsheaders = WebSocket.tryAcceptWithActor[String, String] { request => Future.successful(request.headers.get("token") match { case Some(x) => Right(out => Reverser.props(out)) case _ => Left(Forbidden) }) }
In the preceding examples, we are only checking to see if there is a token header, but this can be updated to any other criteria.
As of 2.3.x, there is no built-in support for wss. However, it's possible to use proxies, such as Nginx or HAProxy as the secure WebSocket (wss) endpoint and forward to an internal Play app with an insecure WebSocket endpoint.
3.14.251.128