unfiltered/unfiltered — pull request #237 by chrislewis (2014-07-13 17:58:20+00:00)
Title: cycle and async plans should push websocket frames through the pipeline

Given the following websocket and http plans:

```scala
@Sharable
object WebSocketFoo extends Plan
with cycle.SynchronousExecution with ServerErrorResponse {
def intent = {
case GET(Path("/")) => {
case Open(s) => println("open! " + s)
case Message(s, Text(t)) => println(s"message from $s: $t")
case Close(s) => println(s"close! $s")
case Error(s, e) => println(s"error! $s")
}
}

def pass = DefaultPassHandler
}

@Sharable
object HttpFoo extends cycle.Plan with cycle.SynchronousExecution with ServerErrorResponse {
def intent = {
case GET(Path("/hi")) => Ok ~> ResponseString("Hello")
}
}
```
The following server will throw exceptions when when it receives websocket frames:
```scala
object Server {
def main(args: Array[String]) {
unfiltered.netty.Http(8080)
.handler(HttpFoo)
.handler(WebSocketFoo)
.run { s =>
println("starting unfiltered app at localhost on port %s"
.format(s.port))
}
}
}
```
While this one will work as expected:
```scala
object Server {
def main(args: Array[String]) {
unfiltered.netty.Http(8080)
.handler(WebSocketFoo)
.handler(HttpFoo)
.run { s =>
println("starting unfiltered app at localhost on port %s"
.format(s.port))
}
}
}
```
This is because the netty http plans pessimistically fail through `sys.error` when a non-http message is received, thus introducing an unnecessary and unintuitive order dependency in servers that service both http and websocket requests. This change results in the plans optimistically pushing websocket frames through the pipeline if received.