=htc #18533 make configuration of parsing less confusing

This commit is contained in:
Konrad Malawski 2015-09-24 15:29:29 +02:00
parent ae83053a64
commit b1f9f77a17
6 changed files with 358 additions and 77 deletions

View file

@ -254,3 +254,14 @@ 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]``. Please note that while each of
these sections expose the same parsing options, they will only be used for their respective APIs. For example, changing
a setting inside ``akka.http.client.parsing`` **does not** change the same value in ``akka.http.host-connection-pool.client.parsing``,
as they are different APIs.
You can check which settings to tweak for which method exposed on the Http object by inspecting their ScalaDoc.
In general though it's as simple as "pool" backed services use the ``host-connection-pool`` section, other clients
which expose ``Flow`` use the ``client`` section, and the server side uses the ``server`` configuration section.

View file

@ -250,3 +250,14 @@ 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]``. Please note that while each of
these sections expose the same parsing options, they will only be used for their respective APIs. For example, changing
a setting inside ``akka.http.client.parsing`` **does not** change the same value in ``akka.http.host-connection-pool.client.parsing``,
as they are different APIs.
You can check which settings to tweak for which method exposed on the Http object by inspecting their ScalaDoc.
In general though it's as simple as "pool" backed services use the ``host-connection-pool`` section, other clients
which expose ``Flow`` use the ``client`` section, and the server side uses the ``server`` configuration section.

View file

