diff --git a/akka-docs/rst/java/code/docs/http/javadsl/server/WebsocketCoreExample.java b/akka-docs/rst/java/code/docs/http/javadsl/server/WebSocketCoreExample.java similarity index 95% rename from akka-docs/rst/java/code/docs/http/javadsl/server/WebsocketCoreExample.java rename to akka-docs/rst/java/code/docs/http/javadsl/server/WebSocketCoreExample.java index 97c1499c82..2b162a70d9 100644 --- a/akka-docs/rst/java/code/docs/http/javadsl/server/WebsocketCoreExample.java +++ b/akka-docs/rst/java/code/docs/http/javadsl/server/WebSocketCoreExample.java @@ -30,15 +30,15 @@ import akka.http.javadsl.model.HttpRequest; import akka.http.javadsl.model.HttpResponse; import akka.http.javadsl.model.ws.Message; import akka.http.javadsl.model.ws.TextMessage; -import akka.http.javadsl.model.ws.Websocket; +import akka.http.javadsl.model.ws.WebSocket; -public class WebsocketCoreExample { +public class WebSocketCoreExample { //#websocket-handling public static HttpResponse handleRequest(HttpRequest request) { System.out.println("Handling request to " + request.getUri()); if (request.getUri().path().equals("/greeter")) - return Websocket.handleWebsocketRequestWith(request, greeter()); + return WebSocket.handleWebSocketRequestWith(request, greeter()); else return HttpResponse.create().withStatus(404); } diff --git a/akka-docs/rst/java/code/docs/http/javadsl/server/WebsocketRoutingExample.java b/akka-docs/rst/java/code/docs/http/javadsl/server/WebSocketRoutingExample.java similarity index 94% rename from akka-docs/rst/java/code/docs/http/javadsl/server/WebsocketRoutingExample.java rename to akka-docs/rst/java/code/docs/http/javadsl/server/WebSocketRoutingExample.java index 343168491a..6d346598ec 100644 --- a/akka-docs/rst/java/code/docs/http/javadsl/server/WebsocketRoutingExample.java +++ b/akka-docs/rst/java/code/docs/http/javadsl/server/WebSocketRoutingExample.java @@ -16,13 +16,13 @@ import akka.http.javadsl.model.ws.TextMessage; import akka.http.javadsl.server.HttpApp; -public class WebsocketRoutingExample extends HttpApp { +public class WebSocketRoutingExample extends HttpApp { //#websocket-route @Override public Route createRoute() { return path("greeter").route( - handleWebsocketMessages(greeter()) + handleWebSocketMessages(greeter()) ); } //#websocket-route diff --git a/akka-docs/rst/java/http/routing-dsl/directives/index.rst b/akka-docs/rst/java/http/routing-dsl/directives/index.rst index 5d9f2f893d..5bcb199c6e 100644 --- a/akka-docs/rst/java/http/routing-dsl/directives/index.rst +++ b/akka-docs/rst/java/http/routing-dsl/directives/index.rst @@ -55,8 +55,8 @@ RangeDirectives SchemeDirectives Contains a single directive ``scheme`` to filter requests based on the URI scheme (http vs. https). -WebsocketDirectives - Contains directives to support answering Websocket requests. +WebSocketDirectives + Contains directives to support answering WebSocket requests. TODO this page should be rewritten as the corresponding Scala page diff --git a/akka-docs/rst/java/http/server-side/low-level-server-side-api.rst b/akka-docs/rst/java/http/server-side/low-level-server-side-api.rst index 015d7b9e30..845724d37a 100644 --- a/akka-docs/rst/java/http/server-side/low-level-server-side-api.rst +++ b/akka-docs/rst/java/http/server-side/low-level-server-side-api.rst @@ -12,7 +12,7 @@ It sports the following features: - Full support for `HTTP pipelining`_ - Full support for asynchronous HTTP streaming including "chunked" transfer encoding accessible through an idiomatic API - Optional SSL/TLS encryption -- Websocket support +- WebSocket support .. _HTTP persistent connections: http://en.wikipedia.org/wiki/HTTP_persistent_connection .. _HTTP pipelining: http://en.wikipedia.org/wiki/HTTP_pipelining diff --git a/akka-docs/rst/java/http/server-side/websocket-support.rst b/akka-docs/rst/java/http/server-side/websocket-support.rst index a0902c0dbc..d595905a95 100644 --- a/akka-docs/rst/java/http/server-side/websocket-support.rst +++ b/akka-docs/rst/java/http/server-side/websocket-support.rst @@ -52,20 +52,20 @@ a streaming message from an Akka Stream source. Server API ---------- -The entrypoint for the Websocket API is the synthetic ``UpgradeToWebsocket`` header which is added to a request -if Akka HTTP encounters a Websocket upgrade request. +The entrypoint for the WebSocket API is the synthetic ``UpgradeToWebSocket`` header which is added to a request +if Akka HTTP encounters a WebSocket upgrade request. -The Websocket specification mandates that details of the Websocket connection are negotiated by placing special-purpose +The WebSocket specification mandates that details of the WebSocket connection are negotiated by placing special-purpose HTTP-headers into request and response of the HTTP upgrade. In Akka HTTP these HTTP-level details of the WebSocket handshake are hidden from the application and don't need to be managed manually. -Instead, the synthetic ``UpgradeToWebsocket`` represents a valid Websocket upgrade request. An application can detect -a Websocket upgrade request by looking for the ``UpgradeToWebsocket`` header. It can choose to accept the upgrade and -start a Websocket connection by responding to that request with an ``HttpResponse`` generated by one of the -``UpgradeToWebsocket.handleMessagesWith`` methods. In its most general form this method expects two arguments: -first, a handler ``Flow`` that will be used to handle Websocket messages on this connection. +Instead, the synthetic ``UpgradeToWebSocket`` represents a valid WebSocket upgrade request. An application can detect +a WebSocket upgrade request by looking for the ``UpgradeToWebSocket`` header. It can choose to accept the upgrade and +start a WebSocket connection by responding to that request with an ``HttpResponse`` generated by one of the +``UpgradeToWebSocket.handleMessagesWith`` methods. In its most general form this method expects two arguments: +first, a handler ``Flow`` that will be used to handle WebSocket messages on this connection. Second, the application can optionally choose one of the proposed application-level sub-protocols by inspecting the -values of ``UpgradeToWebsocket.getRequestedProtocols`` and pass the chosen protocol value to ``handleMessagesWith``. +values of ``UpgradeToWebSocket.getRequestedProtocols`` and pass the chosen protocol value to ``handleMessagesWith``. Handling Messages +++++++++++++++++ @@ -76,7 +76,7 @@ scenarios this fits very well and such a ``Flow`` can be constructed from a simp There are other use-cases, e.g. in a server-push model, where a server message is sent spontaneously, or in a true bi-directional scenario where input and output aren't logically connected. Providing the handler as a ``Flow`` in -these cases may not fit. An overload of ``UpgradeToWebsocket.handleMessagesWith`` is provided, instead, +these cases may not fit. An overload of ``UpgradeToWebSocket.handleMessagesWith`` is provided, instead, which allows to pass an output-generating ``Source`` and an input-receiving ``Sink`` independently. Note that a handler is required to consume the data stream of each message to make place for new messages. Otherwise, @@ -87,40 +87,40 @@ Example Let's look at an example_. -Websocket requests come in like any other requests. In the example, requests to ``/greeter`` are expected to be -Websocket requests: +WebSocket requests come in like any other requests. In the example, requests to ``/greeter`` are expected to be +WebSocket requests: -.. includecode:: ../../code/docs/http/javadsl/server/WebsocketCoreExample.java +.. includecode:: ../../code/docs/http/javadsl/server/WebSocketCoreExample.java :include: websocket-handling -It uses a helper method ``akka.http.javadsl.model.ws.Websocket.handleWebsocketRequestWith`` which can be used if -only Websocket requests are expected. The method looks for the ``UpgradeToWebsocket`` header and returns a response -that will install the passed Websocket handler if the header is found. If the request is no Websocket request it will +It uses a helper method ``akka.http.javadsl.model.ws.WebSocket.handleWebSocketRequestWith`` which can be used if +only WebSocket requests are expected. The method looks for the ``UpgradeToWebSocket`` header and returns a response +that will install the passed WebSocket handler if the header is found. If the request is no WebSocket request it will return a ``400 Bad Request`` error response. In the example, the passed handler expects text messages where each message is expected to contain (a person's) name and then responds with another text message that contains a greeting: -.. includecode:: ../../code/docs/http/javadsl/server/WebsocketCoreExample.java +.. includecode:: ../../code/docs/http/javadsl/server/WebSocketCoreExample.java :include: websocket-handler Routing support --------------- -The routing DSL provides the ``handleWebsocketMessages`` directive to install a WebSocket handler if a request +The routing DSL provides the ``handleWebSocketMessages`` directive to install a WebSocket handler if a request is a WebSocket request. Otherwise, the directive rejects the request. Let's look at how the above example can be rewritten using the high-level routing DSL. Instead of writing the request handler manually, the routing behavior of the app is defined by a route that -uses the ``handleWebsocketRequests`` directive in place of the ``Websocket.handleWebsocketRequestWith``: +uses the ``handleWebSocketRequests`` directive in place of the ``WebSocket.handleWebSocketRequestWith``: -.. includecode:: ../../code/docs/http/javadsl/server/WebsocketRoutingExample.java +.. includecode:: ../../code/docs/http/javadsl/server/WebSocketRoutingExample.java :include: websocket-route The handling code itself will be the same as with using the low-level API. See the `full routing example`_. -.. _example: @github@/akka-docs-dev/rst/java/code/docs/http/javadsl/server/WebsocketCoreExample.java -.. _full routing example: @github@/akka-docs-dev/rst/java/code/docs/http/javadsl/server/WebsocketRoutingExample.java \ No newline at end of file +.. _example: @github@/akka-docs-dev/rst/java/code/docs/http/javadsl/server/WebSocketCoreExample.java +.. _full routing example: @github@/akka-docs-dev/rst/java/code/docs/http/javadsl/server/WebSocketRoutingExample.java \ No newline at end of file diff --git a/akka-docs/rst/scala/code/docs/http/scaladsl/server/WebsocketExampleSpec.scala b/akka-docs/rst/scala/code/docs/http/scaladsl/server/WebSocketExampleSpec.scala similarity index 92% rename from akka-docs/rst/scala/code/docs/http/scaladsl/server/WebsocketExampleSpec.scala rename to akka-docs/rst/scala/code/docs/http/scaladsl/server/WebSocketExampleSpec.scala index 49934db185..f9b41b041b 100644 --- a/akka-docs/rst/scala/code/docs/http/scaladsl/server/WebsocketExampleSpec.scala +++ b/akka-docs/rst/scala/code/docs/http/scaladsl/server/WebSocketExampleSpec.scala @@ -8,7 +8,7 @@ import akka.http.scaladsl.model.ws.BinaryMessage import akka.stream.scaladsl.Sink import org.scalatest.{ Matchers, WordSpec } -class WebsocketExampleSpec extends WordSpec with Matchers { +class WebSocketExampleSpec extends WordSpec with Matchers { "core-example" in { pending // compile-time only test //#websocket-example-using-core @@ -16,7 +16,7 @@ class WebsocketExampleSpec extends WordSpec with Matchers { import akka.stream.ActorMaterializer import akka.stream.scaladsl.{ Source, Flow } import akka.http.scaladsl.Http - import akka.http.scaladsl.model.ws.UpgradeToWebsocket + import akka.http.scaladsl.model.ws.UpgradeToWebSocket import akka.http.scaladsl.model.ws.{ TextMessage, Message } import akka.http.scaladsl.model.{ HttpResponse, Uri, HttpRequest } import akka.http.scaladsl.model.HttpMethods._ @@ -27,7 +27,7 @@ class WebsocketExampleSpec extends WordSpec with Matchers { //#websocket-handler // The Greeter WebSocket Service expects a "name" per message and // returns a greeting message for that name - val greeterWebsocketService = + val greeterWebSocketService = Flow[Message] .mapConcat { // we match but don't actually consume the text message here, @@ -45,8 +45,8 @@ class WebsocketExampleSpec extends WordSpec with Matchers { //#websocket-request-handling val requestHandler: HttpRequest ⇒ HttpResponse = { case req @ HttpRequest(GET, Uri.Path("/greeter"), _, _, _) ⇒ - req.header[UpgradeToWebsocket] match { - case Some(upgrade) ⇒ upgrade.handleMessages(greeterWebsocketService) + req.header[UpgradeToWebSocket] match { + case Some(upgrade) ⇒ upgrade.handleMessages(greeterWebSocketService) case None ⇒ HttpResponse(400, entity = "Not a valid websocket request!") } case _: HttpRequest ⇒ HttpResponse(404, entity = "Unknown resource!") @@ -80,7 +80,7 @@ class WebsocketExampleSpec extends WordSpec with Matchers { // The Greeter WebSocket Service expects a "name" per message and // returns a greeting message for that name - val greeterWebsocketService = + val greeterWebSocketService = Flow[Message] .collect { case tm: TextMessage ⇒ TextMessage(Source.single("Hello ") ++ tm.textStream) @@ -91,7 +91,7 @@ class WebsocketExampleSpec extends WordSpec with Matchers { val route = path("greeter") { get { - handleWebsocketMessages(greeterWebsocketService) + handleWebSocketMessages(greeterWebSocketService) } } //#websocket-routing diff --git a/akka-docs/rst/scala/code/docs/http/scaladsl/server/directives/WebsocketDirectivesExamplesSpec.scala b/akka-docs/rst/scala/code/docs/http/scaladsl/server/directives/WebSocketDirectivesExamplesSpec.scala similarity index 86% rename from akka-docs/rst/scala/code/docs/http/scaladsl/server/directives/WebsocketDirectivesExamplesSpec.scala rename to akka-docs/rst/scala/code/docs/http/scaladsl/server/directives/WebSocketDirectivesExamplesSpec.scala index 881baeeed0..15acb85be4 100644 --- a/akka-docs/rst/scala/code/docs/http/scaladsl/server/directives/WebsocketDirectivesExamplesSpec.scala +++ b/akka-docs/rst/scala/code/docs/http/scaladsl/server/directives/WebSocketDirectivesExamplesSpec.scala @@ -15,7 +15,7 @@ import docs.http.scaladsl.server.RoutingSpec import akka.http.scaladsl.model.ws.{ TextMessage, Message, BinaryMessage } import akka.http.scaladsl.testkit.WSProbe -class WebsocketDirectivesExamplesSpec extends RoutingSpec { +class WebSocketDirectivesExamplesSpec extends RoutingSpec { "greeter-service" in { def greeter: Flow[Message, Message, Any] = Flow[Message].mapConcat { @@ -28,18 +28,18 @@ class WebsocketDirectivesExamplesSpec extends RoutingSpec { } val websocketRoute = path("greeter") { - handleWebsocketMessages(greeter) + handleWebSocketMessages(greeter) } // tests: // create a testing probe representing the client-side val wsClient = WSProbe() - // WS creates a Websocket request for testing + // WS creates a WebSocket request for testing WS("/greeter", wsClient.flow) ~> websocketRoute ~> check { // check response for WS Upgrade headers - isWebsocketUpgrade shouldEqual true + isWebSocketUpgrade shouldEqual true // manually run a WS conversation wsClient.sendMessage("Peter") @@ -74,18 +74,18 @@ class WebsocketDirectivesExamplesSpec extends RoutingSpec { def websocketMultipleProtocolRoute = path("services") { - handleWebsocketMessagesForProtocol(greeterService, "greeter") ~ - handleWebsocketMessagesForProtocol(echoService, "echo") + handleWebSocketMessagesForProtocol(greeterService, "greeter") ~ + handleWebSocketMessagesForProtocol(echoService, "echo") } // tests: val wsClient = WSProbe() - // WS creates a Websocket request for testing + // WS creates a WebSocket request for testing WS("/services", wsClient.flow, List("other", "echo")) ~> websocketMultipleProtocolRoute ~> check { - expectWebsocketUpgradeWithProtocol { protocol ⇒ + expectWebSocketUpgradeWithProtocol { protocol ⇒ protocol shouldEqual "echo" wsClient.sendMessage("Peter") diff --git a/akka-docs/rst/scala/http/low-level-server-side-api.rst b/akka-docs/rst/scala/http/low-level-server-side-api.rst index 8c132a6350..f52aa7f4ef 100644 --- a/akka-docs/rst/scala/http/low-level-server-side-api.rst +++ b/akka-docs/rst/scala/http/low-level-server-side-api.rst @@ -12,7 +12,7 @@ It sports the following features: - Full support for `HTTP pipelining`_ - Full support for asynchronous HTTP streaming including "chunked" transfer encoding accessible through an idiomatic API - Optional SSL/TLS encryption -- Websocket support +- WebSocket support .. _HTTP persistent connections: http://en.wikipedia.org/wiki/HTTP_persistent_connection .. _HTTP pipelining: http://en.wikipedia.org/wiki/HTTP_pipelining diff --git a/akka-docs/rst/scala/http/routing-dsl/directives/alphabetically.rst b/akka-docs/rst/scala/http/routing-dsl/directives/alphabetically.rst index 10f2055570..07654b87b6 100644 --- a/akka-docs/rst/scala/http/routing-dsl/directives/alphabetically.rst +++ b/akka-docs/rst/scala/http/routing-dsl/directives/alphabetically.rst @@ -86,11 +86,11 @@ Directive Description given ``ExceptionHandler`` :ref:`-handleRejections-` Transforms rejections produced by the inner route using the given ``RejectionHandler`` -:ref:`-handleWebsocketMessages-` Handles websocket requests with the given handler and rejects other requests - with an ``ExpectedWebsocketRequestRejection`` -:ref:`-handleWebsocketMessagesForProtocol-` Handles websocket requests with the given handler if the subprotocol matches - and rejects other requests with an ``ExpectedWebsocketRequestRejection`` or - an ``UnsupportedWebsocketSubprotocolRejection``. +:ref:`-handleWebSocketMessages-` Handles websocket requests with the given handler and rejects other requests + with an ``ExpectedWebSocketRequestRejection`` +:ref:`-handleWebSocketMessagesForProtocol-` Handles websocket requests with the given handler if the subprotocol matches + and rejects other requests with an ``ExpectedWebSocketRequestRejection`` or + an ``UnsupportedWebSocketSubprotocolRejection``. :ref:`-handleWith-` Completes the request using a given function :ref:`-head-` Rejects all non-HEAD requests :ref:`-headerValue-` Extracts an HTTP header value using a given ``HttpHeader ⇒ Option[T]`` diff --git a/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebsocketMessages.rst b/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebSocketMessages.rst similarity index 50% rename from akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebsocketMessages.rst rename to akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebSocketMessages.rst index 9a94b83951..517a21cff3 100644 --- a/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebsocketMessages.rst +++ b/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebSocketMessages.rst @@ -1,27 +1,27 @@ -.. _-handleWebsocketMessages-: +.. _-handleWebSocketMessages-: -handleWebsocketMessages +handleWebSocketMessages ======================= Signature --------- -.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebsocketDirectives.scala - :snippet: handleWebsocketMessages +.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebSocketDirectives.scala + :snippet: handleWebSocketMessages Description ----------- -The directive first checks if the request was a valid Websocket handshake request and if yes, it completes the request -with the passed handler. Otherwise, the request is rejected with an ``ExpectedWebsocketRequestRejection``. +The directive first checks if the request was a valid WebSocket handshake request and if yes, it completes the request +with the passed handler. Otherwise, the request is rejected with an ``ExpectedWebSocketRequestRejection``. -Websocket subprotocols offered in the ``Sec-Websocket-Protocol`` header of the request are ignored. If you want to -support several protocols use the :ref:`-handleWebsocketMessagesForProtocol-` directive, instead. +WebSocket subprotocols offered in the ``Sec-WebSocket-Protocol`` header of the request are ignored. If you want to +support several protocols use the :ref:`-handleWebSocketMessagesForProtocol-` directive, instead. -For more information about the Websocket support, see :ref:`server-side-websocket-support-scala`. +For more information about the WebSocket support, see :ref:`server-side-websocket-support-scala`. Example ------- -.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/WebsocketDirectivesExamplesSpec.scala +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/WebSocketDirectivesExamplesSpec.scala :snippet: greeter-service diff --git a/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebSocketMessagesForProtocol.rst b/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebSocketMessagesForProtocol.rst new file mode 100644 index 0000000000..4fd55bd88e --- /dev/null +++ b/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebSocketMessagesForProtocol.rst @@ -0,0 +1,31 @@ +.. _-handleWebSocketMessagesForProtocol-: + +handleWebSocketMessagesForProtocol +================================== + +Signature +--------- + +.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebSocketDirectives.scala + :snippet: handleWebSocketMessagesForProtocol + +Description +----------- +Handles WebSocket requests with the given handler if the given subprotocol is offered in the ``Sec-WebSocket-Protocol`` +header of the request and rejects other requests with an ``ExpectedWebSocketRequestRejection`` or an +``UnsupportedWebSocketSubprotocolRejection``. + +The directive first checks if the request was a valid WebSocket handshake request and if the request offers the passed +subprotocol name. If yes, the directive completes the request with the passed handler. Otherwise, the request is +either rejected with an ``ExpectedWebSocketRequestRejection`` or an ``UnsupportedWebSocketSubprotocolRejection``. + +To support several subprotocols, for example at the same path, several instances of ``handleWebSocketMessagesForProtocol`` can +be chained using ``~`` as you can see in the below example. + +For more information about the WebSocket support, see :ref:`server-side-websocket-support-scala`. + +Example +------- + +.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/WebSocketDirectivesExamplesSpec.scala + :snippet: handle-multiple-protocols diff --git a/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebsocketMessagesForProtocol.rst b/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebsocketMessagesForProtocol.rst deleted file mode 100644 index 254761dfc2..0000000000 --- a/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/handleWebsocketMessagesForProtocol.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. _-handleWebsocketMessagesForProtocol-: - -handleWebsocketMessagesForProtocol -================================== - -Signature ---------- - -.. includecode2:: /../../akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebsocketDirectives.scala - :snippet: handleWebsocketMessagesForProtocol - -Description ------------ -Handles Websocket requests with the given handler if the given subprotocol is offered in the ``Sec-Websocket-Protocol`` -header of the request and rejects other requests with an ``ExpectedWebsocketRequestRejection`` or an -``UnsupportedWebsocketSubprotocolRejection``. - -The directive first checks if the request was a valid Websocket handshake request and if the request offers the passed -subprotocol name. If yes, the directive completes the request with the passed handler. Otherwise, the request is -either rejected with an ``ExpectedWebsocketRequestRejection`` or an ``UnsupportedWebsocketSubprotocolRejection``. - -To support several subprotocols, for example at the same path, several instances of ``handleWebsocketMessagesForProtocol`` can -be chained using ``~`` as you can see in the below example. - -For more information about the Websocket support, see :ref:`server-side-websocket-support-scala`. - -Example -------- - -.. includecode2:: ../../../../code/docs/http/scaladsl/server/directives/WebsocketDirectivesExamplesSpec.scala - :snippet: handle-multiple-protocols diff --git a/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/index.rst b/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/index.rst index 82920ed198..06113c1bfd 100644 --- a/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/index.rst +++ b/akka-docs/rst/scala/http/routing-dsl/directives/websocket-directives/index.rst @@ -1,10 +1,10 @@ -.. _WebsocketDirectives: +.. _WebSocketDirectives: -WebsocketDirectives +WebSocketDirectives =================== .. toctree:: :maxdepth: 1 - handleWebsocketMessages - handleWebsocketMessagesForProtocol \ No newline at end of file + handleWebSocketMessages + handleWebSocketMessagesForProtocol \ No newline at end of file diff --git a/akka-docs/rst/scala/http/routing-dsl/websocket-support.rst b/akka-docs/rst/scala/http/routing-dsl/websocket-support.rst index 547123c29c..2748a0fdb4 100644 --- a/akka-docs/rst/scala/http/routing-dsl/websocket-support.rst +++ b/akka-docs/rst/scala/http/routing-dsl/websocket-support.rst @@ -44,20 +44,20 @@ to create a streaming message from an Akka Stream source. Server API ---------- -The entrypoint for the Websocket API is the synthetic ``UpgradeToWebsocket`` header which is added to a request -if Akka HTTP encounters a Websocket upgrade request. +The entrypoint for the WebSocket API is the synthetic ``UpgradeToWebSocket`` header which is added to a request +if Akka HTTP encounters a WebSocket upgrade request. -The Websocket specification mandates that details of the Websocket connection are negotiated by placing special-purpose +The WebSocket specification mandates that details of the WebSocket connection are negotiated by placing special-purpose HTTP-headers into request and response of the HTTP upgrade. In Akka HTTP these HTTP-level details of the WebSocket handshake are hidden from the application and don't need to be managed manually. -Instead, the synthetic ``UpgradeToWebsocket`` represents a valid Websocket upgrade request. An application can detect -a Websocket upgrade request by looking for the ``UpgradeToWebsocket`` header. It can choose to accept the upgrade and -start a Websocket connection by responding to that request with an ``HttpResponse`` generated by one of the -``UpgradeToWebsocket.handleMessagesWith`` methods. In its most general form this method expects two arguments: -first, a handler ``Flow[Message, Message, Any]`` that will be used to handle Websocket messages on this connection. +Instead, the synthetic ``UpgradeToWebSocket`` represents a valid WebSocket upgrade request. An application can detect +a WebSocket upgrade request by looking for the ``UpgradeToWebSocket`` header. It can choose to accept the upgrade and +start a WebSocket connection by responding to that request with an ``HttpResponse`` generated by one of the +``UpgradeToWebSocket.handleMessagesWith`` methods. In its most general form this method expects two arguments: +first, a handler ``Flow[Message, Message, Any]`` that will be used to handle WebSocket messages on this connection. Second, the application can optionally choose one of the proposed application-level sub-protocols by inspecting the -values of ``UpgradeToWebsocket.requestedProtocols`` and pass the chosen protocol value to ``handleMessages``. +values of ``UpgradeToWebSocket.requestedProtocols`` and pass the chosen protocol value to ``handleMessages``. Handling Messages +++++++++++++++++ @@ -68,7 +68,7 @@ scenarios this fits very well and such a ``Flow`` can be constructed from a simp There are other use-cases, e.g. in a server-push model, where a server message is sent spontaneously, or in a true bi-directional scenario where input and output aren't logically connected. Providing the handler as a ``Flow`` in -these cases may not fit. Another method, ``UpgradeToWebsocket.handleMessagesWithSinkSource``, is provided +these cases may not fit. Another method, ``UpgradeToWebSocket.handleMessagesWithSinkSource``, is provided which allows to pass an output-generating ``Source[Message, Any]`` and an input-receiving ``Sink[Message, Any]`` independently. Note that a handler is required to consume the data stream of each message to make place for new messages. Otherwise, @@ -79,36 +79,36 @@ Example Let's look at an example_. -Websocket requests come in like any other requests. In the example, requests to ``/greeter`` are expected to be -Websocket requests: +WebSocket requests come in like any other requests. In the example, requests to ``/greeter`` are expected to be +WebSocket requests: -.. includecode:: ../../code/docs/http/scaladsl/server/WebsocketExampleSpec.scala +.. includecode:: ../../code/docs/http/scaladsl/server/WebSocketExampleSpec.scala :include: websocket-request-handling -It uses pattern matching on the path and then inspects the request to query for the ``UpgradeToWebsocket`` header. If -such a header is found, it is used to generate a response by passing a handler for Websocket messages to the +It uses pattern matching on the path and then inspects the request to query for the ``UpgradeToWebSocket`` header. If +such a header is found, it is used to generate a response by passing a handler for WebSocket messages to the ``handleMessages`` method. If no such header is found a "400 Bad Request" response is generated. The passed handler expects text messages where each message is expected to contain (a person's) name and then responds with another text message that contains a greeting: -.. includecode:: ../../code/docs/http/scaladsl/server/WebsocketExampleSpec.scala +.. includecode:: ../../code/docs/http/scaladsl/server/WebSocketExampleSpec.scala :include: websocket-handler Routing support --------------- -The routing DSL provides the :ref:`-handleWebsocketMessages-` directive to install a WebSocket handler if the request +The routing DSL provides the :ref:`-handleWebSocketMessages-` directive to install a WebSocket handler if the request was a WebSocket request. Otherwise, the directive rejects the request. Here's the above simple request handler rewritten as a route: -.. includecode2:: ../../code/docs/http/scaladsl/server/directives/WebsocketDirectivesExamplesSpec.scala +.. includecode2:: ../../code/docs/http/scaladsl/server/directives/WebSocketDirectivesExamplesSpec.scala :snippet: greeter-service -The example also includes code demonstrating the testkit support for Websocket services. It allows to create Websocket -requests to run against a route using `WS` which can be used to provide a mock Websocket probe that allows manual -testing of the Websocket handler's behavior if the request was accepted. +The example also includes code demonstrating the testkit support for WebSocket services. It allows to create WebSocket +requests to run against a route using `WS` which can be used to provide a mock WebSocket probe that allows manual +testing of the WebSocket handler's behavior if the request was accepted. -.. _example: @github@/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/WebsocketExampleSpec.scala +.. _example: @github@/akka-docs-dev/rst/scala/code/docs/http/scaladsl/server/WebSocketExampleSpec.scala diff --git a/akka-http-core/RunWebsocketAutobahnTestSuite.md b/akka-http-core/RunWebSocketAutobahnTestSuite.md similarity index 100% rename from akka-http-core/RunWebsocketAutobahnTestSuite.md rename to akka-http-core/RunWebSocketAutobahnTestSuite.md diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/rendering/HttpResponseRendererFactory.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/rendering/HttpResponseRendererFactory.scala index fe3cda7374..846b950181 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/rendering/HttpResponseRendererFactory.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/rendering/HttpResponseRendererFactory.scala @@ -5,7 +5,7 @@ package akka.http.impl.engine.rendering import akka.NotUsed -import akka.http.impl.engine.ws.{ FrameEvent, UpgradeToWebsocketResponseHeader } +import akka.http.impl.engine.ws.{ FrameEvent, UpgradeToWebSocketResponseHeader } import akka.http.scaladsl.model.ws.Message import akka.stream.{ Outlet, Inlet, Attributes, FlowShape, Graph } @@ -63,10 +63,10 @@ private[http] class HttpResponseRendererFactory(serverHeader: Option[headers.Ser def createLogic(inheritedAttributes: Attributes): GraphStageLogic = new GraphStageLogic(shape) { - var closeMode: CloseMode = DontClose // signals what to do after the current response - def close: Boolean = closeMode != DontClose - def closeIf(cond: Boolean): Unit = if (cond) closeMode = CloseConnection - var transferring = false + private[this] var closeMode: CloseMode = DontClose // signals what to do after the current response + private[this] def close: Boolean = closeMode != DontClose + private[this] def closeIf(cond: Boolean): Unit = + if (cond) closeMode = CloseConnection setHandler(in, new InHandler { override def onPush(): Unit = @@ -205,8 +205,8 @@ private[http] class HttpResponseRendererFactory(serverHeader: Option[headers.Ser else if (connHeader != null && connHeader.hasUpgrade) { r ~~ connHeader ~~ CrLf headers - .collectFirst { case u: UpgradeToWebsocketResponseHeader ⇒ u } - .foreach { header ⇒ closeMode = SwitchToWebsocket(header.handler) } + .collectFirst { case u: UpgradeToWebSocketResponseHeader ⇒ u } + .foreach { header ⇒ closeMode = SwitchToWebSocket(header.handler) } } if (mustRenderTransferEncodingChunkedHeader && !transferEncodingSeen) r ~~ `Transfer-Encoding` ~~ ChunkedBytes ~~ CrLf @@ -229,7 +229,7 @@ private[http] class HttpResponseRendererFactory(serverHeader: Option[headers.Ser Strict { closeMode match { - case SwitchToWebsocket(handler) ⇒ ResponseRenderingOutput.SwitchToWebsocket(r.get, handler) + case SwitchToWebSocket(handler) ⇒ ResponseRenderingOutput.SwitchToWebSocket(r.get, handler) case _ ⇒ ResponseRenderingOutput.HttpData(r.get) } } @@ -268,7 +268,7 @@ private[http] class HttpResponseRendererFactory(serverHeader: Option[headers.Ser sealed trait CloseMode case object DontClose extends CloseMode case object CloseConnection extends CloseMode - case class SwitchToWebsocket(handler: Either[Graph[FlowShape[FrameEvent, FrameEvent], Any], Graph[FlowShape[Message, Message], Any]]) extends CloseMode + case class SwitchToWebSocket(handler: Either[Graph[FlowShape[FrameEvent, FrameEvent], Any], Graph[FlowShape[Message, Message], Any]]) extends CloseMode } /** @@ -285,5 +285,5 @@ private[http] sealed trait ResponseRenderingOutput /** INTERNAL API */ private[http] object ResponseRenderingOutput { private[http] case class HttpData(bytes: ByteString) extends ResponseRenderingOutput - private[http] case class SwitchToWebsocket(httpResponseBytes: ByteString, handler: Either[Graph[FlowShape[FrameEvent, FrameEvent], Any], Graph[FlowShape[Message, Message], Any]]) extends ResponseRenderingOutput + private[http] case class SwitchToWebSocket(httpResponseBytes: ByteString, handler: Either[Graph[FlowShape[FrameEvent, FrameEvent], Any], Graph[FlowShape[Message, Message], Any]]) extends ResponseRenderingOutput } diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/server/HttpServerBluePrint.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/server/HttpServerBluePrint.scala index f03a6e5ecd..90b2dc2a2c 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/server/HttpServerBluePrint.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/server/HttpServerBluePrint.scala @@ -491,11 +491,11 @@ private[http] object HttpServerBluePrint { override def onPush(): Unit = grab(fromHttp) match { case HttpData(b) ⇒ push(toNet, b) - case SwitchToWebsocket(bytes, handlerFlow) ⇒ + case SwitchToWebSocket(bytes, handlerFlow) ⇒ push(toNet, bytes) complete(toHttp) cancel(fromHttp) - switchToWebsocket(handlerFlow) + switchToWebSocket(handlerFlow) } override def onUpstreamFinish(): Unit = complete(toNet) override def onUpstreamFailure(ex: Throwable): Unit = fail(toNet, ex) @@ -536,13 +536,13 @@ private[http] object HttpServerBluePrint { } /* - * Websocket support + * WebSocket support */ - def switchToWebsocket(handlerFlow: Either[Graph[FlowShape[FrameEvent, FrameEvent], Any], Graph[FlowShape[Message, Message], Any]]): Unit = { + def switchToWebSocket(handlerFlow: Either[Graph[FlowShape[FrameEvent, FrameEvent], Any], Graph[FlowShape[Message, Message], Any]]): Unit = { val frameHandler = handlerFlow match { case Left(frameHandler) ⇒ frameHandler case Right(messageHandler) ⇒ - Websocket.stack(serverSide = true, maskingRandomFactory = settings.websocketRandomFactory, log = log).join(messageHandler) + WebSocket.stack(serverSide = true, maskingRandomFactory = settings.websocketRandomFactory, log = log).join(messageHandler) } val sinkIn = new SubSinkInlet[ByteString]("FrameSink") @@ -560,7 +560,7 @@ private[http] object HttpServerBluePrint { sinkIn.cancel() } }) - Websocket.framing.join(frameHandler).runWith(Source.empty, sinkIn.sink)(subFusingMaterializer) + WebSocket.framing.join(frameHandler).runWith(Source.empty, sinkIn.sink)(subFusingMaterializer) } else { val sourceOut = new SubSourceOutlet[ByteString]("FrameSource") @@ -596,7 +596,7 @@ private[http] object HttpServerBluePrint { override def onDownstreamFinish(): Unit = cancel(fromNet) }) - Websocket.framing.join(frameHandler).runWith(sourceOut.source, sinkIn.sink)(subFusingMaterializer) + WebSocket.framing.join(frameHandler).runWith(sourceOut.source, sinkIn.sink)(subFusingMaterializer) } } } diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/FrameEvent.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/FrameEvent.scala index c2e0d3045f..e49184f015 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/FrameEvent.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/FrameEvent.scala @@ -12,7 +12,7 @@ private[http] sealed trait FrameEventOrError private[http] final case class FrameError(p: ProtocolException) extends FrameEventOrError /** - * The low-level Websocket framing model. + * The low-level WebSocket framing model. * * INTERNAL API */ diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/FrameEventParser.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/FrameEventParser.scala index eec365cbf8..2e287fb1c8 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/FrameEventParser.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/FrameEventParser.scala @@ -10,7 +10,7 @@ import akka.stream.io.ByteStringParser import akka.stream.Attributes /** - * Streaming parser for the Websocket framing protocol as defined in RFC6455 + * Streaming parser for the WebSocket framing protocol as defined in RFC6455 * * http://tools.ietf.org/html/rfc6455 * diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/FrameOutHandler.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/FrameOutHandler.scala index def70b2db7..70a83f04da 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/FrameOutHandler.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/FrameOutHandler.scala @@ -11,7 +11,7 @@ import scala.concurrent.duration.FiniteDuration import akka.stream.stage._ import akka.http.impl.util.Timestamp import akka.http.impl.engine.ws.FrameHandler._ -import Websocket.Tick +import WebSocket.Tick import akka.http.impl.engine.ws.FrameHandler.UserHandlerErredOut /** @@ -46,7 +46,7 @@ private[http] class FrameOutHandler(serverSide: Boolean, _closeTimeout: FiniteDu become(new WaitingForPeerCloseFrame()) ctx.push(FrameEvent.closeFrame(Protocol.CloseCodes.Regular)) case UserHandlerErredOut(e) ⇒ - log.error(e, s"Websocket handler failed with ${e.getMessage}") + log.error(e, s"WebSocket handler failed with ${e.getMessage}") become(new WaitingForPeerCloseFrame()) ctx.push(FrameEvent.closeFrame(Protocol.CloseCodes.UnexpectedCondition, "internal error")) case Tick ⇒ ctx.pull() // ignore @@ -65,7 +65,7 @@ private[http] class FrameOutHandler(serverSide: Boolean, _closeTimeout: FiniteDu def onPush(elem: AnyRef, ctx: Context[FrameStart]): SyncDirective = elem match { case UserHandlerCompleted ⇒ sendOutLastFrame(ctx) case UserHandlerErredOut(e) ⇒ - log.error(e, s"Websocket handler failed while waiting for handler completion with ${e.getMessage}") + log.error(e, s"WebSocket handler failed while waiting for handler completion with ${e.getMessage}") sendOutLastFrame(ctx) case start: FrameStart ⇒ ctx.push(start) case _ ⇒ ctx.pull() // ignore diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Handshake.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Handshake.scala index 56b63e798c..fc1a48a3d1 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Handshake.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Handshake.scala @@ -10,21 +10,21 @@ import scala.collection.immutable.Seq import scala.reflect.ClassTag import akka.http.impl.util._ import akka.http.scaladsl.model.headers._ -import akka.http.scaladsl.model.ws.{ Message, UpgradeToWebsocket } +import akka.http.scaladsl.model.ws.{ Message, UpgradeToWebSocket } import akka.http.scaladsl.model._ import akka.stream.{ Graph, FlowShape } /** - * Server-side implementation of the Websocket handshake + * Server-side implementation of the WebSocket handshake * * INTERNAL API */ private[http] object Handshake { - val CurrentWebsocketVersion = 13 + val CurrentWebSocketVersion = 13 object Server { /** - * Validates a client Websocket handshake. Returns either `Right(UpgradeToWebsocket)` or + * Validates a client WebSocket handshake. Returns either `Right(UpgradeToWebSocket)` or * `Left(MessageStartError)`. * * From: http://tools.ietf.org/html/rfc6455#section-4.2.1 @@ -62,7 +62,7 @@ private[http] object Handshake { * to speak. The interpretation of this header field is discussed * in Section 9.1. */ - def websocketUpgrade(headers: List[HttpHeader], hostHeaderPresent: Boolean): Option[UpgradeToWebsocket] = { + def websocketUpgrade(headers: List[HttpHeader], hostHeaderPresent: Boolean): Option[UpgradeToWebSocket] = { def find[T <: HttpHeader: ClassTag]: Option[T] = headers.collectFirst { case t: T ⇒ t @@ -83,12 +83,12 @@ private[http] object Handshake { // FIXME See #18709 // val extensions = find[`Sec-WebSocket-Extensions`] - if (upgrade.exists(_.hasWebsocket) && + if (upgrade.exists(_.hasWebSocket) && connection.exists(_.hasUpgrade) && - version.exists(_.hasVersion(CurrentWebsocketVersion)) && + version.exists(_.hasVersion(CurrentWebSocketVersion)) && key.exists(k ⇒ k.isValid)) { - val header = new UpgradeToWebsocketLowLevel { + val header = new UpgradeToWebSocketLowLevel { def requestedProtocols: Seq[String] = clientSupportedSubprotocols def handle(handler: Either[Graph[FlowShape[FrameEvent, FrameEvent], Any], Graph[FlowShape[Message, Message], Any]], subprotocol: Option[String]): HttpResponse = { @@ -134,11 +134,11 @@ private[http] object Handshake { UpgradeHeader, ConnectionUpgradeHeader, `Sec-WebSocket-Accept`.forKey(key), - UpgradeToWebsocketResponseHeader(handler))) + UpgradeToWebSocketResponseHeader(handler))) } object Client { - case class NegotiatedWebsocketSettings(subprotocol: Option[String]) + case class NegotiatedWebSocketSettings(subprotocol: Option[String]) /** * Builds a WebSocket handshake request. @@ -156,7 +156,7 @@ private[http] object Handshake { UpgradeHeader, ConnectionUpgradeHeader, key, - SecWebsocketVersionHeader) ++ protocol ++ extraHeaders + SecWebSocketVersionHeader) ++ protocol ++ extraHeaders (HttpRequest(HttpMethods.GET, uri.toRelative, headers), key) } @@ -165,7 +165,7 @@ private[http] object Handshake { * Tries to validate the HTTP response. Returns either Right(settings) or an error message if * the response cannot be validated. */ - def validateResponse(response: HttpResponse, subprotocols: Seq[String], key: `Sec-WebSocket-Key`): Either[String, NegotiatedWebsocketSettings] = { + def validateResponse(response: HttpResponse, subprotocols: Seq[String], key: `Sec-WebSocket-Key`): Either[String, NegotiatedWebSocketSettings] = { /* From http://tools.ietf.org/html/rfc6455#section-4.1 @@ -249,8 +249,8 @@ private[http] object Handshake { case None ⇒ val subs = response.header[`Sec-WebSocket-Protocol`].flatMap(_.protocols.headOption) - if (subprotocols.isEmpty && subs.isEmpty) Right(NegotiatedWebsocketSettings(None)) // no specific one selected - else if (subs.nonEmpty && subprotocols.contains(subs.get)) Right(NegotiatedWebsocketSettings(Some(subs.get))) + if (subprotocols.isEmpty && subs.isEmpty) Right(NegotiatedWebSocketSettings(None)) // no specific one selected + else if (subs.nonEmpty && subprotocols.contains(subs.get)) Right(NegotiatedWebSocketSettings(Some(subs.get))) else Left(s"response that indicated that the given subprotocol was not supported. (client supported: ${subprotocols.mkString(", ")}, server supported: $subs)") case Some(problem) ⇒ Left(problem) } @@ -259,5 +259,5 @@ private[http] object Handshake { val UpgradeHeader = Upgrade(List(UpgradeProtocol("websocket"))) val ConnectionUpgradeHeader = Connection(List("upgrade")) - val SecWebsocketVersionHeader = `Sec-WebSocket-Version`(Seq(CurrentWebsocketVersion)) + val SecWebSocketVersionHeader = `Sec-WebSocket-Version`(Seq(CurrentWebSocketVersion)) } diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Masking.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Masking.scala index 42802ba643..a56feeeb8e 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Masking.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Masking.scala @@ -11,7 +11,7 @@ import akka.stream.scaladsl.{ Keep, BidiFlow, Flow } import akka.stream.stage.{ SyncDirective, Context, StatefulStage } /** - * Implements Websocket Frame masking. + * Implements WebSocket Frame masking. * * INTERNAL API */ diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Protocol.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Protocol.scala index d6afc7301d..add126cbb4 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Protocol.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Protocol.scala @@ -5,7 +5,7 @@ package akka.http.impl.engine.ws /** - * Contains Websocket protocol constants + * Contains WebSocket protocol constants * * INTERNAL API */ diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/UpgradeToWebsocketLowLevel.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/UpgradeToWebSocketLowLevel.scala similarity index 68% rename from akka-http-core/src/main/scala/akka/http/impl/engine/ws/UpgradeToWebsocketLowLevel.scala rename to akka-http-core/src/main/scala/akka/http/impl/engine/ws/UpgradeToWebSocketLowLevel.scala index 830e42ef4e..b7501ce7e2 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/UpgradeToWebsocketLowLevel.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/UpgradeToWebSocketLowLevel.scala @@ -5,7 +5,7 @@ package akka.http.impl.engine.ws import akka.http.scaladsl.model.HttpResponse -import akka.http.scaladsl.model.ws.UpgradeToWebsocket +import akka.http.scaladsl.model.ws.UpgradeToWebSocket import akka.stream.{ Graph, FlowShape } /** @@ -13,14 +13,14 @@ import akka.stream.{ Graph, FlowShape } * * INTERNAL API */ -private[http] abstract class UpgradeToWebsocketLowLevel extends InternalCustomHeader("UpgradeToWebsocket") with UpgradeToWebsocket { +private[http] abstract class UpgradeToWebSocketLowLevel extends InternalCustomHeader("UpgradeToWebSocket") with UpgradeToWebSocket { /** - * The low-level interface to create Websocket server based on "frames". + * The low-level interface to create WebSocket server based on "frames". * The user needs to handle control frames manually in this case. * * Returns a response to return in a request handler that will signal the - * low-level HTTP implementation to upgrade the connection to Websocket and - * use the supplied handler to handle incoming Websocket frames. + * low-level HTTP implementation to upgrade the connection to WebSocket and + * use the supplied handler to handle incoming WebSocket frames. * * INTERNAL API (for now) */ diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/UpgradeToWebsocketsResponseHeader.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/UpgradeToWebSocketsResponseHeader.scala similarity index 81% rename from akka-http-core/src/main/scala/akka/http/impl/engine/ws/UpgradeToWebsocketsResponseHeader.scala rename to akka-http-core/src/main/scala/akka/http/impl/engine/ws/UpgradeToWebSocketsResponseHeader.scala index e736afaae2..66f2b14b0c 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/UpgradeToWebsocketsResponseHeader.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/UpgradeToWebSocketsResponseHeader.scala @@ -8,8 +8,8 @@ import akka.http.scaladsl.model.headers.CustomHeader import akka.http.scaladsl.model.ws.Message import akka.stream.{ Graph, FlowShape } -private[http] final case class UpgradeToWebsocketResponseHeader(handler: Either[Graph[FlowShape[FrameEvent, FrameEvent], Any], Graph[FlowShape[Message, Message], Any]]) - extends InternalCustomHeader("UpgradeToWebsocketResponseHeader") +private[http] final case class UpgradeToWebSocketResponseHeader(handler: Either[Graph[FlowShape[FrameEvent, FrameEvent], Any], Graph[FlowShape[Message, Message], Any]]) + extends InternalCustomHeader("UpgradeToWebSocketResponseHeader") private[http] abstract class InternalCustomHeader(val name: String) extends CustomHeader { final def renderInRequests = false diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Websocket.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/WebSocket.scala similarity index 99% rename from akka-http-core/src/main/scala/akka/http/impl/engine/ws/Websocket.scala rename to akka-http-core/src/main/scala/akka/http/impl/engine/ws/WebSocket.scala index ce9d3d1604..a084f9742b 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/Websocket.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/WebSocket.scala @@ -20,7 +20,7 @@ import akka.stream.impl.fusing.SubSource * * Defines components of the websocket stack. */ -private[http] object Websocket { +private[http] object WebSocket { import FrameHandler._ /** diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/WebsocketClientBlueprint.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/WebSocketClientBlueprint.scala similarity index 88% rename from akka-http-core/src/main/scala/akka/http/impl/engine/ws/WebsocketClientBlueprint.scala rename to akka-http-core/src/main/scala/akka/http/impl/engine/ws/WebSocketClientBlueprint.scala index 5c205c2bfd..6b8df386b4 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/ws/WebsocketClientBlueprint.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/ws/WebSocketClientBlueprint.scala @@ -26,29 +26,29 @@ import akka.http.impl.engine.parsing.HttpMessageParser.StateResult import akka.http.impl.engine.parsing.ParserOutput.{ RemainingBytes, ResponseStart, NeedMoreData } import akka.http.impl.engine.parsing.{ ParserOutput, HttpHeaderParser, HttpResponseParser } import akka.http.impl.engine.rendering.{ HttpRequestRendererFactory, RequestRenderingContext } -import akka.http.impl.engine.ws.Handshake.Client.NegotiatedWebsocketSettings +import akka.http.impl.engine.ws.Handshake.Client.NegotiatedWebSocketSettings import akka.http.impl.util.StreamUtils -object WebsocketClientBlueprint { +object WebSocketClientBlueprint { /** - * Returns a WebsocketClientLayer that can be materialized once. + * Returns a WebSocketClientLayer that can be materialized once. */ - def apply(request: WebsocketRequest, + def apply(request: WebSocketRequest, settings: ClientConnectionSettings, - log: LoggingAdapter): Http.WebsocketClientLayer = + log: LoggingAdapter): Http.WebSocketClientLayer = (simpleTls.atopMat(handshake(request, settings, log))(Keep.right) atop - Websocket.framing atop - Websocket.stack(serverSide = false, maskingRandomFactory = settings.websocketRandomFactory, log = log)).reversed + WebSocket.framing atop + WebSocket.stack(serverSide = false, maskingRandomFactory = settings.websocketRandomFactory, log = log)).reversed /** * A bidi flow that injects and inspects the WS handshake and then goes out of the way. This BidiFlow * can only be materialized once. */ - def handshake(request: WebsocketRequest, + def handshake(request: WebSocketRequest, settings: ClientConnectionSettings, - log: LoggingAdapter): BidiFlow[ByteString, ByteString, ByteString, ByteString, Future[WebsocketUpgradeResponse]] = { + log: LoggingAdapter): BidiFlow[ByteString, ByteString, ByteString, ByteString, Future[WebSocketUpgradeResponse]] = { import request._ - val result = Promise[WebsocketUpgradeResponse]() + val result = Promise[WebSocketUpgradeResponse]() val valve = StreamUtils.OneTimeValve() @@ -85,7 +85,7 @@ object WebsocketClientBlueprint { case ResponseStart(status, protocol, headers, entity, close) ⇒ val response = HttpResponse(status, headers, protocol = protocol) Handshake.Client.validateResponse(response, subprotocol.toList, key) match { - case Right(NegotiatedWebsocketSettings(protocol)) ⇒ + case Right(NegotiatedWebSocketSettings(protocol)) ⇒ result.success(ValidUpgrade(response, protocol)) become(transparent) @@ -100,8 +100,8 @@ object WebsocketClientBlueprint { throw new IllegalStateException(s"unexpected element of type ${other.getClass}") } case Left(problem) ⇒ - result.success(InvalidUpgradeResponse(response, s"Websocket server at $uri returned $problem")) - ctx.fail(throw new IllegalArgumentException(s"Websocket upgrade did not finish because of '$problem'")) + result.success(InvalidUpgradeResponse(response, s"WebSocket server at $uri returned $problem")) + ctx.fail(throw new IllegalArgumentException(s"WebSocket upgrade did not finish because of '$problem'")) } case other ⇒ throw new IllegalStateException(s"unexpected element of type ${other.getClass}") diff --git a/akka-http-core/src/main/scala/akka/http/impl/model/parser/HeaderParser.scala b/akka-http-core/src/main/scala/akka/http/impl/model/parser/HeaderParser.scala index a84e3e2d7e..c91578e73f 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/model/parser/HeaderParser.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/model/parser/HeaderParser.scala @@ -30,7 +30,7 @@ private[http] class HeaderParser(val input: ParserInput, settings: HeaderParser. with LinkHeader with SimpleHeaders with StringBuilding - with WebsocketHeaders { + with WebSocketHeaders { import CharacterClasses._ // http://www.rfc-editor.org/errata_search.php?rfc=7230 errata id 4189 diff --git a/akka-http-core/src/main/scala/akka/http/impl/model/parser/WebsocketHeaders.scala b/akka-http-core/src/main/scala/akka/http/impl/model/parser/WebSocketHeaders.scala similarity index 93% rename from akka-http-core/src/main/scala/akka/http/impl/model/parser/WebsocketHeaders.scala rename to akka-http-core/src/main/scala/akka/http/impl/model/parser/WebSocketHeaders.scala index ceb3b30254..eec5d2080b 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/model/parser/WebsocketHeaders.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/model/parser/WebSocketHeaders.scala @@ -8,7 +8,7 @@ import akka.http.scaladsl.model.headers._ import akka.parboiled2._ // see grammar at http://tools.ietf.org/html/rfc6455#section-4.3 -private[parser] trait WebsocketHeaders { this: Parser with CommonRules with CommonActions ⇒ +private[parser] trait WebSocketHeaders { this: Parser with CommonRules with CommonActions ⇒ import CharacterClasses._ import Base64Parsing.rfc2045Alphabet @@ -44,7 +44,7 @@ private[parser] trait WebsocketHeaders { this: Parser with CommonRules with Comm private def extension = rule { `extension-token` ~ zeroOrMore(ws(";") ~ `extension-param`) ~> - ((name, params) ⇒ WebsocketExtension(name, Map(params: _*))) + ((name, params) ⇒ WebSocketExtension(name, Map(params: _*))) } private def `extension-token`: Rule1[String] = token private def `extension-param`: Rule1[(String, String)] = diff --git a/akka-http-core/src/main/scala/akka/http/javadsl/Http.scala b/akka-http-core/src/main/scala/akka/http/javadsl/Http.scala index 4cadd43cd5..e977a19e10 100644 --- a/akka-http-core/src/main/scala/akka/http/javadsl/Http.scala +++ b/akka-http-core/src/main/scala/akka/http/javadsl/Http.scala @@ -600,102 +600,120 @@ class Http(system: ExtendedActorSystem) extends akka.actor.Extension { * Fires a single [[HttpRequest]] across the (cached) host connection pool for the request's * effective URI to produce a response future. * - * If an explicit [[HttpsContext]] is given then it rather than the configured default [[HttpsContext]] will be used - * for setting up the HTTPS connection pool, if required. + * The given [[HttpsConnectionContext]] will be used for encruption if the request is sent to an https endpoint. * * Note that the request must have either an absolute URI or a valid `Host` header, otherwise * the future will be completed with an error. */ def singleRequest(request: HttpRequest, + connectionContext: HttpsConnectionContext, settings: ConnectionPoolSettings, - httpsContext: Optional[HttpsContext], log: LoggingAdapter, materializer: Materializer): Future[HttpResponse] = - delegate.singleRequest(request.asScala, settings, httpsContext, log)(materializer) + delegate.singleRequest(request.asScala, connectionContext.asScala, settings, log)(materializer) /** - * Constructs a Websocket [[BidiFlow]]. + * Constructs a WebSocket [[BidiFlow]]. * * The layer is not reusable and must only be materialized once. */ - def websocketClientLayer(request: WebsocketRequest): BidiFlow[Message, SslTlsOutbound, SslTlsInbound, Message, Future[WebsocketUpgradeResponse]] = - adaptWsBidiFlow(delegate.websocketClientLayer(request.asScala)) + def webSocketClientLayer(request: WebSocketRequest): BidiFlow[Message, SslTlsOutbound, SslTlsInbound, Message, Future[WebSocketUpgradeResponse]] = + adaptWsBidiFlow(delegate.webSocketClientLayer(request.asScala)) /** - * Constructs a Websocket [[BidiFlow]] using the configured default [[ClientConnectionSettings]], + * Constructs a WebSocket [[BidiFlow]] using the configured default [[ClientConnectionSettings]], * configured using the `akka.http.client` config section. * * The layer is not reusable and must only be materialized once. */ - def websocketClientLayer(request: WebsocketRequest, - settings: ClientConnectionSettings): BidiFlow[Message, SslTlsOutbound, SslTlsInbound, Message, Future[WebsocketUpgradeResponse]] = - adaptWsBidiFlow(delegate.websocketClientLayer(request.asScala, settings)) + def webSocketClientLayer(request: WebSocketRequest, + settings: ClientConnectionSettings): BidiFlow[Message, SslTlsOutbound, SslTlsInbound, Message, Future[WebSocketUpgradeResponse]] = + adaptWsBidiFlow(delegate.webSocketClientLayer(request.asScala, settings)) /** - * Constructs a Websocket [[BidiFlow]] using the configured default [[ClientConnectionSettings]], + * Constructs a WebSocket [[BidiFlow]] using the configured default [[ClientConnectionSettings]], * configured using the `akka.http.client` config section. * * The layer is not reusable and must only be materialized once. */ - def websocketClientLayer(request: WebsocketRequest, + def webSocketClientLayer(request: WebSocketRequest, settings: ClientConnectionSettings, - log: LoggingAdapter): BidiFlow[Message, SslTlsOutbound, SslTlsInbound, Message, Future[WebsocketUpgradeResponse]] = - adaptWsBidiFlow(delegate.websocketClientLayer(request.asScala, settings, log)) + log: LoggingAdapter): BidiFlow[Message, SslTlsOutbound, SslTlsInbound, Message, Future[WebSocketUpgradeResponse]] = + adaptWsBidiFlow(delegate.webSocketClientLayer(request.asScala, settings, log)) /** - * Constructs a flow that once materialized establishes a Websocket connection to the given Uri. + * Constructs a flow that once materialized establishes a WebSocket connection to the given Uri. * * The layer is not reusable and must only be materialized once. */ - def websocketClientFlow(request: WebsocketRequest): Flow[Message, Message, Future[WebsocketUpgradeResponse]] = + def webSocketClientFlow(request: WebSocketRequest): Flow[Message, Message, Future[WebSocketUpgradeResponse]] = adaptWsFlow { - delegate.websocketClientFlow(request.asScala) + delegate.webSocketClientFlow(request.asScala) } /** - * Constructs a flow that once materialized establishes a Websocket connection to the given Uri. + * Constructs a flow that once materialized establishes a WebSocket connection to the given Uri. * * The layer is not reusable and must only be materialized once. */ - def websocketClientFlow(request: WebsocketRequest, + def webSocketClientFlow(request: WebSocketRequest, + connectionContext: HttpsConnectionContext, localAddress: Optional[InetSocketAddress], settings: ClientConnectionSettings, - httpsContext: Optional[HttpsContext], - log: LoggingAdapter): Flow[Message, Message, Future[WebsocketUpgradeResponse]] = + log: LoggingAdapter): Flow[Message, Message, Future[WebSocketUpgradeResponse]] = adaptWsFlow { - delegate.websocketClientFlow(request.asScala, localAddress.asScala, settings, httpsContext, log) + delegate.webSocketClientFlow(request.asScala, connectionContext.asScala, localAddress.asScala, settings, log) } /** - * Runs a single Websocket conversation given a Uri and a flow that represents the client side of the - * Websocket conversation. + * Runs a single WebSocket conversation given a Uri and a flow that represents the client side of the + * WebSocket conversation. + * + * The [[defaultClientHttpsContext]] is used to configure TLS for the connection. */ - def singleWebsocketRequest[T](request: WebsocketRequest, + def singleWebSocketRequest[T](request: WebSocketRequest, clientFlow: Flow[Message, Message, T], - materializer: Materializer): Pair[Future[WebsocketUpgradeResponse], T] = + materializer: Materializer): Pair[Future[WebSocketUpgradeResponse], T] = adaptWsResultTuple { - delegate.singleWebsocketRequest( + delegate.singleWebSocketRequest( request.asScala, adaptWsFlow[T](clientFlow))(materializer) } /** - * Runs a single Websocket conversation given a Uri and a flow that represents the client side of the - * Websocket conversation. + * Runs a single WebSocket conversation given a Uri and a flow that represents the client side of the + * WebSocket conversation. + * + * The [[defaultClientHttpsContext]] is used to configure TLS for the connection. */ - def singleWebsocketRequest[T](request: WebsocketRequest, + def singleWebSocketRequest[T](request: WebSocketRequest, clientFlow: Flow[Message, Message, T], - localAddress: Optional[InetSocketAddress], - settings: ClientConnectionSettings, - httpsContext: Optional[HttpsContext], - log: LoggingAdapter, - materializer: Materializer): Pair[Future[WebsocketUpgradeResponse], T] = + connectionContext: HttpsConnectionContext, + materializer: Materializer): Pair[Future[WebSocketUpgradeResponse], T] = adaptWsResultTuple { - delegate.singleWebsocketRequest( + delegate.singleWebSocketRequest( request.asScala, adaptWsFlow[T](clientFlow), + connectionContext.asScala)(materializer) + } + + /** + * Runs a single WebSocket conversation given a Uri and a flow that represents the client side of the + * WebSocket conversation. + */ + def singleWebSocketRequest[T](request: WebSocketRequest, + clientFlow: Flow[Message, Message, T], + connectionContext: HttpsConnectionContext, + localAddress: Optional[InetSocketAddress], + settings: ClientConnectionSettings, + log: LoggingAdapter, + materializer: Materializer): Pair[Future[WebSocketUpgradeResponse], T] = + adaptWsResultTuple { + delegate.singleWebSocketRequest( + request.asScala, + adaptWsFlow[T](clientFlow), + connectionContext.asScala, localAddress.asScala, settings, - httpsContext, log)(materializer) } @@ -735,12 +753,12 @@ class Http(system: ExtendedActorSystem) extends akka.actor.Extension { JavaMapping.adapterBidiFlow[HttpRequest, sm.HttpRequest, sm.HttpResponse, HttpResponse] .atop(clientLayer)) - private def adaptWsBidiFlow(wsLayer: scaladsl.Http.WebsocketClientLayer): BidiFlow[Message, SslTlsOutbound, SslTlsInbound, Message, Future[WebsocketUpgradeResponse]] = + private def adaptWsBidiFlow(wsLayer: scaladsl.Http.WebSocketClientLayer): BidiFlow[Message, SslTlsOutbound, SslTlsInbound, Message, Future[WebSocketUpgradeResponse]] = new BidiFlow( JavaMapping.adapterBidiFlow[Message, sm.ws.Message, sm.ws.Message, Message] .atopMat(wsLayer)((_, s) ⇒ adaptWsUpgradeResponse(s))) - private def adaptWsFlow(wsLayer: stream.scaladsl.Flow[sm.ws.Message, sm.ws.Message, Future[scaladsl.model.ws.WebsocketUpgradeResponse]]): Flow[Message, Message, Future[WebsocketUpgradeResponse]] = + private def adaptWsFlow(wsLayer: stream.scaladsl.Flow[sm.ws.Message, sm.ws.Message, Future[scaladsl.model.ws.WebSocketUpgradeResponse]]): Flow[Message, Message, Future[WebSocketUpgradeResponse]] = Flow.fromGraph(JavaMapping.adapterBidiFlow[Message, sm.ws.Message, sm.ws.Message, Message].joinMat(wsLayer)(Keep.right).mapMaterializedValue(adaptWsUpgradeResponse _)) private def adaptWsFlow[Mat](javaFlow: Flow[Message, Message, Mat]): stream.scaladsl.Flow[scaladsl.model.ws.Message, scaladsl.model.ws.Message, Mat] = @@ -749,10 +767,10 @@ class Http(system: ExtendedActorSystem) extends akka.actor.Extension { .viaMat(javaFlow.asScala)(Keep.right) .map(_.asScala) - private def adaptWsResultTuple[T](result: (Future[scaladsl.model.ws.WebsocketUpgradeResponse], T)): Pair[Future[WebsocketUpgradeResponse], T] = + private def adaptWsResultTuple[T](result: (Future[scaladsl.model.ws.WebSocketUpgradeResponse], T)): Pair[Future[WebSocketUpgradeResponse], T] = result match { case (fut, tMat) ⇒ Pair(adaptWsUpgradeResponse(fut), tMat) } - private def adaptWsUpgradeResponse(responseFuture: Future[scaladsl.model.ws.WebsocketUpgradeResponse]): Future[WebsocketUpgradeResponse] = - responseFuture.map(WebsocketUpgradeResponse.adapt)(system.dispatcher) + private def adaptWsUpgradeResponse(responseFuture: Future[scaladsl.model.ws.WebSocketUpgradeResponse]): Future[WebSocketUpgradeResponse] = + responseFuture.map(WebSocketUpgradeResponse.adapt)(system.dispatcher) } diff --git a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/Message.scala b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/Message.scala index 92b89fef2d..5ed16311bd 100644 --- a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/Message.scala +++ b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/Message.scala @@ -9,7 +9,7 @@ import akka.stream.javadsl.Source import akka.util.ByteString /** - * Represents a Websocket message. A message can either be a binary message or a text message. + * Represents a WebSocket message. A message can either be a binary message or a text message. */ sealed abstract class Message { /** @@ -39,7 +39,7 @@ object Message { } /** - * Represents a Websocket text message. A text message can either be strict in which case + * Represents a WebSocket text message. A text message can either be strict in which case * the complete data is already available or it can be streamed in which case [[getStreamedText]] * will return a Source streaming the data as it comes in. */ diff --git a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/PeerClosedConnectionException.scala b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/PeerClosedConnectionException.scala index 5ca5d43c98..eebdf7736f 100644 --- a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/PeerClosedConnectionException.scala +++ b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/PeerClosedConnectionException.scala @@ -5,7 +5,7 @@ package akka.http.javadsl.model.ws /** - * A PeerClosedConnectionException will be reported to the Websocket handler if the peer has closed the connection. + * A PeerClosedConnectionException will be reported to the WebSocket handler if the peer has closed the connection. * `closeCode` and `closeReason` contain close messages as reported by the peer. */ trait PeerClosedConnectionException extends RuntimeException { diff --git a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/UpgradeToWebsocket.scala b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/UpgradeToWebSocket.scala similarity index 68% rename from akka-http-core/src/main/scala/akka/http/javadsl/model/ws/UpgradeToWebsocket.scala rename to akka-http-core/src/main/scala/akka/http/javadsl/model/ws/UpgradeToWebSocket.scala index b820573e38..a75b995d7a 100644 --- a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/UpgradeToWebsocket.scala +++ b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/UpgradeToWebSocket.scala @@ -11,10 +11,10 @@ import akka.stream.Materializer import akka.stream._ /** - * A virtual header that Websocket requests will contain. Use [[UpgradeToWebsocket.handleMessagesWith]] to - * create a Websocket handshake response and handle the Websocket message stream with the given handler. + * A virtual header that WebSocket requests will contain. Use [[UpgradeToWebSocket.handleMessagesWith]] to + * create a WebSocket handshake response and handle the WebSocket message stream with the given handler. */ -trait UpgradeToWebsocket extends sm.HttpHeader { +trait UpgradeToWebSocket extends sm.HttpHeader { /** * Returns the sequence of protocols the client accepts. * @@ -23,27 +23,27 @@ trait UpgradeToWebsocket extends sm.HttpHeader { def getRequestedProtocols(): JIterable[String] /** - * Returns a response that can be used to answer a Websocket handshake request. The connection will afterwards - * use the given handlerFlow to handle Websocket messages from the client. + * Returns a response that can be used to answer a WebSocket handshake request. The connection will afterwards + * use the given handlerFlow to handle WebSocket messages from the client. */ def handleMessagesWith(handlerFlow: Graph[FlowShape[Message, Message], _ <: Any]): HttpResponse /** - * Returns a response that can be used to answer a Websocket handshake request. The connection will afterwards - * use the given handlerFlow to handle Websocket messages from the client. The given subprotocol must be one + * Returns a response that can be used to answer a WebSocket handshake request. The connection will afterwards + * use the given handlerFlow to handle WebSocket messages from the client. The given subprotocol must be one * of the ones offered by the client. */ def handleMessagesWith(handlerFlow: Graph[FlowShape[Message, Message], _ <: Any], subprotocol: String): HttpResponse /** - * Returns a response that can be used to answer a Websocket handshake request. The connection will afterwards - * use the given inSink to handle Websocket messages from the client and the given outSource to send messages to the client. + * Returns a response that can be used to answer a WebSocket handshake request. The connection will afterwards + * use the given inSink to handle WebSocket messages from the client and the given outSource to send messages to the client. */ def handleMessagesWith(inSink: Graph[SinkShape[Message], _ <: Any], outSource: Graph[SourceShape[Message], _ <: Any]): HttpResponse /** - * Returns a response that can be used to answer a Websocket handshake request. The connection will afterwards - * use the given inSink to handle Websocket messages from the client and the given outSource to send messages to the client. + * Returns a response that can be used to answer a WebSocket handshake request. The connection will afterwards + * use the given inSink to handle WebSocket messages from the client and the given outSource to send messages to the client. * * The given subprotocol must be one of the ones offered by the client. */ diff --git a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/Websocket.scala b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebSocket.scala similarity index 55% rename from akka-http-core/src/main/scala/akka/http/javadsl/model/ws/Websocket.scala rename to akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebSocket.scala index 31bdf1dc44..7c71d35eb5 100644 --- a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/Websocket.scala +++ b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebSocket.scala @@ -8,15 +8,15 @@ import akka.stream.javadsl.Flow import akka.http.javadsl.model._ import akka.http.impl.util.JavaMapping.Implicits._ -object Websocket { +object WebSocket { /** - * If a given request is a Websocket request a response accepting the request is returned using the given handler to - * handle the Websocket message stream. If the request wasn't a Websocket request a response with status code 400 is + * If a given request is a WebSocket request a response accepting the request is returned using the given handler to + * handle the WebSocket message stream. If the request wasn't a WebSocket request a response with status code 400 is * returned. */ - def handleWebsocketRequestWith(request: HttpRequest, handler: Flow[Message, Message, _]): HttpResponse = - request.asScala.header[UpgradeToWebsocket] match { + def handleWebSocketRequestWith(request: HttpRequest, handler: Flow[Message, Message, _]): HttpResponse = + request.asScala.header[UpgradeToWebSocket] match { case Some(header) ⇒ header.handleMessagesWith(handler) - case None ⇒ HttpResponse.create().withStatus(StatusCodes.BAD_REQUEST).withEntity("Expected websocket request") + case None ⇒ HttpResponse.create().withStatus(StatusCodes.BAD_REQUEST).withEntity("Expected WebSocket request") } } diff --git a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebSocketRequest.scala b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebSocketRequest.scala new file mode 100644 index 0000000000..5b3a26ac27 --- /dev/null +++ b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebSocketRequest.scala @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009-2015 Typesafe Inc. + */ + +package akka.http.javadsl.model.ws + +import akka.http.javadsl.model.{ Uri, HttpHeader } +import akka.http.scaladsl.model.ws.{ WebSocketRequest ⇒ ScalaWebSocketRequest } + +/** + * Represents a WebSocket request. Use `WebSocketRequest.create` to create a request + * for a target URI and then use `addHeader` or `requestSubprotocol` to set optional + * details. + */ +abstract class WebSocketRequest { + /** + * Return a copy of this request that contains the given additional header. + */ + def addHeader(header: HttpHeader): WebSocketRequest + + /** + * Return a copy of this request that will require that the server uses the + * given WebSocket subprotocol. + */ + def requestSubprotocol(subprotocol: String): WebSocketRequest + + def asScala: ScalaWebSocketRequest +} +object WebSocketRequest { + import akka.http.impl.util.JavaMapping.Implicits._ + + /** + * Creates a WebSocketRequest to a target URI. Use the methods on `WebSocketRequest` + * to specify further details. + */ + def create(uri: Uri): WebSocketRequest = + wrap(ScalaWebSocketRequest(uri.asScala)) + + /** + * Creates a WebSocketRequest to a target URI. Use the methods on `WebSocketRequest` + * to specify further details. + */ + def create(uriString: String): WebSocketRequest = + create(Uri.create(uriString)) + + /** + * Wraps a Scala version of WebSocketRequest. + */ + def wrap(scalaRequest: ScalaWebSocketRequest): WebSocketRequest = + new WebSocketRequest { + def addHeader(header: HttpHeader): WebSocketRequest = + transform(s ⇒ s.copy(extraHeaders = s.extraHeaders :+ header.asScala)) + def requestSubprotocol(subprotocol: String): WebSocketRequest = + transform(_.copy(subprotocol = Some(subprotocol))) + + def asScala: ScalaWebSocketRequest = scalaRequest + + def transform(f: ScalaWebSocketRequest ⇒ ScalaWebSocketRequest): WebSocketRequest = + wrap(f(asScala)) + } +} diff --git a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebsocketUpgradeResponse.scala b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebSocketUpgradeResponse.scala similarity index 84% rename from akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebsocketUpgradeResponse.scala rename to akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebSocketUpgradeResponse.scala index 58b3af73d6..08c65c180e 100644 --- a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebsocketUpgradeResponse.scala +++ b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebSocketUpgradeResponse.scala @@ -11,11 +11,11 @@ import akka.http.scaladsl import akka.http.scaladsl.model.ws.{ InvalidUpgradeResponse, ValidUpgrade } /** - * Represents an upgrade response for a Websocket upgrade request. Can either be valid, in which + * Represents an upgrade response for a WebSocket upgrade request. Can either be valid, in which * case the `chosenSubprotocol` method is valid, or if invalid, the `invalidationReason` method * can be used to find out why the upgrade failed. */ -trait WebsocketUpgradeResponse { +trait WebSocketUpgradeResponse { def isValid: Boolean /** @@ -35,12 +35,12 @@ trait WebsocketUpgradeResponse { def invalidationReason: String } -object WebsocketUpgradeResponse { +object WebSocketUpgradeResponse { import akka.http.impl.util.JavaMapping.Implicits._ - def adapt(scalaResponse: scaladsl.model.ws.WebsocketUpgradeResponse): WebsocketUpgradeResponse = + def adapt(scalaResponse: scaladsl.model.ws.WebSocketUpgradeResponse): WebSocketUpgradeResponse = scalaResponse match { case ValidUpgrade(resp, chosen) ⇒ - new WebsocketUpgradeResponse { + new WebSocketUpgradeResponse { def isValid: Boolean = true def response: HttpResponse = resp def chosenSubprotocol: Optional[String] = chosen.asJava @@ -48,7 +48,7 @@ object WebsocketUpgradeResponse { throw new UnsupportedOperationException("invalidationReason must not be called for valid response") } case InvalidUpgradeResponse(resp, cause) ⇒ - new WebsocketUpgradeResponse { + new WebSocketUpgradeResponse { def isValid: Boolean = false def response: HttpResponse = resp def chosenSubprotocol: Optional[String] = throw new UnsupportedOperationException("chosenSubprotocol must not be called for valid response") diff --git a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebsocketRequest.scala b/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebsocketRequest.scala deleted file mode 100644 index d895cb6e56..0000000000 --- a/akka-http-core/src/main/scala/akka/http/javadsl/model/ws/WebsocketRequest.scala +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2009-2015 Typesafe Inc. - */ - -package akka.http.javadsl.model.ws - -import akka.http.javadsl.model.{ Uri, HttpHeader } -import akka.http.scaladsl.model.ws.{ WebsocketRequest ⇒ ScalaWebsocketRequest } - -/** - * Represents a Websocket request. Use `WebsocketRequest.create` to create a request - * for a target URI and then use `addHeader` or `requestSubprotocol` to set optional - * details. - */ -abstract class WebsocketRequest { - /** - * Return a copy of this request that contains the given additional header. - */ - def addHeader(header: HttpHeader): WebsocketRequest - - /** - * Return a copy of this request that will require that the server uses the - * given Websocket subprotocol. - */ - def requestSubprotocol(subprotocol: String): WebsocketRequest - - def asScala: ScalaWebsocketRequest -} -object WebsocketRequest { - import akka.http.impl.util.JavaMapping.Implicits._ - - /** - * Creates a WebsocketRequest to a target URI. Use the methods on `WebsocketRequest` - * to specify further details. - */ - def create(uri: Uri): WebsocketRequest = - wrap(ScalaWebsocketRequest(uri.asScala)) - - /** - * Creates a WebsocketRequest to a target URI. Use the methods on `WebsocketRequest` - * to specify further details. - */ - def create(uriString: String): WebsocketRequest = - create(Uri.create(uriString)) - - /** - * Wraps a Scala version of WebsocketRequest. - */ - def wrap(scalaRequest: ScalaWebsocketRequest): WebsocketRequest = - new WebsocketRequest { - def addHeader(header: HttpHeader): WebsocketRequest = - transform(s ⇒ s.copy(extraHeaders = s.extraHeaders :+ header.asScala)) - def requestSubprotocol(subprotocol: String): WebsocketRequest = - transform(_.copy(subprotocol = Some(subprotocol))) - - def asScala: ScalaWebsocketRequest = scalaRequest - - def transform(f: ScalaWebsocketRequest ⇒ ScalaWebsocketRequest): WebsocketRequest = - wrap(f(asScala)) - } -} diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala index 1ea0bae136..7b544682cf 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/Http.scala @@ -14,28 +14,25 @@ import akka.http._ import akka.http.impl.engine.HttpConnectionTimeoutException import akka.http.impl.engine.client._ import akka.http.impl.engine.server._ -import akka.http.impl.engine.ws.WebsocketClientBlueprint +import akka.http.impl.engine.ws.WebSocketClientBlueprint import akka.http.impl.util.StreamUtils import akka.http.scaladsl.model._ import akka.http.scaladsl.model.headers.Host -import akka.http.scaladsl.model.ws.{ WebsocketUpgradeResponse, WebsocketRequest, Message } +import akka.http.scaladsl.model.ws.{ Message, WebSocketRequest, WebSocketUpgradeResponse } import akka.http.scaladsl.util.FastFuture import akka.NotUsed import akka.stream.Materializer import akka.stream.io._ import akka.stream.scaladsl._ import com.typesafe.config.Config -import com.typesafe.sslconfig.akka.util.AkkaLoggerFactory import com.typesafe.sslconfig.akka._ +import com.typesafe.sslconfig.akka.util.AkkaLoggerFactory import com.typesafe.sslconfig.ssl._ -import scala.collection.immutable import scala.concurrent.{ ExecutionContext, Future, Promise, TimeoutException } import scala.util.Try import scala.util.control.NonFatal -import scala.compat.java8.OptionConverters._ - class HttpExt(private val config: Config)(implicit val system: ActorSystem) extends akka.actor.Extension with DefaultSSLContextCreation { @@ -629,7 +626,7 @@ object Http extends ExtensionId[HttpExt] with ExtensionIdProvider { //# /** - * The type of the client-side Websocket layer as a stand-alone BidiFlow + * The type of the client-side WebSocket layer as a stand-alone BidiFlow * that can be put atop the TCP layer to form an HTTP client. * * {{{ @@ -640,7 +637,7 @@ object Http extends ExtensionId[HttpExt] with ExtensionIdProvider { * +------+ * }}} */ - type WebsocketClientLayer = BidiFlow[Message, SslTlsOutbound, SslTlsInbound, Message, Future[WebsocketUpgradeResponse]] + type WebSocketClientLayer = BidiFlow[Message, SslTlsOutbound, SslTlsInbound, Message, Future[WebSocketUpgradeResponse]] /** * Represents a prospective HTTP server binding. @@ -756,10 +753,16 @@ trait DefaultSSLContextCreation { val cipherSuites = sslConfig.configureCipherSuites(defaultCiphers, config) defaultParams.setCipherSuites(cipherSuites) + // auth! + val clientAuth = config.sslParametersConfig.clientAuth match { + case ClientAuth.Default ⇒ None + case auth ⇒ Some(auth) + } // hostname! defaultParams.setEndpointIdentificationAlgorithm("https") - HttpsContext(sslContext, sslParameters = Some(defaultParams)) + // new HttpsConnectionContext(sslContext, Some(cipherSuites.toList), Some(defaultProtocols.toList), clientAuth, Some(defaultParams)) + new HttpsConnectionContext(sslContext, None, None, None, Some(defaultParams)) // previously } } diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/WebsocketExtension.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/WebSocketExtension.scala similarity index 90% rename from akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/WebsocketExtension.scala rename to akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/WebSocketExtension.scala index f11f0bbaba..c95f47ea26 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/WebsocketExtension.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/WebSocketExtension.scala @@ -10,7 +10,7 @@ import akka.http.impl.util.{ Rendering, ValueRenderable } /** * A websocket extension as defined in http://tools.ietf.org/html/rfc6455#section-4.3 */ -final case class WebsocketExtension(name: String, params: immutable.Map[String, String] = Map.empty) extends ValueRenderable { +final case class WebSocketExtension(name: String, params: immutable.Map[String, String] = Map.empty) extends ValueRenderable { def render[R <: Rendering](r: R): r.type = { r ~~ name if (params.nonEmpty) diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/headers.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/headers.scala index 121e8c27ed..ed73cd3729 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/headers.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/headers/headers.scala @@ -689,6 +689,7 @@ private[http] object `Sec-WebSocket-Accept` extends ModeledCompanion[`Sec-WebSoc */ private[http] final case class `Sec-WebSocket-Accept`(key: String) extends ResponseHeader { protected[http] def renderValue[R <: Rendering](r: R): r.type = r ~~ key + protected def companion = `Sec-WebSocket-Accept` } @@ -697,12 +698,12 @@ private[http] final case class `Sec-WebSocket-Accept`(key: String) extends Respo */ // http://tools.ietf.org/html/rfc6455#section-4.3 private[http] object `Sec-WebSocket-Extensions` extends ModeledCompanion[`Sec-WebSocket-Extensions`] { - implicit val extensionsRenderer = Renderer.defaultSeqRenderer[WebsocketExtension] + implicit val extensionsRenderer = Renderer.defaultSeqRenderer[WebSocketExtension] } /** * INTERNAL API */ -private[http] final case class `Sec-WebSocket-Extensions`(extensions: immutable.Seq[WebsocketExtension]) +private[http] final case class `Sec-WebSocket-Extensions`(extensions: immutable.Seq[WebSocketExtension]) extends ResponseHeader { require(extensions.nonEmpty, "Sec-WebSocket-Extensions.extensions must not be empty") import `Sec-WebSocket-Extensions`.extensionsRenderer @@ -725,10 +726,11 @@ private[http] object `Sec-WebSocket-Key` extends ModeledCompanion[`Sec-WebSocket */ private[http] final case class `Sec-WebSocket-Key`(key: String) extends RequestHeader { protected[http] def renderValue[R <: Rendering](r: R): r.type = r ~~ key + protected def companion = `Sec-WebSocket-Key` /** - * Checks if the key value is valid according to the Websocket specification, i.e. + * Checks if the key value is valid according to the WebSocket specification, i.e. * if the String is a Base64 representation of 16 bytes. */ def isValid: Boolean = Try(Base64.rfc2045().decode(key)).toOption.exists(_.length == 16) @@ -858,7 +860,7 @@ final case class Upgrade(protocols: immutable.Seq[UpgradeProtocol]) extends Requ protected def companion = Upgrade - def hasWebsocket: Boolean = protocols.exists(_.name equalsIgnoreCase "websocket") + def hasWebSocket: Boolean = protocols.exists(_.name equalsIgnoreCase "websocket") } // http://tools.ietf.org/html/rfc7231#section-5.5.3 diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/Message.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/Message.scala index 4a38aa64bd..7cce22716b 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/Message.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/Message.scala @@ -9,7 +9,7 @@ import akka.util.ByteString //#message-model /** - * The ADT for Websocket messages. A message can either be a binary or a text message. + * The ADT for WebSocket messages. A message can either be a binary or a text message. */ sealed trait Message diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/PeerClosedConnectionException.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/PeerClosedConnectionException.scala index 8f768252f5..d49a5dede5 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/PeerClosedConnectionException.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/PeerClosedConnectionException.scala @@ -7,7 +7,7 @@ package akka.http.scaladsl.model.ws import akka.http.javadsl /** - * A PeerClosedConnectionException will be reported to the Websocket handler if the peer has closed the connection. + * A PeerClosedConnectionException will be reported to the WebSocket handler if the peer has closed the connection. * `closeCode` and `closeReason` contain close messages as reported by the peer. */ class PeerClosedConnectionException(val closeCode: Int, val closeReason: String) diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/UpgradeToWebsocket.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/UpgradeToWebSocket.scala similarity index 89% rename from akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/UpgradeToWebsocket.scala rename to akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/UpgradeToWebSocket.scala index 3d67839a78..584b62bbfe 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/UpgradeToWebsocket.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/UpgradeToWebSocket.scala @@ -13,11 +13,11 @@ import akka.http.javadsl.{ model ⇒ jm } import akka.http.scaladsl.model.HttpResponse /** - * A custom header that will be added to an Websocket upgrade HttpRequest that - * enables a request handler to upgrade this connection to a Websocket connection and - * registers a Websocket handler. + * A custom header that will be added to an WebSocket upgrade HttpRequest that + * enables a request handler to upgrade this connection to a WebSocket connection and + * registers a WebSocket handler. */ -trait UpgradeToWebsocket extends jm.ws.UpgradeToWebsocket { +trait UpgradeToWebSocket extends jm.ws.UpgradeToWebSocket { /** * A sequence of protocols the client accepts. * @@ -26,11 +26,11 @@ trait UpgradeToWebsocket extends jm.ws.UpgradeToWebsocket { def requestedProtocols: immutable.Seq[String] /** - * The high-level interface to create a Websocket server based on "messages". + * The high-level interface to create a WebSocket server based on "messages". * * Returns a response to return in a request handler that will signal the - * low-level HTTP implementation to upgrade the connection to Websocket and - * use the supplied handler to handle incoming Websocket messages. + * low-level HTTP implementation to upgrade the connection to WebSocket and + * use the supplied handler to handle incoming WebSocket messages. * * Optionally, a subprotocol out of the ones requested by the client can be chosen. */ @@ -38,10 +38,10 @@ trait UpgradeToWebsocket extends jm.ws.UpgradeToWebsocket { subprotocol: Option[String] = None): HttpResponse /** - * The high-level interface to create a Websocket server based on "messages". + * The high-level interface to create a WebSocket server based on "messages". * * Returns a response to return in a request handler that will signal the - * low-level HTTP implementation to upgrade the connection to Websocket and + * low-level HTTP implementation to upgrade the connection to WebSocket and * use the supplied inSink to consume messages received from the client and * the supplied outSource to produce message to sent to the client. * diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/WebsocketRequest.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/WebSocketRequest.scala similarity index 52% rename from akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/WebsocketRequest.scala rename to akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/WebSocketRequest.scala index e4dd04a02b..9e070649db 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/WebsocketRequest.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/WebSocketRequest.scala @@ -11,16 +11,16 @@ import scala.collection.immutable import akka.http.scaladsl.model.{ HttpHeader, Uri } /** - * Represents a Websocket request. + * Represents a WebSocket request. * @param uri The target URI to connect to. - * @param extraHeaders Extra headers to add to the Websocket request. - * @param subprotocol A Websocket subprotocol if required. + * @param extraHeaders Extra headers to add to the WebSocket request. + * @param subprotocol A WebSocket subprotocol if required. */ -final case class WebsocketRequest( +final case class WebSocketRequest( uri: Uri, extraHeaders: immutable.Seq[HttpHeader] = Nil, subprotocol: Option[String] = None) -object WebsocketRequest { - implicit def fromTargetUri(uri: Uri): WebsocketRequest = WebsocketRequest(uri) - implicit def fromTargetUriString(uriString: String): WebsocketRequest = WebsocketRequest(uriString) +object WebSocketRequest { + implicit def fromTargetUri(uri: Uri): WebSocketRequest = WebSocketRequest(uri) + implicit def fromTargetUriString(uriString: String): WebSocketRequest = WebSocketRequest(uriString) } \ No newline at end of file diff --git a/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/WebsocketUpgradeResponse.scala b/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/WebSocketUpgradeResponse.scala similarity index 75% rename from akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/WebsocketUpgradeResponse.scala rename to akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/WebSocketUpgradeResponse.scala index 595fbc2298..95dfd6173f 100644 --- a/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/WebsocketUpgradeResponse.scala +++ b/akka-http-core/src/main/scala/akka/http/scaladsl/model/ws/WebSocketUpgradeResponse.scala @@ -9,8 +9,8 @@ import akka.http.scaladsl.model.HttpResponse /** * Represents the response to a websocket upgrade request. Can either be [[ValidUpgrade]] or [[InvalidUpgradeResponse]]. */ -sealed trait WebsocketUpgradeResponse { +sealed trait WebSocketUpgradeResponse { def response: HttpResponse } -final case class ValidUpgrade(response: HttpResponse, chosenSubprotocol: Option[String]) extends WebsocketUpgradeResponse -final case class InvalidUpgradeResponse(response: HttpResponse, cause: String) extends WebsocketUpgradeResponse \ No newline at end of file +final case class ValidUpgrade(response: HttpResponse, chosenSubprotocol: Option[String]) extends WebSocketUpgradeResponse +final case class InvalidUpgradeResponse(response: HttpResponse, cause: String) extends WebSocketUpgradeResponse \ No newline at end of file diff --git a/akka-http-core/src/test/java/akka/http/javadsl/WSEchoTestClientApp.java b/akka-http-core/src/test/java/akka/http/javadsl/WSEchoTestClientApp.java index e21133c75b..57e3b8cb07 100644 --- a/akka-http-core/src/test/java/akka/http/javadsl/WSEchoTestClientApp.java +++ b/akka-http-core/src/test/java/akka/http/javadsl/WSEchoTestClientApp.java @@ -9,7 +9,7 @@ import akka.actor.ActorSystem; import akka.dispatch.Futures; import akka.http.javadsl.model.ws.Message; import akka.http.javadsl.model.ws.TextMessage; -import akka.http.javadsl.model.ws.WebsocketRequest; +import akka.http.javadsl.model.ws.WebSocketRequest; import akka.japi.function.Function; import akka.stream.ActorMaterializer; import akka.stream.Materializer; @@ -67,8 +67,8 @@ public class WSEchoTestClientApp { Flow.fromSinkAndSourceMat(echoSink, echoSource, Keep.>, NotUsed>left()); Future> result = - Http.get(system).singleWebsocketRequest( - WebsocketRequest.create("ws://echo.websocket.org"), + Http.get(system).singleWebSocketRequest( + WebSocketRequest.create("ws://echo.websocket.org"), echoClient, materializer ).second(); diff --git a/akka-http-core/src/test/java/akka/http/javadsl/model/JavaTestServer.java b/akka-http-core/src/test/java/akka/http/javadsl/model/JavaTestServer.java index caaaa5654e..330f9a7e55 100644 --- a/akka-http-core/src/test/java/akka/http/javadsl/model/JavaTestServer.java +++ b/akka-http-core/src/test/java/akka/http/javadsl/model/JavaTestServer.java @@ -11,7 +11,7 @@ import akka.http.javadsl.ServerBinding; import akka.japi.Function; import akka.http.javadsl.model.ws.Message; import akka.http.javadsl.model.ws.TextMessage; -import akka.http.javadsl.model.ws.Websocket; +import akka.http.javadsl.model.ws.WebSocket; import akka.japi.JavaPartialFunction; import akka.stream.ActorMaterializer; import akka.stream.Materializer; @@ -39,9 +39,9 @@ public class JavaTestServer { System.out.println("Handling request to " + request.getUri()); if (request.getUri().path().equals("/")) - return Websocket.handleWebsocketRequestWith(request, echoMessages()); + return WebSocket.handleWebSocketRequestWith(request, echoMessages()); else if (request.getUri().path().equals("/greeter")) - return Websocket.handleWebsocketRequestWith(request, greeter()); + return WebSocket.handleWebSocketRequestWith(request, greeter()); else return JavaApiTestCases.handleRequest(request); } diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/rendering/ResponseRendererSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/rendering/ResponseRendererSpec.scala index 734e6a5ac4..db41e6f7aa 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/rendering/ResponseRendererSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/rendering/ResponseRendererSpec.scala @@ -592,7 +592,7 @@ class ResponseRendererSpec extends FreeSpec with Matchers with BeforeAndAfterAll .via(renderer.named("renderer")) .map { case ResponseRenderingOutput.HttpData(bytes) ⇒ bytes - case _: ResponseRenderingOutput.SwitchToWebsocket ⇒ throw new IllegalStateException("Didn't expect websocket response") + case _: ResponseRenderingOutput.SwitchToWebSocket ⇒ throw new IllegalStateException("Didn't expect websocket response") } .groupedWithin(1000, 100.millis) .viaMat(StreamUtils.identityFinishReporter[Seq[ByteString]])(Keep.right) diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/EchoTestClientApp.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/EchoTestClientApp.scala index edddaeadc6..750e11f9df 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/EchoTestClientApp.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/EchoTestClientApp.scala @@ -54,7 +54,7 @@ object EchoTestClientApp extends App { def echoClient = Flow.fromSinkAndSourceMat(sink, source)(Keep.left) - val (upgrade, res) = Http().singleWebsocketRequest("wss://echo.websocket.org", echoClient) + val (upgrade, res) = Http().singleWebSocketRequest("wss://echo.websocket.org", echoClient) res onComplete { case Success(res) ⇒ println("Run successful. Got these elements:") diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/FramingSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/FramingSpec.scala index 095eef7e51..553e1faa7a 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/FramingSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/FramingSpec.scala @@ -18,7 +18,7 @@ import Protocol.Opcode class FramingSpec extends FreeSpec with Matchers with WithMaterializerSpec { import BitBuilder._ - "The Websocket parser/renderer round-trip should work for" - { + "The WebSocket parser/renderer round-trip should work for" - { "the frame header" - { "interpret flags correctly" - { "FIN" in { diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/MessageSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/MessageSpec.scala index ce2bd4394b..52de6d7182 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/MessageSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/MessageSpec.scala @@ -26,7 +26,7 @@ class MessageSpec extends FreeSpec with Matchers with WithMaterializerSpec { 0 // but don't finish it ) - "The Websocket implementation should" - { + "The WebSocket implementation should" - { "collect messages from frames" - { "for binary messages" - { "for an empty message" in new ClientTestSetup { @@ -864,7 +864,7 @@ class MessageSpec extends FreeSpec with Matchers with WithMaterializerSpec { Source.fromPublisher(netIn) .via(printEvent("netIn")) .via(FrameEventParser) - .via(Websocket + .via(WebSocket .stack(serverSide, maskingRandomFactory = Randoms.SecureRandomInstances, closeTimeout = closeTimeout, log = system.log) .join(messageHandler)) .via(printEvent("frameRendererIn")) diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WSClientAutobahnTest.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WSClientAutobahnTest.scala index 7b03976cfe..c832bc6e64 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WSClientAutobahnTest.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WSClientAutobahnTest.scala @@ -167,7 +167,7 @@ object WSClientAutobahnTest extends App { system.scheduler.scheduleOnce(60.seconds)(system.terminate()) def runWs[T](uri: Uri, clientFlow: Flow[Message, Message, T]): T = - Http().singleWebsocketRequest(uri, clientFlow)._2 + Http().singleWebSocketRequest(uri, clientFlow)._2 def completionSignal[T]: Flow[T, T, Future[Unit]] = Flow[T].transformMaterializing { () ⇒ @@ -193,8 +193,8 @@ object WSClientAutobahnTest extends App { } /** - * The autobahn tests define a weird API where every request must be a Websocket request and - * they will send a single websocket message with the result. Websocket everywhere? Strange, + * The autobahn tests define a weird API where every request must be a WebSocket request and + * they will send a single websocket message with the result. WebSocket everywhere? Strange, * but somewhat consistent. */ def runToSingleText(uri: Uri): Future[String] = { diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WSServerAutobahnTest.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WSServerAutobahnTest.scala index e2ca57b0c7..4096797169 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WSServerAutobahnTest.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WSServerAutobahnTest.scala @@ -12,7 +12,7 @@ import scala.concurrent.duration._ import akka.actor.ActorSystem import akka.http.scaladsl.Http import akka.http.scaladsl.model.HttpMethods._ -import akka.http.scaladsl.model.ws.{ Message, UpgradeToWebsocket } +import akka.http.scaladsl.model.ws.{ Message, UpgradeToWebSocket } import akka.http.scaladsl.model._ import akka.stream.ActorMaterializer import akka.stream.scaladsl.Flow @@ -28,9 +28,9 @@ object WSServerAutobahnTest extends App { try { val binding = Http().bindAndHandleSync({ - case req @ HttpRequest(GET, Uri.Path("/"), _, _, _) if req.header[UpgradeToWebsocket].isDefined ⇒ - req.header[UpgradeToWebsocket] match { - case Some(upgrade) ⇒ upgrade.handleMessages(echoWebsocketService) // needed for running the autobahn test suite + case req @ HttpRequest(GET, Uri.Path("/"), _, _, _) if req.header[UpgradeToWebSocket].isDefined ⇒ + req.header[UpgradeToWebSocket] match { + case Some(upgrade) ⇒ upgrade.handleMessages(echoWebSocketService) // needed for running the autobahn test suite case None ⇒ HttpResponse(400, entity = "Not a valid websocket request!") } case _: HttpRequest ⇒ HttpResponse(404, entity = "Unknown resource!") @@ -49,6 +49,6 @@ object WSServerAutobahnTest extends App { system.terminate() } - def echoWebsocketService: Flow[Message, Message, NotUsed] = + def echoWebSocketService: Flow[Message, Message, NotUsed] = Flow[Message] // just let message flow directly to the output } diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebsocketClientSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebSocketClientSpec.scala similarity index 94% rename from akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebsocketClientSpec.scala rename to akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebSocketClientSpec.scala index db89236f69..c74f10c3ef 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebsocketClientSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebSocketClientSpec.scala @@ -7,7 +7,7 @@ package akka.http.impl.engine.ws import java.util.Random import akka.NotUsed -import akka.http.scaladsl.model.ws.{ InvalidUpgradeResponse, WebsocketUpgradeResponse } +import akka.http.scaladsl.model.ws.{ InvalidUpgradeResponse, WebSocketUpgradeResponse } import akka.stream.ClosedShape import scala.concurrent.duration._ @@ -25,8 +25,8 @@ import org.scalatest.{ Matchers, FreeSpec } import akka.http.impl.util._ -class WebsocketClientSpec extends FreeSpec with Matchers with WithMaterializerSpec { - "The client-side Websocket implementation should" - { +class WebSocketClientSpec extends FreeSpec with Matchers with WithMaterializerSpec { + "The client-side WebSocket implementation should" - { "establish a websocket connection when the user requests it" in new EstablishedConnectionSetup with ClientEchoes "establish connection with case insensitive header values" in new TestSetup with ClientEchoes { expectWireData(UpgradeRequestBytes) @@ -54,7 +54,7 @@ class WebsocketClientSpec extends FreeSpec with Matchers with WithMaterializerSp |""") expectNetworkAbort() - expectInvalidUpgradeResponseCause("Websocket server at ws://example.org/ws returned unexpected status code: 404 Not Found") + expectInvalidUpgradeResponseCause("WebSocket server at ws://example.org/ws returned unexpected status code: 404 Not Found") } "missing Sec-WebSocket-Accept hash" in new TestSetup with ClientEchoes { expectWireData(UpgradeRequestBytes) @@ -69,7 +69,7 @@ class WebsocketClientSpec extends FreeSpec with Matchers with WithMaterializerSp |""") expectNetworkAbort() - expectInvalidUpgradeResponseCause("Websocket server at ws://example.org/ws returned response that was missing required `Sec-WebSocket-Accept` header.") + expectInvalidUpgradeResponseCause("WebSocket server at ws://example.org/ws returned response that was missing required `Sec-WebSocket-Accept` header.") } "wrong Sec-WebSocket-Accept hash" in new TestSetup with ClientEchoes { expectWireData(UpgradeRequestBytes) @@ -85,7 +85,7 @@ class WebsocketClientSpec extends FreeSpec with Matchers with WithMaterializerSp |""") expectNetworkAbort() - expectInvalidUpgradeResponseCause("Websocket server at ws://example.org/ws returned response with invalid `Sec-WebSocket-Accept` header.") + expectInvalidUpgradeResponseCause("WebSocket server at ws://example.org/ws returned response with invalid `Sec-WebSocket-Accept` header.") } "missing `Upgrade` header" in new TestSetup with ClientEchoes { expectWireData(UpgradeRequestBytes) @@ -100,7 +100,7 @@ class WebsocketClientSpec extends FreeSpec with Matchers with WithMaterializerSp |""") expectNetworkAbort() - expectInvalidUpgradeResponseCause("Websocket server at ws://example.org/ws returned response that was missing required `Upgrade` header.") + expectInvalidUpgradeResponseCause("WebSocket server at ws://example.org/ws returned response that was missing required `Upgrade` header.") } "missing `Connection: upgrade` header" in new TestSetup with ClientEchoes { expectWireData(UpgradeRequestBytes) @@ -115,7 +115,7 @@ class WebsocketClientSpec extends FreeSpec with Matchers with WithMaterializerSp |""") expectNetworkAbort() - expectInvalidUpgradeResponseCause("Websocket server at ws://example.org/ws returned response that was missing required `Connection` header.") + expectInvalidUpgradeResponseCause("WebSocket server at ws://example.org/ws returned response that was missing required `Connection` header.") } } @@ -227,7 +227,7 @@ class WebsocketClientSpec extends FreeSpec with Matchers with WithMaterializerSp expectNetworkAbort() expectInvalidUpgradeResponseCause( - "Websocket server at ws://example.org/ws returned response that indicated that the given subprotocol was not supported. (client supported: v2, server supported: None)") + "WebSocket server at ws://example.org/ws returned response that indicated that the given subprotocol was not supported. (client supported: v2, server supported: None)") } "if different protocol was selected" in new TestSetup with ClientProbes { override protected def requestedSubProtocol: Option[String] = Some("v2") @@ -256,7 +256,7 @@ class WebsocketClientSpec extends FreeSpec with Matchers with WithMaterializerSp expectNetworkAbort() expectInvalidUpgradeResponseCause( - "Websocket server at ws://example.org/ws returned response that indicated that the given subprotocol was not supported. (client supported: v2, server supported: Some(v3))") + "WebSocket server at ws://example.org/ws returned response that indicated that the given subprotocol was not supported. (client supported: v2, server supported: Some(v3))") } } } @@ -303,9 +303,9 @@ class WebsocketClientSpec extends FreeSpec with Matchers with WithMaterializerSp def targetUri: Uri = "ws://example.org/ws" - def clientLayer: Http.WebsocketClientLayer = - Http(system).websocketClientLayer( - WebsocketRequest(targetUri, subprotocol = requestedSubProtocol), + def clientLayer: Http.WebSocketClientLayer = + Http(system).webSocketClientLayer( + WebSocketRequest(targetUri, subprotocol = requestedSubProtocol), settings = settings) val (netOut, netIn, response) = { @@ -352,7 +352,7 @@ class WebsocketClientSpec extends FreeSpec with Matchers with WithMaterializerSp def expectNetworkAbort(): Unit = netOut.expectError() def closeNetworkInput(): Unit = netIn.sendComplete() - def expectResponse(response: WebsocketUpgradeResponse): Unit = + def expectResponse(response: WebSocketUpgradeResponse): Unit = expectInvalidUpgradeResponse() shouldEqual response def expectInvalidUpgradeResponseCause(expected: String): Unit = expectInvalidUpgradeResponse().cause shouldEqual expected diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebSocketIntegrationSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebSocketIntegrationSpec.scala new file mode 100644 index 0000000000..dfc64f8f12 --- /dev/null +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebSocketIntegrationSpec.scala @@ -0,0 +1,174 @@ +/** + * Copyright (C) 2015 Typesafe Inc. + */ +package akka.http.impl.engine.ws + +import scala.concurrent.Await +import scala.concurrent.duration.DurationInt +import org.scalactic.ConversionCheckedTripleEquals +import org.scalatest.concurrent.ScalaFutures +import org.scalatest.time.Span.convertDurationToSpan +import akka.http.scaladsl.Http +import akka.http.scaladsl.model.HttpRequest +import akka.http.scaladsl.model.Uri.apply +import akka.http.scaladsl.model.ws._ +import akka.stream._ +import akka.stream.scaladsl._ +import akka.stream.testkit._ +import akka.stream.scaladsl.GraphDSL.Implicits._ +import org.scalatest.concurrent.Eventually +import akka.stream.io.SslTlsPlacebo +import java.net.InetSocketAddress +import akka.stream.impl.fusing.GraphStages +import akka.util.ByteString +import akka.http.scaladsl.model.StatusCodes +import akka.stream.testkit.scaladsl.TestSink +import scala.concurrent.Future + +class WebSocketIntegrationSpec extends AkkaSpec("akka.stream.materializer.debug.fuzzing-mode=off") + with ScalaFutures with ConversionCheckedTripleEquals with Eventually { + + implicit val patience = PatienceConfig(3.seconds) + import system.dispatcher + implicit val materializer = ActorMaterializer() + + "A WebSocket server" must { + + "not reset the connection when no data are flowing" in Utils.assertAllStagesStopped { + val source = TestPublisher.probe[Message]() + val bindingFuture = Http().bindAndHandleSync({ + case HttpRequest(_, _, headers, _, _) ⇒ + val upgrade = headers.collectFirst { case u: UpgradeToWebSocket ⇒ u }.get + upgrade.handleMessages(Flow.fromSinkAndSource(Sink.ignore, Source.fromPublisher(source)), None) + }, interface = "localhost", port = 0) + val binding = Await.result(bindingFuture, 3.seconds) + val myPort = binding.localAddress.getPort + + val (response, sink) = Http().singleWebSocketRequest( + WebSocketRequest("ws://127.0.0.1:" + myPort), + Flow.fromSinkAndSourceMat(TestSink.probe[Message], Source.empty)(Keep.left)) + + response.futureValue.response.status.isSuccess should ===(true) + sink + .request(10) + .expectNoMsg(500.millis) + + source + .sendNext(TextMessage("hello")) + .sendComplete() + sink + .expectNext(TextMessage("hello")) + .expectComplete() + + binding.unbind() + } + + "not reset the connection when no data are flowing and the connection is closed from the client" in Utils.assertAllStagesStopped { + val source = TestPublisher.probe[Message]() + val bindingFuture = Http().bindAndHandleSync({ + case HttpRequest(_, _, headers, _, _) ⇒ + val upgrade = headers.collectFirst { case u: UpgradeToWebSocket ⇒ u }.get + upgrade.handleMessages(Flow.fromSinkAndSource(Sink.ignore, Source.fromPublisher(source)), None) + }, interface = "localhost", port = 0) + val binding = Await.result(bindingFuture, 3.seconds) + val myPort = binding.localAddress.getPort + + val ((response, breaker), sink) = + Source.empty + .viaMat { + Http().webSocketClientLayer(WebSocketRequest("ws://localhost:" + myPort)) + .atop(SslTlsPlacebo.forScala) + .joinMat(Flow.fromGraph(GraphStages.breaker[ByteString]).via( + Tcp().outgoingConnection(new InetSocketAddress("localhost", myPort), halfClose = true)))(Keep.both) + }(Keep.right) + .toMat(TestSink.probe[Message])(Keep.both) + .run() + + response.futureValue.response.status.isSuccess should ===(true) + sink + .request(10) + .expectNoMsg(1500.millis) + + breaker.value.get.get.complete() + + source + .sendNext(TextMessage("hello")) + .sendComplete() + sink + .expectNext(TextMessage("hello")) + .expectComplete() + + binding.unbind() + } + + "echo 100 elements and then shut down without error" in Utils.assertAllStagesStopped { + + val bindingFuture = Http().bindAndHandleSync({ + case HttpRequest(_, _, headers, _, _) ⇒ + val upgrade = headers.collectFirst { case u: UpgradeToWebSocket ⇒ u }.get + upgrade.handleMessages(Flow.apply, None) + }, interface = "localhost", port = 0) + val binding = Await.result(bindingFuture, 3.seconds) + val myPort = binding.localAddress.getPort + + val N = 100 + val (response, count) = Http().singleWebSocketRequest( + WebSocketRequest("ws://127.0.0.1:" + myPort), + Flow.fromSinkAndSourceMat( + Sink.fold(0)((n, _: Message) ⇒ n + 1), + Source.repeat(TextMessage("hello")).take(N))(Keep.left)) + + count.futureValue should ===(N) + binding.unbind() + } + + "send back 100 elements and then terminate without error even when not ordinarily closed" in Utils.assertAllStagesStopped { + val N = 100 + + val handler = Flow.fromGraph(GraphDSL.create() { implicit b ⇒ + val merge = b.add(Merge[Int](2)) + + // convert to int so we can connect to merge + val mapMsgToInt = b.add(Flow[Message].map(_ ⇒ -1)) + val mapIntToMsg = b.add(Flow[Int].map(x ⇒ TextMessage.Strict(s"Sending: $x"))) + + // source we want to use to send message to the connected websocket sink + val rangeSource = b.add(Source(1 to N)) + + mapMsgToInt ~> merge // this part of the merge will never provide msgs + rangeSource ~> merge ~> mapIntToMsg + + FlowShape(mapMsgToInt.in, mapIntToMsg.out) + }) + + val bindingFuture = Http().bindAndHandleSync({ + case HttpRequest(_, _, headers, _, _) ⇒ + val upgrade = headers.collectFirst { case u: UpgradeToWebSocket ⇒ u }.get + upgrade.handleMessages(handler, None) + }, interface = "localhost", port = 0) + val binding = Await.result(bindingFuture, 3.seconds) + val myPort = binding.localAddress.getPort + + @volatile var messages = 0 + val (breaker, completion) = + Source.maybe + .viaMat { + Http().webSocketClientLayer(WebSocketRequest("ws://localhost:" + myPort)) + .atop(SslTlsPlacebo.forScala) + // the resource leak of #19398 existed only for severed websocket connections + .atopMat(GraphStages.bidiBreaker[ByteString, ByteString])(Keep.right) + .join(Tcp().outgoingConnection(new InetSocketAddress("localhost", myPort), halfClose = true)) + }(Keep.right) + .toMat(Sink.foreach(_ ⇒ messages += 1))(Keep.both) + .run() + eventually(messages should ===(N)) + // breaker should have been fulfilled long ago + breaker.value.get.get.completeAndCancel() + completion.futureValue + + binding.unbind() + } + + } + +} diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebsocketServerSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebSocketServerSpec.scala similarity index 94% rename from akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebsocketServerSpec.scala rename to akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebSocketServerSpec.scala index ce9b6ddc7e..75e89ed288 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebsocketServerSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/ws/WebSocketServerSpec.scala @@ -14,10 +14,10 @@ import akka.http.impl.util._ import akka.http.impl.engine.server.HttpServerTestSetupBase -class WebsocketServerSpec extends FreeSpec with Matchers with WithMaterializerSpec { spec ⇒ +class WebSocketServerSpec extends FreeSpec with Matchers with WithMaterializerSpec { spec ⇒ import WSTestUtils._ - "The server-side Websocket integration should" - { + "The server-side WebSocket integration should" - { "establish a websocket connection when the user requests it" - { "when user handler instantly tries to send messages" in Utils.assertAllStagesStopped { new TestSetup { @@ -33,7 +33,7 @@ class WebsocketServerSpec extends FreeSpec with Matchers with WithMaterializerSp |""") val request = expectRequest() - val upgrade = request.header[UpgradeToWebsocket] + val upgrade = request.header[UpgradeToWebSocket] upgrade.isDefined shouldBe true val source = @@ -79,7 +79,7 @@ class WebsocketServerSpec extends FreeSpec with Matchers with WithMaterializerSp |""") val request = expectRequest() - val upgrade = request.header[UpgradeToWebsocket] + val upgrade = request.header[UpgradeToWebSocket] upgrade.isDefined shouldBe true val response = upgrade.get.handleMessages(Flow[Message]) // simple echoing @@ -115,7 +115,7 @@ class WebsocketServerSpec extends FreeSpec with Matchers with WithMaterializerSp } } "prevent the selection of an unavailable subprotocol" in pending - "reject invalid Websocket handshakes" - { + "reject invalid WebSocket handshakes" - { "missing `Upgrade: websocket` header" in pending "missing `Connection: upgrade` header" in pending "missing `Sec-WebSocket-Key header" in pending diff --git a/akka-http-core/src/test/scala/akka/http/impl/model/parser/HttpHeaderSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/model/parser/HttpHeaderSpec.scala index a46c9200e3..92e9781845 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/model/parser/HttpHeaderSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/model/parser/HttpHeaderSpec.scala @@ -401,23 +401,23 @@ class HttpHeaderSpec extends FreeSpec with Matchers { } "Sec-WebSocket-Extensions" in { "Sec-WebSocket-Extensions: abc" =!= - `Sec-WebSocket-Extensions`(Vector(WebsocketExtension("abc"))) + `Sec-WebSocket-Extensions`(Vector(WebSocketExtension("abc"))) "Sec-WebSocket-Extensions: abc, def" =!= - `Sec-WebSocket-Extensions`(Vector(WebsocketExtension("abc"), WebsocketExtension("def"))) + `Sec-WebSocket-Extensions`(Vector(WebSocketExtension("abc"), WebSocketExtension("def"))) "Sec-WebSocket-Extensions: abc; param=2; use_y, def" =!= - `Sec-WebSocket-Extensions`(Vector(WebsocketExtension("abc", Map("param" -> "2", "use_y" -> "")), WebsocketExtension("def"))) + `Sec-WebSocket-Extensions`(Vector(WebSocketExtension("abc", Map("param" -> "2", "use_y" -> "")), WebSocketExtension("def"))) "Sec-WebSocket-Extensions: abc; param=\",xyz\", def" =!= - `Sec-WebSocket-Extensions`(Vector(WebsocketExtension("abc", Map("param" -> ",xyz")), WebsocketExtension("def"))) + `Sec-WebSocket-Extensions`(Vector(WebSocketExtension("abc", Map("param" -> ",xyz")), WebSocketExtension("def"))) // real examples from https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-19 "Sec-WebSocket-Extensions: permessage-deflate" =!= - `Sec-WebSocket-Extensions`(Vector(WebsocketExtension("permessage-deflate"))) + `Sec-WebSocket-Extensions`(Vector(WebSocketExtension("permessage-deflate"))) "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits; server_max_window_bits=10" =!= - `Sec-WebSocket-Extensions`(Vector(WebsocketExtension("permessage-deflate", Map("client_max_window_bits" -> "", "server_max_window_bits" -> "10")))) + `Sec-WebSocket-Extensions`(Vector(WebSocketExtension("permessage-deflate", Map("client_max_window_bits" -> "", "server_max_window_bits" -> "10")))) "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits; server_max_window_bits=10, permessage-deflate; client_max_window_bits" =!= `Sec-WebSocket-Extensions`(Vector( - WebsocketExtension("permessage-deflate", Map("client_max_window_bits" -> "", "server_max_window_bits" -> "10")), - WebsocketExtension("permessage-deflate", Map("client_max_window_bits" -> "")))) + WebSocketExtension("permessage-deflate", Map("client_max_window_bits" -> "", "server_max_window_bits" -> "10")), + WebSocketExtension("permessage-deflate", Map("client_max_window_bits" -> "")))) } "Sec-WebSocket-Key" in { "Sec-WebSocket-Key: c2Zxb3JpbmgyMzA5dGpoMDIzOWdlcm5vZ2luCg==" =!= `Sec-WebSocket-Key`("c2Zxb3JpbmgyMzA5dGpoMDIzOWdlcm5vZ2luCg==") diff --git a/akka-http-core/src/test/scala/akka/http/scaladsl/TestServer.scala b/akka-http-core/src/test/scala/akka/http/scaladsl/TestServer.scala index 6b79a4d328..eeccdd9442 100644 --- a/akka-http-core/src/test/scala/akka/http/scaladsl/TestServer.scala +++ b/akka-http-core/src/test/scala/akka/http/scaladsl/TestServer.scala @@ -27,17 +27,17 @@ object TestServer extends App { try { val binding = Http().bindAndHandleSync({ - case req @ HttpRequest(GET, Uri.Path("/"), _, _, _) if req.header[UpgradeToWebsocket].isDefined ⇒ - req.header[UpgradeToWebsocket] match { - case Some(upgrade) ⇒ upgrade.handleMessages(echoWebsocketService) // needed for running the autobahn test suite + case req @ HttpRequest(GET, Uri.Path("/"), _, _, _) if req.header[UpgradeToWebSocket].isDefined ⇒ + req.header[UpgradeToWebSocket] match { + case Some(upgrade) ⇒ upgrade.handleMessages(echoWebSocketService) // needed for running the autobahn test suite case None ⇒ HttpResponse(400, entity = "Not a valid websocket request!") } case HttpRequest(GET, Uri.Path("/"), _, _, _) ⇒ index case HttpRequest(GET, Uri.Path("/ping"), _, _, _) ⇒ HttpResponse(entity = "PONG!") case HttpRequest(GET, Uri.Path("/crash"), _, _, _) ⇒ sys.error("BOOM!") case req @ HttpRequest(GET, Uri.Path("/ws-greeter"), _, _, _) ⇒ - req.header[UpgradeToWebsocket] match { - case Some(upgrade) ⇒ upgrade.handleMessages(greeterWebsocketService) + req.header[UpgradeToWebSocket] match { + case Some(upgrade) ⇒ upgrade.handleMessages(greeterWebSocketService) case None ⇒ HttpResponse(400, entity = "Not a valid websocket request!") } case _: HttpRequest ⇒ HttpResponse(404, entity = "Unknown resource!") @@ -66,10 +66,10 @@ object TestServer extends App { | |""".stripMargin)) - def echoWebsocketService: Flow[Message, Message, NotUsed] = + def echoWebSocketService: Flow[Message, Message, NotUsed] = Flow[Message] // just let message flow directly to the output - def greeterWebsocketService: Flow[Message, Message, NotUsed] = + def greeterWebSocketService: Flow[Message, Message, NotUsed] = Flow[Message] .collect { case TextMessage.Strict(name) ⇒ TextMessage(s"Hello '$name'") diff --git a/akka-http-testkit/src/main/scala/akka/http/scaladsl/testkit/RouteTest.scala b/akka-http-testkit/src/main/scala/akka/http/scaladsl/testkit/RouteTest.scala index afd7eed06f..73d2ccfc49 100644 --- a/akka-http-testkit/src/main/scala/akka/http/scaladsl/testkit/RouteTest.scala +++ b/akka-http-testkit/src/main/scala/akka/http/scaladsl/testkit/RouteTest.scala @@ -90,18 +90,18 @@ trait RouteTest extends RequestBuilding with WSTestRequestBuilding with RouteTes if (r.size == 1) r.head else failTest("Expected a single rejection but got %s (%s)".format(r.size, r)) } - def isWebsocketUpgrade: Boolean = - status == StatusCodes.SwitchingProtocols && header[Upgrade].exists(_.hasWebsocket) + def isWebSocketUpgrade: Boolean = + status == StatusCodes.SwitchingProtocols && header[Upgrade].exists(_.hasWebSocket) /** - * Asserts that the received response is a Websocket upgrade response and the extracts + * Asserts that the received response is a WebSocket upgrade response and the extracts * the chosen subprotocol and passes it to the handler. */ - def expectWebsocketUpgradeWithProtocol(body: String ⇒ Unit): Unit = { - if (!isWebsocketUpgrade) failTest("Response was no Websocket Upgrade response") + def expectWebSocketUpgradeWithProtocol(body: String ⇒ Unit): Unit = { + if (!isWebSocketUpgrade) failTest("Response was no WebSocket Upgrade response") header[`Sec-WebSocket-Protocol`] match { case Some(`Sec-WebSocket-Protocol`(Seq(protocol))) ⇒ body(protocol) - case _ ⇒ failTest("No Websocket protocol found in response.") + case _ ⇒ failTest("No WebSocket protocol found in response.") } } diff --git a/akka-http-testkit/src/main/scala/akka/http/scaladsl/testkit/WSTestRequestBuilding.scala b/akka-http-testkit/src/main/scala/akka/http/scaladsl/testkit/WSTestRequestBuilding.scala index e050e22eb9..1e686d79dd 100644 --- a/akka-http-testkit/src/main/scala/akka/http/scaladsl/testkit/WSTestRequestBuilding.scala +++ b/akka-http-testkit/src/main/scala/akka/http/scaladsl/testkit/WSTestRequestBuilding.scala @@ -7,7 +7,7 @@ package akka.http.scaladsl.testkit import akka.http.impl.engine.ws.InternalCustomHeader import akka.http.scaladsl.model.headers.{ UpgradeProtocol, Upgrade, `Sec-WebSocket-Protocol` } import akka.http.scaladsl.model.{ StatusCodes, HttpResponse, HttpRequest, Uri } -import akka.http.scaladsl.model.ws.{ UpgradeToWebsocket, Message } +import akka.http.scaladsl.model.ws.{ UpgradeToWebSocket, Message } import scala.collection.immutable import akka.stream.{ Graph, FlowShape } import akka.stream.scaladsl.Flow @@ -15,7 +15,7 @@ import akka.stream.scaladsl.Flow trait WSTestRequestBuilding { self: RouteTest ⇒ def WS(uri: Uri, clientSideHandler: Flow[Message, Message, Any], subprotocols: Seq[String] = Nil)(): HttpRequest = HttpRequest(uri = uri) - .addHeader(new InternalCustomHeader("UpgradeToWebsocketTestHeader") with UpgradeToWebsocket { + .addHeader(new InternalCustomHeader("UpgradeToWebSocketTestHeader") with UpgradeToWebSocket { def requestedProtocols: immutable.Seq[String] = subprotocols.toList def handleMessages(handlerFlow: Graph[FlowShape[Message, Message], Any], subprotocol: Option[String]): HttpResponse = { diff --git a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/WebsocketDirectivesSpec.scala b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/WebSocketDirectivesSpec.scala similarity index 81% rename from akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/WebsocketDirectivesSpec.scala rename to akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/WebSocketDirectivesSpec.scala index daa6f4b712..1e36679498 100644 --- a/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/WebsocketDirectivesSpec.scala +++ b/akka-http-tests/src/test/scala/akka/http/scaladsl/server/directives/WebSocketDirectivesSpec.scala @@ -14,16 +14,16 @@ import akka.http.scaladsl.testkit.WSProbe import akka.http.scaladsl.model.headers.`Sec-WebSocket-Protocol` import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.model.ws._ -import akka.http.scaladsl.server.{ UnsupportedWebsocketSubprotocolRejection, ExpectedWebsocketRequestRejection, Route, RoutingSpec } +import akka.http.scaladsl.server.{ UnsupportedWebSocketSubprotocolRejection, ExpectedWebSocketRequestRejection, Route, RoutingSpec } -class WebsocketDirectivesSpec extends RoutingSpec { - "the handleWebsocketMessages directive" should { +class WebSocketDirectivesSpec extends RoutingSpec { + "the handleWebSocketMessages directive" should { "handle websocket requests" in { val wsClient = WSProbe() WS("http://localhost/", wsClient.flow) ~> websocketRoute ~> check { - isWebsocketUpgrade shouldEqual true + isWebSocketUpgrade shouldEqual true wsClient.sendMessage("Peter") wsClient.expectMessage("Hello Peter!") @@ -42,7 +42,7 @@ class WebsocketDirectivesSpec extends RoutingSpec { WS("http://localhost/", wsClient.flow, List("other", "echo", "greeter")) ~> websocketMultipleProtocolRoute ~> check { - expectWebsocketUpgradeWithProtocol { protocol ⇒ + expectWebSocketUpgradeWithProtocol { protocol ⇒ protocol shouldEqual "echo" wsClient.sendMessage("Peter") @@ -62,7 +62,7 @@ class WebsocketDirectivesSpec extends RoutingSpec { "reject websocket requests if no subprotocol matches" in { WS("http://localhost/", Flow[Message], List("other")) ~> websocketMultipleProtocolRoute ~> check { rejections.collect { - case UnsupportedWebsocketSubprotocolRejection(p) ⇒ p + case UnsupportedWebSocketSubprotocolRejection(p) ⇒ p }.toSet shouldEqual Set("greeter", "echo") } @@ -74,20 +74,20 @@ class WebsocketDirectivesSpec extends RoutingSpec { } "reject non-websocket requests" in { Get("http://localhost/") ~> websocketRoute ~> check { - rejection shouldEqual ExpectedWebsocketRequestRejection + rejection shouldEqual ExpectedWebSocketRequestRejection } Get("http://localhost/") ~> Route.seal(websocketRoute) ~> check { status shouldEqual StatusCodes.BadRequest - responseAs[String] shouldEqual "Expected Websocket Upgrade request" + responseAs[String] shouldEqual "Expected WebSocket Upgrade request" } } } - def websocketRoute = handleWebsocketMessages(greeter) + def websocketRoute = handleWebSocketMessages(greeter) def websocketMultipleProtocolRoute = - handleWebsocketMessagesForProtocol(echo, "echo") ~ - handleWebsocketMessagesForProtocol(greeter, "greeter") + handleWebSocketMessagesForProtocol(echo, "echo") ~ + handleWebSocketMessagesForProtocol(greeter, "greeter") def greeter: Flow[Message, Message, Any] = Flow[Message].mapConcat { diff --git a/akka-http/src/main/scala/akka/http/impl/server/RejectionHandlerWrapper.scala b/akka-http/src/main/scala/akka/http/impl/server/RejectionHandlerWrapper.scala index ecf631a6cf..e512ff5cd5 100644 --- a/akka-http/src/main/scala/akka/http/impl/server/RejectionHandlerWrapper.scala +++ b/akka-http/src/main/scala/akka/http/impl/server/RejectionHandlerWrapper.scala @@ -61,10 +61,10 @@ private[http] class RejectionHandlerWrapper(javaHandler: server.RejectionHandler handleAuthorizationFailedRejection(ctx) case MissingCookieRejection(cookieName) ⇒ handleMissingCookieRejection(ctx, cookieName) - case ExpectedWebsocketRequestRejection ⇒ - handleExpectedWebsocketRequestRejection(ctx) - case UnsupportedWebsocketSubprotocolRejection(supportedProtocol) ⇒ - handleUnsupportedWebsocketSubprotocolRejection(ctx, supportedProtocol) + case ExpectedWebSocketRequestRejection ⇒ + handleExpectedWebSocketRequestRejection(ctx) + case UnsupportedWebSocketSubprotocolRejection(supportedProtocol) ⇒ + handleUnsupportedWebSocketSubprotocolRejection(ctx, supportedProtocol) case ValidationRejection(message, cause) ⇒ handleValidationRejection(ctx, message, cause.orNull) diff --git a/akka-http/src/main/scala/akka/http/impl/server/RouteImplementation.scala b/akka-http/src/main/scala/akka/http/impl/server/RouteImplementation.scala index 8ecbc91bbd..8d1ab2dbc9 100644 --- a/akka-http/src/main/scala/akka/http/impl/server/RouteImplementation.scala +++ b/akka-http/src/main/scala/akka/http/impl/server/RouteImplementation.scala @@ -158,7 +158,7 @@ private[http] object RouteImplementation extends Directives with server.RouteCon def resolve(fileName: String): ContentType = ContentTypeResolver.Default(fileName) })) - case HandleWebsocketMessages(handler) ⇒ handleWebsocketMessages(JavaMapping.toScala(handler)) + case HandleWebSocketMessages(handler) ⇒ handleWebSocketMessages(JavaMapping.toScala(handler)) case Redirect(uri, code) ⇒ redirect(uri.asScala, code.asScala.asInstanceOf[Redirection]) // guarded by require in Redirect case dyn: DynamicDirectiveRoute1[t1Type] ⇒ diff --git a/akka-http/src/main/scala/akka/http/impl/server/RouteStructure.scala b/akka-http/src/main/scala/akka/http/impl/server/RouteStructure.scala index 6d7bd3a120..831ab40448 100644 --- a/akka-http/src/main/scala/akka/http/impl/server/RouteStructure.scala +++ b/akka-http/src/main/scala/akka/http/impl/server/RouteStructure.scala @@ -84,7 +84,7 @@ private[http] object RouteStructure { case class RangeSupport()(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute - case class HandleWebsocketMessages(handler: Flow[Message, Message, Any]) extends Route + case class HandleWebSocketMessages(handler: Flow[Message, Message, Any]) extends Route case class SetCookie(cookie: HttpCookie)(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute case class DeleteCookie(name: String, domain: Option[String], path: Option[String])(val innerRoute: Route, val moreInnerRoutes: immutable.Seq[Route]) extends DirectiveRoute diff --git a/akka-http/src/main/scala/akka/http/javadsl/server/Directives.scala b/akka-http/src/main/scala/akka/http/javadsl/server/Directives.scala index a06592c0b2..d722a76b44 100644 --- a/akka-http/src/main/scala/akka/http/javadsl/server/Directives.scala +++ b/akka-http/src/main/scala/akka/http/javadsl/server/Directives.scala @@ -9,7 +9,7 @@ import scala.collection.immutable import scala.annotation.varargs import akka.http.javadsl.model.HttpMethods -abstract class AllDirectives extends WebsocketDirectives +abstract class AllDirectives extends WebSocketDirectives /** * diff --git a/akka-http/src/main/scala/akka/http/javadsl/server/RejectionHandler.scala b/akka-http/src/main/scala/akka/http/javadsl/server/RejectionHandler.scala index 85e2738451..56f5626bfd 100644 --- a/akka-http/src/main/scala/akka/http/javadsl/server/RejectionHandler.scala +++ b/akka-http/src/main/scala/akka/http/javadsl/server/RejectionHandler.scala @@ -157,13 +157,13 @@ abstract class RejectionHandler { /** * Callback called to handle rejection created when a websocket request was expected but none was found. */ - def handleExpectedWebsocketRequestRejection(ctx: RequestContext): RouteResult = passRejection() + def handleExpectedWebSocketRequestRejection(ctx: RequestContext): RouteResult = passRejection() /** * Callback called to handle rejection created when a websocket request was not handled because none * of the given subprotocols was supported. */ - def handleUnsupportedWebsocketSubprotocolRejection(ctx: RequestContext, supportedProtocol: String): RouteResult = passRejection() + def handleUnsupportedWebSocketSubprotocolRejection(ctx: RequestContext, supportedProtocol: String): RouteResult = passRejection() /** * Callback called to handle rejection created by the `validation` directive as well as for `IllegalArgumentExceptions` diff --git a/akka-http/src/main/scala/akka/http/javadsl/server/directives/WebsocketDirectives.scala b/akka-http/src/main/scala/akka/http/javadsl/server/directives/WebSocketDirectives.scala similarity index 61% rename from akka-http/src/main/scala/akka/http/javadsl/server/directives/WebsocketDirectives.scala rename to akka-http/src/main/scala/akka/http/javadsl/server/directives/WebSocketDirectives.scala index 12d42c4ba9..0ecfed40fb 100644 --- a/akka-http/src/main/scala/akka/http/javadsl/server/directives/WebsocketDirectives.scala +++ b/akka-http/src/main/scala/akka/http/javadsl/server/directives/WebSocketDirectives.scala @@ -9,11 +9,11 @@ import akka.http.impl.server.RouteStructure import akka.http.javadsl.model.ws.Message import akka.stream.javadsl.Flow -abstract class WebsocketDirectives extends SchemeDirectives { +abstract class WebSocketDirectives extends SchemeDirectives { /** * Handles websocket requests with the given handler and rejects other requests with a - * [[ExpectedWebsocketRequestRejection]]. + * [[ExpectedWebSocketRequestRejection]]. */ - def handleWebsocketMessages(handler: Flow[Message, Message, _]): Route = - RouteStructure.HandleWebsocketMessages(handler) + def handleWebSocketMessages(handler: Flow[Message, Message, _]): Route = + RouteStructure.HandleWebSocketMessages(handler) } diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/Directives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/Directives.scala index 30a0c9affe..1dbfbfca7e 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/Directives.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/Directives.scala @@ -29,6 +29,6 @@ trait Directives extends RouteConcatenation with RouteDirectives with SchemeDirectives with SecurityDirectives - with WebsocketDirectives + with WebSocketDirectives object Directives extends Directives diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/Rejection.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/Rejection.scala index 3a09367347..b258e3cf53 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/Rejection.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/Rejection.scala @@ -166,13 +166,13 @@ case class MissingCookieRejection(cookieName: String) extends Rejection /** * Rejection created when a websocket request was expected but none was found. */ -case object ExpectedWebsocketRequestRejection extends Rejection +case object ExpectedWebSocketRequestRejection extends Rejection /** * Rejection created when a websocket request was not handled because none of the given subprotocols * was supported. */ -case class UnsupportedWebsocketSubprotocolRejection(supportedProtocol: String) extends Rejection +case class UnsupportedWebSocketSubprotocolRejection(supportedProtocol: String) extends Rejection /** * Rejection created by the `validation` directive as well as for `IllegalArgumentExceptions` diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/RejectionHandler.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/RejectionHandler.scala index 864694878e..4ae710abe1 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/RejectionHandler.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/RejectionHandler.scala @@ -204,8 +204,8 @@ object RejectionHandler { val supported = rejections.map(_.supported.value).mkString(" or ") complete((BadRequest, "The request's Content-Encoding is not supported. Expected:\n" + supported)) } - .handle { case ExpectedWebsocketRequestRejection ⇒ complete((BadRequest, "Expected Websocket Upgrade request")) } - .handleAll[UnsupportedWebsocketSubprotocolRejection] { rejections ⇒ + .handle { case ExpectedWebSocketRequestRejection ⇒ complete((BadRequest, "Expected WebSocket Upgrade request")) } + .handleAll[UnsupportedWebSocketSubprotocolRejection] { rejections ⇒ val supported = rejections.map(_.supportedProtocol) complete(HttpResponse(BadRequest, entity = s"None of the websocket subprotocols offered in the request are supported. Supported are ${supported.map("'" + _ + "'").mkString(",")}.", diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebSocketDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebSocketDirectives.scala new file mode 100644 index 0000000000..aaadb7a8ce --- /dev/null +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebSocketDirectives.scala @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2009-2015 Typesafe Inc. + */ + +package akka.http.scaladsl.server +package directives + +import scala.collection.immutable + +import akka.http.scaladsl.model.ws.{ UpgradeToWebSocket, Message } +import akka.stream.scaladsl.Flow + +trait WebSocketDirectives { + import RouteDirectives._ + import HeaderDirectives._ + import BasicDirectives._ + + /** + * Extract the [[UpgradeToWebSocket]] header if existent. Rejects with an [[ExpectedWebSocketRequestRejection]], otherwise. + */ + def extractUpgradeToWebSocket: Directive1[UpgradeToWebSocket] = + optionalHeaderValueByType[UpgradeToWebSocket](()).flatMap { + case Some(upgrade) ⇒ provide(upgrade) + case None ⇒ reject(ExpectedWebSocketRequestRejection) + } + + /** + * Extract the list of WebSocket subprotocols as offered by the client in the [[Sec-WebSocket-Protocol]] header if + * this is a WebSocket request. Rejects with an [[ExpectedWebSocketRequestRejection]], otherwise. + */ + def extractOfferedWsProtocols: Directive1[immutable.Seq[String]] = extractUpgradeToWebSocket.map(_.requestedProtocols) + + /** + * Handles WebSocket requests with the given handler and rejects other requests with an + * [[ExpectedWebSocketRequestRejection]]. + */ + def handleWebSocketMessages(handler: Flow[Message, Message, Any]): Route = + handleWebSocketMessagesForOptionalProtocol(handler, None) + + /** + * Handles WebSocket requests with the given handler if the given subprotocol is offered in the request and + * rejects other requests with an [[ExpectedWebSocketRequestRejection]] or an [[UnsupportedWebSocketSubprotocolRejection]]. + */ + def handleWebSocketMessagesForProtocol(handler: Flow[Message, Message, Any], subprotocol: String): Route = + handleWebSocketMessagesForOptionalProtocol(handler, Some(subprotocol)) + + /** + * Handles WebSocket requests with the given handler and rejects other requests with an + * [[ExpectedWebSocketRequestRejection]]. + * + * If the `subprotocol` parameter is None any WebSocket request is accepted. If the `subprotocol` parameter is + * `Some(protocol)` a WebSocket request is only accepted if the list of subprotocols supported by the client (as + * announced in the WebSocket request) contains `protocol`. If the client did not offer the protocol in question + * the request is rejected with an [[UnsupportedWebSocketSubprotocolRejection]] rejection. + * + * To support several subprotocols you may chain several `handleWebSocketMessage` Routes. + */ + def handleWebSocketMessagesForOptionalProtocol(handler: Flow[Message, Message, Any], subprotocol: Option[String]): Route = + extractUpgradeToWebSocket { upgrade ⇒ + if (subprotocol.forall(sub ⇒ upgrade.requestedProtocols.exists(_ equalsIgnoreCase sub))) + complete(upgrade.handleMessages(handler, subprotocol)) + else + reject(UnsupportedWebSocketSubprotocolRejection(subprotocol.get)) // None.forall == true + } +} diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebsocketDirectives.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebsocketDirectives.scala deleted file mode 100644 index 5768c4ea25..0000000000 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/directives/WebsocketDirectives.scala +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2009-2015 Typesafe Inc. - */ - -package akka.http.scaladsl.server -package directives - -import scala.collection.immutable - -import akka.http.scaladsl.model.ws.{ UpgradeToWebsocket, Message } -import akka.stream.scaladsl.Flow - -trait WebsocketDirectives { - import RouteDirectives._ - import HeaderDirectives._ - import BasicDirectives._ - - /** - * Extract the [[UpgradeToWebsocket]] header if existent. Rejects with an [[ExpectedWebsocketRequestRejection]], otherwise. - */ - def extractUpgradeToWebsocket: Directive1[UpgradeToWebsocket] = - optionalHeaderValueByType[UpgradeToWebsocket](()).flatMap { - case Some(upgrade) ⇒ provide(upgrade) - case None ⇒ reject(ExpectedWebsocketRequestRejection) - } - - /** - * Extract the list of Websocket subprotocols as offered by the client in the [[Sec-Websocket-Protocol]] header if - * this is a Websocket request. Rejects with an [[ExpectedWebsocketRequestRejection]], otherwise. - */ - def extractOfferedWsProtocols: Directive1[immutable.Seq[String]] = extractUpgradeToWebsocket.map(_.requestedProtocols) - - /** - * Handles Websocket requests with the given handler and rejects other requests with an - * [[ExpectedWebsocketRequestRejection]]. - */ - def handleWebsocketMessages(handler: Flow[Message, Message, Any]): Route = - handleWebsocketMessagesForOptionalProtocol(handler, None) - - /** - * Handles Websocket requests with the given handler if the given subprotocol is offered in the request and - * rejects other requests with an [[ExpectedWebsocketRequestRejection]] or an [[UnsupportedWebsocketSubprotocolRejection]]. - */ - def handleWebsocketMessagesForProtocol(handler: Flow[Message, Message, Any], subprotocol: String): Route = - handleWebsocketMessagesForOptionalProtocol(handler, Some(subprotocol)) - - /** - * Handles Websocket requests with the given handler and rejects other requests with an - * [[ExpectedWebsocketRequestRejection]]. - * - * If the `subprotocol` parameter is None any Websocket request is accepted. If the `subprotocol` parameter is - * `Some(protocol)` a Websocket request is only accepted if the list of subprotocols supported by the client (as - * announced in the Websocket request) contains `protocol`. If the client did not offer the protocol in question - * the request is rejected with an [[UnsupportedWebsocketSubprotocolRejection]] rejection. - * - * To support several subprotocols you may chain several `handleWebsocketMessage` Routes. - */ - def handleWebsocketMessagesForOptionalProtocol(handler: Flow[Message, Message, Any], subprotocol: Option[String]): Route = - extractUpgradeToWebsocket { upgrade ⇒ - if (subprotocol.forall(sub ⇒ upgrade.requestedProtocols.exists(_ equalsIgnoreCase sub))) - complete(upgrade.handleMessages(handler, subprotocol)) - else - reject(UnsupportedWebsocketSubprotocolRejection(subprotocol.get)) // None.forall == true - } -}