diff --git a/akka-docs-dev/rst/java/http/http-model.rst b/akka-docs-dev/rst/java/http/http-model.rst index 6783d95212..7d469146df 100644 --- a/akka-docs-dev/rst/java/http/http-model.rst +++ b/akka-docs-dev/rst/java/http/http-model.rst @@ -254,3 +254,17 @@ Parsing / Rendering Parsing and rendering of HTTP data structures is heavily optimized and for most types there's currently no public API provided to parse (or render to) Strings or byte arrays. + +.. note:: + Various parsing and rendering settings are available to tweak in the configuration under ``akka.http.client[.parsing]``, + ``akka.http.server[.parsing]`` and ``akka.http.host-connection-pool[.client.parsing]``, with defaults for all of these + being defined in the ``akka.http.parsing`` configuration section. + + For example, if you want to change a parsing setting for all components, you can set the ``akka.http.parsing.illegal-header-warnings = off`` + value. However this setting can be stil overriden by the more specific sections, like for example ``akka.http.server.parsing.illegal-header-warnings = on``. + In this case both ``client`` and ``host-connection-pool`` APIs will see the setting ``off``, however the server will see ``on``. + + In the case of ``akka.http.host-connection-pool.client`` settings, they default to settings set in ``akka.http.client``, + and can override them if needed. This is useful, since both ``client`` and ``host-connection-pool`` APIs, + such as the Client API ``Http.get(sys).outgoingConnection`` or the Host Connection Pool APIs ``Http.get(sys).singleRequest`` + or ``Http.get(sys).superPool``, usually need the same settings, however the ``server`` most likely has a very different set of settings. diff --git a/akka-docs-dev/rst/scala/http/common/http-model.rst b/akka-docs-dev/rst/scala/http/common/http-model.rst index 39dbd13d79..152a0b764b 100644 --- a/akka-docs-dev/rst/scala/http/common/http-model.rst +++ b/akka-docs-dev/rst/scala/http/common/http-model.rst @@ -250,3 +250,17 @@ Parsing / Rendering Parsing and rendering of HTTP data structures is heavily optimized and for most types there's currently no public API provided to parse (or render to) Strings or byte arrays. + +.. note:: + Various parsing and rendering settings are available to tweak in the configuration under ``akka.http.client[.parsing]``, + ``akka.http.server[.parsing]`` and ``akka.http.host-connection-pool[.client.parsing]``, with defaults for all of these + being defined in the ``akka.http.parsing`` configuration section. + + For example, if you want to change a parsing setting for all components, you can set the ``akka.http.parsing.illegal-header-warnings = off`` + value. However this setting can be stil overriden by the more specific sections, like for example ``akka.http.server.parsing.illegal-header-warnings = on``. + In this case both ``client`` and ``host-connection-pool`` APIs will see the setting ``off``, however the server will see ``on``. + + In the case of ``akka.http.host-connection-pool.client`` settings, they default to settings set in ``akka.http.client``, + and can override them if needed. This is useful, since both ``client`` and ``host-connection-pool`` APIs, + such as the Client API ``Http().outgoingConnection`` or the Host Connection Pool APIs ``Http().singleRequest`` or ``Http().superPool``, + usually need the same settings, however the ``server`` most likely has a very different set of settings. diff --git a/akka-http-core/src/main/resources/reference.conf b/akka-http-core/src/main/resources/reference.conf index 4cd7e35465..34a6e5a77e 100644 --- a/akka-http-core/src/main/resources/reference.conf +++ b/akka-http-core/src/main/resources/reference.conf @@ -88,7 +88,9 @@ akka.http { } # Modify to tweak parsing settings on the server-side only. - parsing = ${akka.http.parsing} + parsing { + # no overrides by default, see `akka.http.parsing` for default values + } } client { @@ -142,7 +144,9 @@ akka.http { } # Modify to tweak parsing settings on the client-side only. - parsing = ${akka.http.parsing} + parsing { + # no overrides by default, see `akka.http.parsing` for default values + } } host-connection-pool { @@ -179,15 +183,73 @@ akka.http { idle-timeout = 30 s # Modify to tweak client settings for host connection pools only. - client = ${akka.http.client} + # + # IMPORTANT: + # Please note that this section mirrors `akka.http.client` however is used only for pool-based APIs, + # such as `Http().superPool` or `Http().singleRequest`. + client = { + # The default value of the `User-Agent` header to produce if no + # explicit `User-Agent`-header was included in a request. + # If this value is the empty string and no header was included in + # the request, no `User-Agent` header will be rendered at all. + user-agent-header = akka-http/${akka.version} + + # The time period within which the TCP connecting process must be completed. + connecting-timeout = 10s + + # The time after which an idle connection will be automatically closed. + # Set to `infinite` to completely disable idle timeouts. + idle-timeout = 60 s + + # The initial size of the buffer to render the request headers in. + # Can be used for fine-tuning request rendering performance but probably + # doesn't have to be fiddled with in most applications. + request-header-size-hint = 512 + + # The proxy configurations to be used for requests with the specified + # scheme. + proxy { + # Proxy settings for unencrypted HTTP requests + # Set to 'none' to always connect directly, 'default' to use the system + # settings as described in http://docs.oracle.com/javase/6/docs/technotes/guides/net/proxies.html + # or specify the proxy host, port and non proxy hosts as demonstrated + # in the following example: + # http { + # host = myproxy.com + # port = 8080 + # non-proxy-hosts = ["*.direct-access.net"] + # } + http = default + + # Proxy settings for HTTPS requests (currently unsupported) + https = default + } + + # Socket options to set for the listening socket. If a setting is left + # undefined, it will use whatever the default on the system is. + socket-options { + so-receive-buffer-size = undefined + so-send-buffer-size = undefined + so-reuse-address = undefined + so-traffic-class = undefined + tcp-keep-alive = undefined + tcp-oob-inline = undefined + tcp-no-delay = undefined + } + + + # IMPORTANT: Please note that this section is replicated in `client` and `server`. + parsing { + # no overrides by default, see `akka.http.parsing` for default values + } + } } - # The (default) configuration of the HTTP message parser for the server and the client. - # IMPORTANT: These settings (i.e. children of `akka.http.parsing`) can't be directly - # overridden in `application.conf` to change the parser settings for client and server - # at the same time. Instead, override the concrete settings beneath - # `akka.http.server.parsing` and `akka.http.client.parsing` - # where these settings are copied to. + # Modify to tweak default parsing settings. + # + # IMPORTANT: + # Please note that this sections settings can be overriden by the corresponding settings in: + # `akka.http.server.parsing`, `akka.http.client.parsing` or `akka.http.http-connection-pool.client.parsing`. parsing { # The limits for the various parts of the HTTP message parser. max-uri-length = 2k diff --git a/akka-http-core/src/main/scala/akka/http/ClientConnectionSettings.scala b/akka-http-core/src/main/scala/akka/http/ClientConnectionSettings.scala index dc1aacaa74..1718e7a41f 100644 --- a/akka-http-core/src/main/scala/akka/http/ClientConnectionSettings.scala +++ b/akka-http-core/src/main/scala/akka/http/ClientConnectionSettings.scala @@ -29,14 +29,15 @@ final case class ClientConnectionSettings( } object ClientConnectionSettings extends SettingsCompanion[ClientConnectionSettings]("akka.http.client") { - def fromSubConfig(c: Config) = { + def fromSubConfig(root: Config, inner: Config) = { + val c = inner.withFallback(root.getConfig(prefix)) apply( c.getString("user-agent-header").toOption.map(`User-Agent`(_)), c getFiniteDuration "connecting-timeout", c getPotentiallyInfiniteDuration "idle-timeout", c getIntBytes "request-header-size-hint", - SocketOptionSettings fromSubConfig c.getConfig("socket-options"), - ParserSettings fromSubConfig c.getConfig("parsing")) + SocketOptionSettings.fromSubConfig(root, c.getConfig("socket-options")), + ParserSettings.fromSubConfig(root, c.getConfig("parsing"))) } /** diff --git a/akka-http-core/src/main/scala/akka/http/ConnectionPoolSettings.scala b/akka-http-core/src/main/scala/akka/http/ConnectionPoolSettings.scala index 7161854889..b990bd4383 100644 --- a/akka-http-core/src/main/scala/akka/http/ConnectionPoolSettings.scala +++ b/akka-http-core/src/main/scala/akka/http/ConnectionPoolSettings.scala @@ -5,15 +5,14 @@ package akka.http import java.lang.{ Iterable ⇒ JIterable } -import akka.http.scaladsl.HttpsContext -import com.typesafe.config.Config -import scala.collection.immutable -import scala.concurrent.duration.Duration -import akka.japi.Util._ + import akka.actor.ActorSystem import akka.event.LoggingAdapter import akka.http.impl.util._ -import akka.io.Inet +import akka.http.scaladsl.HttpsContext +import com.typesafe.config.Config + +import scala.concurrent.duration.Duration final case class HostConnectionPoolSetup(host: String, port: Int, setup: ConnectionPoolSetup) @@ -42,18 +41,18 @@ final case class ConnectionPoolSettings( require(maxRetries >= 0, "max-retries must be >= 0") require(maxOpenRequests > 0 && (maxOpenRequests & (maxOpenRequests - 1)) == 0, "max-open-requests must be a power of 2 > 0") require(pipeliningLimit > 0, "pipelining-limit must be > 0") - require(idleTimeout >= Duration.Zero, "idleTimeout must be >= 0") + require(idleTimeout >= Duration.Zero, "idle-timeout must be >= 0") } object ConnectionPoolSettings extends SettingsCompanion[ConnectionPoolSettings]("akka.http.host-connection-pool") { - def fromSubConfig(c: Config) = { + def fromSubConfig(root: Config, c: Config) = { apply( c getInt "max-connections", c getInt "max-retries", c getInt "max-open-requests", c getInt "pipelining-limit", c getPotentiallyInfiniteDuration "idle-timeout", - ClientConnectionSettings fromSubConfig c.getConfig("client")) + ClientConnectionSettings.fromSubConfig(root, c.getConfig("client"))) } /** diff --git a/akka-http-core/src/main/scala/akka/http/ParserSettings.scala b/akka-http-core/src/main/scala/akka/http/ParserSettings.scala index 99b74b19a6..9d08dd499a 100644 --- a/akka-http-core/src/main/scala/akka/http/ParserSettings.scala +++ b/akka-http-core/src/main/scala/akka/http/ParserSettings.scala @@ -55,7 +55,8 @@ final case class ParserSettings( } object ParserSettings extends SettingsCompanion[ParserSettings]("akka.http.parsing") { - def fromSubConfig(c: Config) = { + def fromSubConfig(root: Config, inner: Config) = { + val c = inner.withFallback(root.getConfig(prefix)) val cacheConfig = c getConfig "header-cache" apply( diff --git a/akka-http-core/src/main/scala/akka/http/ServerSettings.scala b/akka-http-core/src/main/scala/akka/http/ServerSettings.scala index baba8b8152..e1d4a3197a 100644 --- a/akka-http-core/src/main/scala/akka/http/ServerSettings.scala +++ b/akka-http-core/src/main/scala/akka/http/ServerSettings.scala @@ -45,7 +45,7 @@ object ServerSettings extends SettingsCompanion[ServerSettings]("akka.http.serve } implicit def timeoutsShortcut(s: ServerSettings): Timeouts = s.timeouts - def fromSubConfig(c: Config) = apply( + def fromSubConfig(root: Config, c: Config) = apply( c.getString("server-header").toOption.map(Server(_)), Timeouts( c getPotentiallyInfiniteDuration "idle-timeout", @@ -57,7 +57,7 @@ object ServerSettings extends SettingsCompanion[ServerSettings]("akka.http.serve c getBoolean "verbose-error-messages", c getIntBytes "response-header-size-hint", c getInt "backlog", - SocketOptionSettings fromSubConfig c.getConfig("socket-options"), + SocketOptionSettings.fromSubConfig(root, c.getConfig("socket-options")), defaultHostHeader = HttpHeader.parse("Host", c getString "default-host-header") match { case HttpHeader.ParsingResult.Ok(x: Host, Nil) ⇒ x @@ -65,7 +65,7 @@ object ServerSettings extends SettingsCompanion[ServerSettings]("akka.http.serve val info = result.errors.head.withSummary("Configured `default-host-header` is illegal") throw new ConfigurationException(info.formatPretty) }, - ParserSettings fromSubConfig c.getConfig("parsing")) + ParserSettings.fromSubConfig(root, c.getConfig("parsing"))) def apply(optionalSettings: Option[ServerSettings])(implicit actorRefFactory: ActorRefFactory): ServerSettings = optionalSettings getOrElse apply(actorSystem) diff --git a/akka-http-core/src/main/scala/akka/http/impl/util/SettingsCompanion.scala b/akka-http-core/src/main/scala/akka/http/impl/util/SettingsCompanion.scala index 0d3069f084..0b17652f46 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/util/SettingsCompanion.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/util/SettingsCompanion.scala @@ -15,7 +15,7 @@ import akka.actor.ActorSystem /** * INTERNAL API */ -private[http] abstract class SettingsCompanion[T](prefix: String) { +private[http] abstract class SettingsCompanion[T](protected val prefix: String) { private final val MaxCached = 8 private[this] var cache = ListMap.empty[ActorSystem, T] @@ -41,9 +41,9 @@ private[http] abstract class SettingsCompanion[T](prefix: String) { .withFallback(defaultReference(getClass.getClassLoader))) def apply(config: Config): T = - fromSubConfig(config getConfig prefix) + fromSubConfig(config, config getConfig prefix) - def fromSubConfig(c: Config): T + def fromSubConfig(root: Config, c: Config): T } private[http] object SettingsCompanion { diff --git a/akka-http-core/src/main/scala/akka/http/impl/util/SocketOptionSettings.scala b/akka-http-core/src/main/scala/akka/http/impl/util/SocketOptionSettings.scala index d79e02e6f1..f07d29c182 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/util/SocketOptionSettings.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/util/SocketOptionSettings.scala @@ -12,11 +12,11 @@ import akka.io.Inet.SocketOption import com.typesafe.config.Config private[http] object SocketOptionSettings { - def fromSubConfig(config: Config): immutable.Traversable[SocketOption] = { + def fromSubConfig(root: Config, c: Config): immutable.Traversable[SocketOption] = { def so[T](setting: String)(f: (Config, String) ⇒ T)(cons: T ⇒ SocketOption): List[SocketOption] = - config.getString(setting) match { + c.getString(setting) match { case "undefined" ⇒ Nil - case x ⇒ cons(f(config, setting)) :: Nil + case x ⇒ cons(f(c, setting)) :: Nil } so("so-receive-buffer-size")(_ getIntBytes _)(Inet.SO.ReceiveBufferSize) ::: 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 b94926ecd8..e231f5013a 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 @@ -37,6 +37,8 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E // SYNCHRONIZED ACCESS ONLY! private[this] var _defaultClientHttpsContext: HttpsContext = _ + // ** SERVER ** // + /** * Creates a [[Source]] of [[IncomingConnection]] instances which represents a prospective HTTP server binding * on the given `endpoint`. @@ -52,6 +54,9 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E * * If no ``port`` is explicitly given (or the port value is negative) the protocol's default port will be used, * which is 80 for HTTP and 443 for HTTPS. + * + * To configure additional settings for a server started using this method, + * use the `akka.http.server` config section or pass in a [[ServerSettings]] explicitly. */ def bind(interface: String, port: Int = -1, settings: ServerSettings = ServerSettings(system), @@ -76,6 +81,9 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E * * The number of concurrently accepted connections can be configured by overriding * the `akka.http.server.max-connections` setting. + * + * To configure additional settings for a server started using this method, + * use the `akka.http.server` config section or pass in a [[ServerSettings]] explicitly. */ def bindAndHandle(handler: Flow[HttpRequest, HttpResponse, Any], interface: String, port: Int = -1, @@ -114,6 +122,9 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E * * The number of concurrently accepted connections can be configured by overriding * the `akka.http.server.max-connections` setting. + * + * To configure additional settings for a server started using this method, + * use the `akka.http.server` config section or pass in a [[ServerSettings]] explicitly. */ def bindAndHandleSync(handler: HttpRequest ⇒ HttpResponse, interface: String, port: Int = -1, @@ -128,6 +139,9 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E * * The number of concurrently accepted connections can be configured by overriding * the `akka.http.server.max-connections` setting. + * + * To configure additional settings for a server started using this method, + * use the `akka.http.server` config section or pass in a [[ServerSettings]] explicitly. */ def bindAndHandleAsync(handler: HttpRequest ⇒ Future[HttpResponse], interface: String, port: Int = -1, @@ -140,8 +154,10 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E type ServerLayer = Http.ServerLayer /** - * Constructs a [[ServerLayer]] stage using the configured default [[ServerSettings]]. The returned [[BidiFlow]] - * can only be materialized once. + * Constructs a [[ServerLayer]] stage using the configured default [[ServerSettings]], + * configured using the `akka.http.server` config section. + * + * The returned [[BidiFlow]] can only be materialized once. */ def serverLayer()(implicit mat: Materializer): ServerLayer = serverLayer(ServerSettings(system)) @@ -155,9 +171,14 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E log: LoggingAdapter = system.log)(implicit mat: Materializer): ServerLayer = HttpServerBluePrint(settings, remoteAddress, log) + // ** CLIENT ** // + /** * Creates a [[Flow]] representing a prospective HTTP client connection to the given endpoint. * Every materialization of the produced flow will attempt to establish a new outgoing connection. + * + * To configure additional settings for requests made using this method, + * use the `akka.http.client` config section or pass in a [[ClientConnectionSettings]] explicitly. */ def outgoingConnection(host: String, port: Int = 80, localAddress: Option[InetSocketAddress] = None, @@ -170,6 +191,9 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E * * If an explicit [[HttpsContext]] is given then it rather than the configured default [[HttpsContext]] will be used * for encryption on the connection. + * + * To configure additional settings for requests made using this method, + * use the `akka.http.client` config section or pass in a [[ClientConnectionSettings]] explicitly. */ def outgoingConnectionTls(host: String, port: Int = 443, localAddress: Option[InetSocketAddress] = None, @@ -196,7 +220,8 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E type ClientLayer = Http.ClientLayer /** - * Constructs a [[ClientLayer]] stage using the configured default [[ClientConnectionSettings]]. + * Constructs a [[ClientLayer]] stage using the configured default [[ClientConnectionSettings]], + * configured using the `akka.http.client` config section. */ def clientLayer(hostHeader: Host): ClientLayer = clientLayer(hostHeader, ClientConnectionSettings(system)) @@ -209,6 +234,8 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E log: LoggingAdapter = system.log): ClientLayer = OutgoingConnectionBlueprint(hostHeader, settings, log) + // ** CONNECTION POOL ** // + /** * Starts a new connection pool to the given host and configuration and returns a [[Flow]] which dispatches * the requests from all its materializations across this pool. @@ -222,6 +249,9 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E * response for A. * In order to allow for easy response-to-request association the flow takes in a custom, opaque context * object of type ``T`` from the application which is emitted together with the corresponding response. + * + * To configure additional settings for the pool (and requests made using it), + * use the `akka.http.host-connection-pool` config section or pass in a [[ConnectionPoolSettings]] explicitly. */ def newHostConnectionPool[T](host: String, port: Int = 80, settings: ConnectionPoolSettings = ConnectionPoolSettings(system), @@ -235,6 +265,9 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E * * If an explicit [[HttpsContext]] is given then it rather than the configured default [[HttpsContext]] will be used * for encryption on the connections. + * + * To configure additional settings for the pool (and requests made using it), + * use the `akka.http.host-connection-pool` config section or pass in a [[ConnectionPoolSettings]] explicitly. */ def newHostConnectionPoolTls[T](host: String, port: Int = 443, settings: ConnectionPoolSettings = ConnectionPoolSettings(system), @@ -280,6 +313,9 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E * response for A. * In order to allow for easy response-to-request association the flow takes in a custom, opaque context * object of type ``T`` from the application which is emitted together with the corresponding response. + * + * To configure additional settings for the pool (and requests made using it), + * use the `akka.http.host-connection-pool` config section or pass in a [[ConnectionPoolSettings]] explicitly. */ def cachedHostConnectionPool[T](host: String, port: Int = 80, settings: ConnectionPoolSettings = ConnectionPoolSettings(system), @@ -294,6 +330,9 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E * * If an explicit [[HttpsContext]] is given then it rather than the configured default [[HttpsContext]] will be used * for encryption on the connections. + * + * To configure additional settings for the pool (and requests made using it), + * use the `akka.http.host-connection-pool` config section or pass in a [[ConnectionPoolSettings]] explicitly. */ def cachedHostConnectionPoolTls[T](host: String, port: Int = 443, settings: ConnectionPoolSettings = ConnectionPoolSettings(system), @@ -338,6 +377,9 @@ class HttpExt(config: Config)(implicit system: ActorSystem) extends akka.actor.E * response for A. * In order to allow for easy response-to-request association the flow takes in a custom, opaque context * object of type ``T`` from the application which is emitted together with the corresponding response. + * + * To configure additional settings for the pool (and requests made using it), + * use the `akka.http.host-connection-pool` config section or pass in a [[ConnectionPoolSettings]] explicitly. */ def superPool[T](settings: ConnectionPoolSettings = ConnectionPoolSettings(system), httpsContext: Option[HttpsContext] = None, diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/client/HttpConfigurationSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/client/HttpConfigurationSpec.scala new file mode 100644 index 0000000000..fb8699ebc9 --- /dev/null +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/client/HttpConfigurationSpec.scala @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2009-2014 Typesafe Inc. + */ + +package akka.http.impl.engine.client + +import akka.actor.ActorSystem +import akka.http.{ ClientConnectionSettings, ConnectionPoolSettings, ServerSettings } +import akka.stream.testkit.AkkaSpec +import com.typesafe.config.ConfigFactory + +class HttpConfigurationSpec extends AkkaSpec { + + val On = true + val Off = false + + "Reference configurations" should { + "have default client and server `parsing` settings" in { + ServerSettings(system).parserSettings.toString should ===(ClientConnectionSettings(system).parserSettings.toString) + } + "have default client and pool `parsing` settings" in { + ServerSettings(system).parserSettings.toString should ===(ConnectionPoolSettings(system).connectionSettings.parserSettings.toString) + } + "have default client and pool `client` settings" in { + ClientConnectionSettings(system).toString should ===(ConnectionPoolSettings(system).connectionSettings.toString) + } + + "override value from `akka.http.parsing` by setting `akka.http.client.parsing`" in { + configuredSystem("""akka.http.client.parsing.illegal-header-warnings = off""") { sys ⇒ + val client = ClientConnectionSettings(sys) + client.parserSettings.illegalHeaderWarnings should ===(Off) + + val pool = ConnectionPoolSettings(sys) + pool.connectionSettings.parserSettings.illegalHeaderWarnings should ===(Off) + + val server = ServerSettings(sys) + server.parserSettings.illegalHeaderWarnings should ===(On) + } + } + + "override `akka.http.parsing` by setting `akka.http.host-connection-pool.client.parsing` setting" in { + configuredSystem("""akka.http.host-connection-pool.client.parsing.illegal-header-warnings = off""") { sys ⇒ + val client = ClientConnectionSettings(sys) + client.parserSettings.illegalHeaderWarnings should ===(On) + + val pool = ConnectionPoolSettings(sys) + pool.connectionSettings.parserSettings.illegalHeaderWarnings should ===(Off) + + val server = ServerSettings(sys) + server.parserSettings.illegalHeaderWarnings should ===(On) + } + } + + "set `akka.http.host-connection-pool.client.idle-timeout` only" in { + configuredSystem("""akka.http.host-connection-pool.client.idle-timeout = 1337s""") { sys ⇒ + import scala.concurrent.duration._ + + val client = ClientConnectionSettings(sys) + client.idleTimeout should ===(60.seconds) + + val pool = ConnectionPoolSettings(sys) + pool.connectionSettings.idleTimeout should ===(1337.seconds) + + val server = ServerSettings(sys) + server.idleTimeout should ===(60.seconds) // no change, default akka.http.server.idle-timeout + } + } + "set `akka.http.server.idle-timeout` only" in { + configuredSystem("""akka.http.server.idle-timeout = 1337s""") { sys ⇒ + import scala.concurrent.duration._ + + val client = ClientConnectionSettings(sys) + client.idleTimeout should ===(60.seconds) + + val pool = ConnectionPoolSettings(sys) + pool.connectionSettings.idleTimeout should ===(60.seconds) + + val server = ServerSettings(sys) + server.idleTimeout should ===(1337.seconds) + } + } + + "change parser settings for all by setting `akka.http.parsing`" in { + configuredSystem("""akka.http.parsing.illegal-header-warnings = off""") { sys ⇒ + val client = ClientConnectionSettings(sys) + client.parserSettings.illegalHeaderWarnings should ===(Off) + + val pool = ConnectionPoolSettings(sys) + pool.connectionSettings.parserSettings.illegalHeaderWarnings should ===(Off) + + val server = ServerSettings(sys) + server.parserSettings.illegalHeaderWarnings should ===(Off) + } + } + + "change parser settings for all by setting `akka.http.parsing`, unless client/server override it" in { + configuredSystem(""" + akka.http { + parsing.illegal-header-warnings = off + server.parsing.illegal-header-warnings = on + client.parsing.illegal-header-warnings = on // also affects host-connection-pool.client + }""") { sys ⇒ + val client = ClientConnectionSettings(sys) + client.parserSettings.illegalHeaderWarnings should ===(On) + + val pool = ConnectionPoolSettings(sys) + pool.connectionSettings.parserSettings.illegalHeaderWarnings should ===(On) + + val server = ServerSettings(sys) + server.parserSettings.illegalHeaderWarnings should ===(On) + } + } + + "change parser settings for all by setting `akka.http.parsing`, unless all override it" in { + configuredSystem(""" + akka.http { + parsing.illegal-header-warnings = off + server.parsing.illegal-header-warnings = on + client.parsing.illegal-header-warnings = on + host-connection-pool.client.parsing.illegal-header-warnings = off + }""") { sys ⇒ + val client = ClientConnectionSettings(sys) + client.parserSettings.illegalHeaderWarnings should ===(On) + + val pool = ConnectionPoolSettings(sys) + pool.connectionSettings.parserSettings.illegalHeaderWarnings should ===(Off) + + val server = ServerSettings(sys) + server.parserSettings.illegalHeaderWarnings should ===(On) + } + } + } + + def configuredSystem(overrides: String)(block: ActorSystem ⇒ Unit) = { + val config = ConfigFactory.parseString(overrides).withFallback(ConfigFactory.load()) + // we go via ActorSystem in order to hit the settings caching infrastructure + val sys = ActorSystem("config-testing", config) + try block(sys) finally sys.shutdown() + } + +} \ No newline at end of file diff --git a/akka-http/src/main/scala/akka/http/scaladsl/server/RoutingSettings.scala b/akka-http/src/main/scala/akka/http/scaladsl/server/RoutingSettings.scala index 7fbd156524..fe88fc878f 100644 --- a/akka-http/src/main/scala/akka/http/scaladsl/server/RoutingSettings.scala +++ b/akka-http/src/main/scala/akka/http/scaladsl/server/RoutingSettings.scala @@ -18,7 +18,7 @@ case class RoutingSettings( fileIODispatcher: String) object RoutingSettings extends SettingsCompanion[RoutingSettings]("akka.http.routing") { - def fromSubConfig(c: Config) = apply( + def fromSubConfig(root: Config, c: Config) = apply( c getBoolean "verbose-error-messages", c getBoolean "file-get-conditional", c getBoolean "render-vanity-footer",