Skip to content

Commit

Permalink
Allow users to directly configure Akka HTTP settings (#8392)
Browse files Browse the repository at this point in the history
* Allow users to directly configure Akka HTTP settings

Fixes #8368.

Refactor the AkkaHttpServer class so that more of its internal
behavior is accessible to advanced users. Users can now extend
this class and override behavior through protected methods.
The custom class can be hooked into Play through the existing
play.server.provider setting.

By allowing users to change the Akka HTTP server behavior,
particularly the server settings, we reduce the pressure on
Play to provide a perfect and universal configuration out of
the box. We can now provide a configuration that is right for
most users and allow advanced users to reconfigure their
settings as needed.

For example, it is now possible to modify the Akka HTTP server's
configuration to extend the list of HTTP methods that is
supported. This example is shown in an integration test.

* Reduce API surface; use context

* Documentation

* Fix compile error

* Add documentation source files

* Fix doc tests; minor doc tweak

* Copyright to 2018

* Fix broken doc links

* Added blank line after header
  • Loading branch information
richdougherty authored and jroper committed May 10, 2018
1 parent 6768cb9 commit ba0ce3e
Show file tree
Hide file tree
Showing 12 changed files with 338 additions and 57 deletions.
Expand Up @@ -44,7 +44,7 @@ There are a couple of special things to know about configuration when running yo
You can configure extra settings for the `run` command in your `build.sbt`. These settings won't be used when you deploy your application.

```
PlayKeys.devSettings := Seq("play.server.http.port" -> "8080")
PlayKeys.devSettings += "play.server.http.port" -> "8080"
```

### HTTP server settings in `application.conf`
Expand Down
Expand Up @@ -21,8 +21,30 @@ You can read more about the configuration settings in the [Akka HTTP documentati
>
> They will be automatically recognized. Keep in mind that Play configurations listed above will override the Akka ones.
There is also a separate configuration file for the HTTP/2 support in Akka HTTP, if you have enabled the `AkkaHttp2Support` plugin:
There is also a separate configuration file for the HTTP/2 support in Akka HTTP, if you have [[enabled the `AkkaHttp2Support` plugin|AkkaHttpServer#HTTP/2-support-(experimental)]]:

@[](/confs/play-akka-http2-support/reference.conf)

> **Note:** In dev mode, when you use the `run` command, your `application.conf` settings will not be picked up by the server. This is because in dev mode the server starts before the application classpath is available. There are several [[other options|ConfigFile#Using-with-the-run-command]] you'll need to use instead.
## Direct Akka HTTP configuration

If you need direct access to Akka HTTP's `ServerSettings` and `ParserSettings` objects you can do this by extending Play's `AkkaHttpServer` class with your own. The `AkkaHttpServer` class has several protected methods which can be overridden to change how Play configures its Akka HTTP backend.

Note that writing your own server class is advanced usage. Usually you can do all the configuration you need through normal configuration settings.

The code below shows an example of a custom server which modifies some Akka HTTP settings. Below the server class is a `ServerProvider` class which acts as a factory for the custom server.

@[custom-akka-http-server](code/CustomAkkaHttpServer.scala)

Once you've written a custom server and `ServerProvider` class you'll need to tell Play about them by setting the `play.server.provider` configuration option to the full name of your `ServerProvider` class.

For example, adding the following settings to your `build.sbt` and `application.conf` will tell Play to use your new server for both the sbt `run` task and when your application is deployed.

`build.sbt`:

@[custom-akka-http-server-provider](code/build.sbt)

`application.conf`:

@[custom-akka-http-server-provider](code/application.conf)
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2009-2018 Lightbend Inc. <https://www.lightbend.com>
*/

//#custom-akka-http-server
//###replace: package server
package detailedtopics.configuration.customakkaserver

import java.util.Random
import play.core.server.{AkkaHttpServer, AkkaHttpServerProvider, ServerProvider}
import akka.http.scaladsl.ConnectionContext
import akka.http.scaladsl.model.HttpMethod
import akka.http.scaladsl.settings.{ParserSettings, ServerSettings}

/** A custom Akka HTTP server with advanced configuration. */
class CustomAkkaHttpServer(context: AkkaHttpServer.Context) extends AkkaHttpServer(context) {
override protected def createParserSettings(): ParserSettings = {
val defaultSettings: ParserSettings =
super.createParserSettings()
defaultSettings.withCustomMethods(HttpMethod.custom("TICKLE"))
}
override protected def createServerSettings(port: Int, connectionContext: ConnectionContext, secure: Boolean): ServerSettings = {
val defaultSettings: ServerSettings =
super.createServerSettings(port, connectionContext, secure)
defaultSettings.withWebsocketRandomFactory(() => new Random())
}
}

/** A factory that instantiates a CustomAkkaHttpServer. */
class CustomAkkaHttpServerProvider extends ServerProvider {
def createServer(context: ServerProvider.Context) = {
val serverContext = AkkaHttpServer.Context.fromServerProviderContext(context)
new CustomAkkaHttpServer(serverContext)
}
}
//#custom-akka-http-server
@@ -0,0 +1,4 @@
//#custom-akka-http-server-provider
//###replace: play.server.provider = server.CustomAkkaHttpServerProvider
#play.server.provider = server.CustomAkkaHttpServerProvider
//#custom-akka-http-server-provider
Expand Up @@ -4,7 +4,9 @@ libraryDependencies += ehcache
//#play-ws-cache-deps

//#prefix-with-play-akka-dev-mode
PlayKeys.devSettings ++= Seq(
"play.akka.dev-mode.akka.cluster.log-info" -> "off"
)
PlayKeys.devSettings += "play.akka.dev-mode.akka.cluster.log-info" -> "off"
//#prefix-with-play-akka-dev-mode

//#custom-akka-http-server-provider
PlayKeys.devSettings += "play.server.provider" -> "server.CustomAkkaHttpServerProvider"
//#custom-akka-http-server-provider
Expand Up @@ -3,6 +3,8 @@

Play uses the [Akka HTTP](https://doc.akka.io/docs/akka-http/current/index.html) server backend to implement HTTP requests and responses using Akka Streams over the network. Akka HTTP implements a full server stack for HTTP, including full HTTPS support, and has support for HTTP/2.

The Akka HTTP server backend is the default in Play. You can also use the [[Netty backend|NettyServer]] if you choose.

## Akka HTTP Implementation

Play's server backend uses the [low level server API](https://doc.akka.io/docs/akka-http/current/server-side/low-level-api.html?language=scala) to handle Akka's `HttpRequest` and `HttpResponse` classes.
Expand All @@ -19,7 +21,7 @@ Please configure any work with blocking APIs off the main rendering thread, usin

## Configuring Akka HTTP

You can configure the Akka HTTP server settings through [[application.conf|SettingsAkkaHttp]]. That also describes how to enable the HTTP/2 support.
There are a variety of options that can be configured for the Akka HTTP server. These are given in the [[documentation on configuring Akka HTTP|SettingsAkkaHttp]].

## HTTP/2 support (experimental)

Expand Down Expand Up @@ -54,3 +56,23 @@ export AGENT=$(pwd)/$(find target -name 'jetty-alpn-agent-*.jar' | head -1)
```

You also may want to write a simple script to run your app with the needed options, as demonstrated the `./play` script in the [play-scala-tls-example](https://github.com/playframework/play-scala-tls-example/blob/2.5.x/play)

## Manually selecting the Akka HTTP server

If for some reason you have both the Akka HTTP and the Netty server JARs on your classpath, then Play won't be able to predictably choose a server backend. You'll need to manually select the Akka HTTP server. This can be done by explicitly overriding the `play.server.provider` configuration option and setting it to a value of `play.core.server.AkkaHttpServerProvider`.

The `play.server.provider` configuration setting can be set in the same way as other configuration options. Different methods of setting configuration are described in the [[configuration file documentation|ConfigFile]]. Several examples of enabling the Akka HTTP server backend are shown below.

The recommended way to do this is to add the setting to two places. First, to enable Akka HTTP for the sbt `run` task, add the following to your `build.sbt`:

```
PlayKeys.devSettings += "play.server.provider" -> "play.core.server.AkkaHttpServerProvider"
```

Second, to enable the Akka HTTP backend for when you deploy your application or when you use the sbt `start` task, add the following to your `application.conf` file:

```
play.server.provider = play.core.server.AkkaHttpServerProvider
```

By adding the setting to both `build.sbt` and `application.conf` you can ensure that the Akka HTTP backend will be used in all cases.
16 changes: 14 additions & 2 deletions documentation/manual/working/commonGuide/server/NettyServer.md
Expand Up @@ -17,12 +17,24 @@ Now Play should automatically select the Netty server for running in dev mode, p

## Manually selecting the Netty server

If for some reason you have both the Akka HTTP server and the Netty HTTP server on your classpath, you'll need to manually select it. This can be done using the `play.server.provider` system property, for example, in dev mode:
If for some reason you have both the Akka HTTP and the Netty server JARs on your classpath, then Play won't be able to predictably choose a server backend. You'll need to manually select the Netty server. This can be done by explicitly overriding the `play.server.provider` configuration option and setting it to a value of `play.core.server.NettyServerProvider`.

The `play.server.provider` configuration setting can be set in the same way as other configuration options. Different methods of setting configuration are described in the [[configuration file documentation|ConfigFile]]. Several examples of enabling the Netty server are shown below.

The recommended way to do this is to add the setting to two places. First, to enable Netty for the sbt `run` task, add the following to your `build.sbt`:

```
run -Dplay.server.provider=play.core.server.NettyServerProvider
PlayKeys.devSettings += "play.server.provider" -> "play.core.server.NettyServerProvider"
```

Second, to enable the Netty backend for when you deploy your application or when you use the sbt `start` task, add the following to your `application.conf` file:

```
play.server.provider = play.core.server.NettyServerProvider
```

By adding the setting to both `build.sbt` and `application.conf` you can ensure that the Netty backend will be used in all cases.

## Verifying that the Netty server is running

When the Netty server is running the request attribute `RequestAttrKey.Server` with the value `netty` will be set for all requests. The Akka HTTP backend will not set a value for this request attribute.
Expand Down

0 comments on commit ba0ce3e

Please sign in to comment.