@ -88,106 +88,9 @@ akka.http {
}
# Modify to tweak parsing settings on the server-side only.
parsing = ${akka.http.parsing}
}
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
}
# Modify to tweak parsing settings on the client-side only.
parsing = ${akka.http.parsing}
}
host-connection-pool {
# The maximum number of parallel connections that a connection pool to a
# single host endpoint is allowed to establish. Must be greater than zero.
max-connections = 4
# The maximum number of times failed requests are attempted again,
# (if the request can be safely retried) before giving up and returning an error.
# Set to zero to completely disable request retries.
max-retries = 5
# The maximum number of open requests accepted into the pool across all
# materializations of any of its client flows.
# Protects against (accidentally) overloading a single pool with too many client flow materializations.
# Note that with N concurrent materializations the max number of open request in the pool
# will never exceed N * max-connections * pipelining-limit.
# Must be a power of 2 and > 0!
max-open-requests = 32
# The maximum number of requests that are dispatched to the target host in
# batch-mode across a single connection (HTTP pipelining).
# A setting of 1 disables HTTP pipelining, since only one request per
# connection can be "in flight" at any time.
# Set to higher values to enable HTTP pipelining.
# This value must be > 0.
# (Note that, independently of this setting, pipelining will never be done
# on a connection that still has a non-idempotent request in flight.
# See http://tools.ietf.org/html/rfc7230#section-6.3.2 for more info.)
pipelining-limit = 1
# The time after which an idle connection pool (without pending requests)
# will automatically terminate itself. Set to `infinite` to completely disable idle timeouts.
idle-timeout = 30 s
# Modify to tweak client settings for host connection pools only.
client = ${akka.http.client}
}
# 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.
#
# IMPORTANT:
# Please note that this section is replicated in `client` and `http-connection-pool`
parsing {
# The limits for the various parts of the HTTP message parser.
max-uri-length = 2k
@ -257,3 +160,290 @@ akka.http {
}
}
}
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
}
# Modify to tweak parsing settings on the client-side only.
#
# IMPORTANT:
# Please note that this section is replicated in `server` and `http-connection-pool`.
parsing {
# The limits for the various parts of the HTTP message parser.
max-uri-length = 2k
max-method-length = 16
max-response-reason-length = 64
max-header-name-length = 64
max-header-value-length = 8k
max-header-count = 64
max-chunk-ext-length = 256
max-chunk-size = 1m
# Maximum content length which should not be exceeded by incoming HttpRequests.
# For file uploads which use the entityBytes Source of an incoming HttpRequest it is safe to
# set this to a very high value (or to `infinite` if feeling very adventurous) as the streaming
# upload will be back-pressured properly by Akka Streams.
# Please note however that this setting is a global property, and is applied to all incoming requests,
# not only file uploads consumed in a streaming fashion, so pick this limit wisely.
max-content-length = 8m
# Sets the strictness mode for parsing request target URIs.
# The following values are defined:
#
# `strict`: RFC3986-compliant URIs are required,
# a 400 response is triggered on violations
#
# `relaxed`: all visible 7-Bit ASCII chars are allowed
#
# `relaxed-with-raw-query`: like `relaxed` but additionally
# the URI query is not parsed, but delivered as one raw string
# as the `key` value of a single Query structure element.
#
uri-parsing-mode = strict
# Enables/disables the logging of warning messages in case an incoming
# message (request or response) contains an HTTP header which cannot be
# parsed into its high-level model class due to incompatible syntax.
# Note that, independently of this settings, akka-http will accept messages
# with such headers as long as the message as a whole would still be legal
# under the HTTP specification even without this header.
# If a header cannot be parsed into a high-level model instance it will be
# provided as a `RawHeader`.
# If logging is enabled it is performed with the configured
# `error-logging-verbosity`.
illegal-header-warnings = on
# Configures the verbosity with which message (request or response) parsing
# errors are written to the application log.
#
# Supported settings:
# `off` : no log messages are produced
# `simple`: a condensed single-line message is logged
# `full` : the full error details (potentially spanning several lines) are logged
error-logging-verbosity = full
# limits for the number of different values per header type that the
# header cache will hold
header-cache {
default = 12
Content-MD5 = 0
Date = 0
If-Match = 0
If-Modified-Since = 0
If-None-Match = 0
If-Range = 0
If-Unmodified-Since = 0
User-Agent = 32
}
}
}
host-connection-pool {
# The maximum number of parallel connections that a connection pool to a
# single host endpoint is allowed to establish. Must be greater than zero.
max-connections = 4
# The maximum number of times failed requests are attempted again,
# (if the request can be safely retried) before giving up and returning an error.
# Set to zero to completely disable request retries.
max-retries = 5
# The maximum number of open requests accepted into the pool across all
# materializations of any of its client flows.
# Protects against (accidentally) overloading a single pool with too many client flow materializations.
# Note that with N concurrent materializations the max number of open request in the pool
# will never exceed N * max-connections * pipelining-limit.
# Must be a power of 2 and > 0!
max-open-requests = 32
# The maximum number of requests that are dispatched to the target host in
# batch-mode across a single connection (HTTP pipelining).
# A setting of 1 disables HTTP pipelining, since only one request per
# connection can be "in flight" at any time.
# Set to higher values to enable HTTP pipelining.
# This value must be > 0.
# (Note that, independently of this setting, pipelining will never be done
# on a connection that still has a non-idempotent request in flight.
# See http://tools.ietf.org/html/rfc7230#section-6.3.2 for more info.)
pipelining-limit = 1
# The time after which an idle connection pool (without pending requests)
# will automatically terminate itself. Set to `infinite` to completely disable idle timeouts.
idle-timeout = 30 s
# Modify to tweak client settings for host connection pools only.
#
# 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 {
# The limits for the various parts of the HTTP message parser.
max-uri-length = 2k
max-method-length = 16
max-response-reason-length = 64
max-header-name-length = 64
max-header-value-length = 8k
max-header-count = 64
max-chunk-ext-length = 256
max-chunk-size = 1m
# Maximum content length which should not be exceeded by incoming HttpRequests.
# For file uploads which use the entityBytes Source of an incoming HttpRequest it is safe to
# set this to a very high value (or to `infinite` if feeling very adventurous) as the streaming
# upload will be back-pressured properly by Akka Streams.
# Please note however that this setting is a global property, and is applied to all incoming requests,
# not only file uploads consumed in a streaming fashion, so pick this limit wisely.
max-content-length = 8m
# Sets the strictness mode for parsing request target URIs.
# The following values are defined:
#
# `strict`: RFC3986-compliant URIs are required,
# a 400 response is triggered on violations
#
# `relaxed`: all visible 7-Bit ASCII chars are allowed
#
# `relaxed-with-raw-query`: like `relaxed` but additionally
# the URI query is not parsed, but delivered as one raw string
# as the `key` value of a single Query structure element.
#
uri-parsing-mode = strict
# Enables/disables the logging of warning messages in case an incoming
# message (request or response) contains an HTTP header which cannot be
# parsed into its high-level model class due to incompatible syntax.
# Note that, independently of this settings, akka-http will accept messages
# with such headers as long as the message as a whole would still be legal
# under the HTTP specification even without this header.
# If a header cannot be parsed into a high-level model instance it will be
# provided as a `RawHeader`.
# If logging is enabled it is performed with the configured
# `error-logging-verbosity`.
illegal-header-warnings = on
# Configures the verbosity with which message (request or response) parsing
# errors are written to the application log.
#
# Supported settings:
# `off` : no log messages are produced
# `simple`: a condensed single-line message is logged
# `full` : the full error details (potentially spanning several lines) are logged
error-logging-verbosity = full
# limits for the number of different values per header type that the
# header cache will hold
header-cache {
default = 12
Content-MD5 = 0
Date = 0
If-Match = 0
If-Modified-Since = 0
If-None-Match = 0
If-Range = 0
If-Unmodified-Since = 0
User-Agent = 32
}
}
}
}
}

View file

@ -42,7 +42,7 @@ 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") {

View file

@ -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,

View file

@ -0,0 +1,27 @@
/*
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.http.impl.engine.client
import akka.stream.testkit.AkkaSpec
class ClientConfigurationSpec extends AkkaSpec {
"Reference configurations" should {
for {
(first, second) "akka.http.client" -> "akka.http.host-connection-pool.client" ::
"akka.http.client.parsing" -> "akka.http.host-connection-pool.client.parsing" ::
"akka.http.server.parsing" -> "akka.http.client.parsing" ::
Nil
} s"be consistent for: `$first` and `$second`" in {
configShouldBeEqual("akka.http.client.parsing", "akka.http.host-connection-pool.client.parsing")
}
}
private def configShouldBeEqual(first: String, second: String): Unit = {
val config = system.settings.config
withClue(s"Config [$first] did not equal [$second]!") {
config.getConfig(first) should ===(config.getConfig(second))
}
}
}