+htc #20771 provide different options to deal with the illegal response header value (#20976)

This commit is contained in:
Hawstein 2016-07-24 23:56:39 +08:00 committed by Konrad Malawski
parent 1d0837856a
commit cf46ab887f
16 changed files with 185 additions and 56 deletions

View file

@ -352,6 +352,15 @@ akka.http {
# `full` : the full error details (potentially spanning several lines) are logged
error-logging-verbosity = full
# Configures the processing mode when encountering illegal characters in
# header value of response.
#
# Supported mode:
# `error` : default mode, throw an ParsingException and terminate the processing
# `warn` : ignore the illegal characters in response header value and log a warning message
# `ignore` : just ignore the illegal characters in response header value
illegal-response-header-value-processing-mode = error
# limits for the number of different values per header type that the
# header cache will hold
header-cache {

View file

@ -83,7 +83,7 @@ private[http] object OutgoingConnectionBlueprint {
val responseParsingMerge = b.add {
// the initial header parser we initially use for every connection,
// will not be mutated, all "shared copy" parsers copy on first-write into the header cache
val rootParser = new HttpResponseParser(parserSettings, HttpHeaderParser(parserSettings) { info
val rootParser = new HttpResponseParser(parserSettings, HttpHeaderParser(parserSettings, log) { info
if (parserSettings.illegalHeaderWarnings)
logParsingError(info withSummaryPrepended "Illegal response header", log, parserSettings.errorLoggingVerbosity)
})

View file

@ -58,7 +58,7 @@ private[http] final class BodyPartParser(
private[this] val boyerMoore = new BoyerMoore(needle)
// TODO: prevent re-priming header parser from scratch
private[this] val headerParser = HttpHeaderParser(settings) { errorInfo
private[this] val headerParser = HttpHeaderParser(settings, log) { errorInfo
if (illegalHeaderWarnings) log.warning(errorInfo.withSummaryPrepended("Illegal multipart header").formatPretty)
}

View file

@ -7,6 +7,10 @@ package akka.http.impl.engine.parsing
import java.nio.{ CharBuffer, ByteBuffer }
import java.util.Arrays.copyOf
import java.lang.{ StringBuilder JStringBuilder }
import akka.event.LoggingAdapter
import akka.http.scaladsl.settings.ParserSettings.IllegalResponseHeaderValueProcessingMode
import akka.http.scaladsl.settings.ParserSettings
import scala.annotation.tailrec
import akka.parboiled2.CharUtils
import akka.util.ByteString
@ -60,6 +64,7 @@ import akka.http.impl.model.parser.CharacterClasses._
*/
private[engine] final class HttpHeaderParser private (
val settings: HttpHeaderParser.Settings,
val log: LoggingAdapter,
onIllegalHeader: ErrorInfo Unit,
private[this] var nodes: Array[Char] = new Array(512), // initial size, can grow as needed
private[this] var nodeCount: Int = 0,
@ -85,7 +90,7 @@ private[engine] final class HttpHeaderParser private (
* Returns a copy of this parser that shares the trie data with this instance.
*/
def createShallowCopy(): HttpHeaderParser =
new HttpHeaderParser(settings, onIllegalHeader, nodes, nodeCount, branchData, branchDataCount, values, valueCount)
new HttpHeaderParser(settings, log, onIllegalHeader, nodes, nodeCount, branchData, branchDataCount, values, valueCount)
/**
* Parses a header line and returns the line start index of the subsequent line.
@ -145,12 +150,14 @@ private[engine] final class HttpHeaderParser private (
val colonIx = scanHeaderNameAndReturnIndexOfColon(input, lineStart, lineStart + 1 + maxHeaderNameLength)(cursor)
val headerName = asciiString(input, lineStart, colonIx)
try {
val valueParser = new RawHeaderValueParser(headerName, maxHeaderValueLength, headerValueCacheLimit(headerName))
val valueParser = new RawHeaderValueParser(headerName, maxHeaderValueLength,
headerValueCacheLimit(headerName), log, illegalResponseHeaderValueProcessingMode)
insert(input, valueParser)(cursor, colonIx + 1, nodeIx, colonIx)
parseHeaderLine(input, lineStart)(cursor, nodeIx)
} catch {
case OutOfTrieSpaceException // if we cannot insert we drop back to simply creating new header instances
val (headerValue, endIx) = scanHeaderValue(this, input, colonIx + 1, colonIx + maxHeaderValueLength + 3)()
val (headerValue, endIx) = scanHeaderValue(this, input, colonIx + 1, colonIx + maxHeaderValueLength + 3,
log, settings.illegalResponseHeaderValueProcessingMode)()
resultHeader = RawHeader(headerName, headerValue.trim)
endIx
}
@ -413,6 +420,7 @@ private[http] object HttpHeaderParser {
def maxHeaderValueLength: Int
def headerValueCacheLimit(headerName: String): Int
def customMediaTypes: MediaTypes.FindCustom
def illegalResponseHeaderValueProcessingMode: IllegalResponseHeaderValueProcessingMode
}
private def predefinedHeaders = Seq(
@ -426,16 +434,16 @@ private[http] object HttpHeaderParser {
"Cache-Control: no-cache",
"Expect: 100-continue")
def apply(settings: HttpHeaderParser.Settings)(onIllegalHeader: ErrorInfo Unit = info throw IllegalHeaderException(info)) =
prime(unprimed(settings, onIllegalHeader))
def apply(settings: HttpHeaderParser.Settings, log: LoggingAdapter)(onIllegalHeader: ErrorInfo Unit = info throw IllegalHeaderException(info)) =
prime(unprimed(settings, log, onIllegalHeader))
def unprimed(settings: HttpHeaderParser.Settings, warnOnIllegalHeader: ErrorInfo Unit) =
new HttpHeaderParser(settings, warnOnIllegalHeader)
def unprimed(settings: HttpHeaderParser.Settings, log: LoggingAdapter, warnOnIllegalHeader: ErrorInfo Unit) =
new HttpHeaderParser(settings, log, warnOnIllegalHeader)
def prime(parser: HttpHeaderParser): HttpHeaderParser = {
val valueParsers: Seq[HeaderValueParser] =
HeaderParser.ruleNames.map { name
new ModeledHeaderValueParser(name, parser.settings.maxHeaderValueLength, parser.settings.headerValueCacheLimit(name), parser.settings)
new ModeledHeaderValueParser(name, parser.settings.maxHeaderValueLength, parser.settings.headerValueCacheLimit(name), parser.log, parser.settings)
}(collection.breakOut)
def insertInGoodOrder(items: Seq[Any])(startIx: Int = 0, endIx: Int = items.size): Unit =
if (endIx - startIx > 0) {
@ -470,11 +478,11 @@ private[http] object HttpHeaderParser {
def cachingEnabled = maxValueCount > 0
}
private[parsing] class ModeledHeaderValueParser(headerName: String, maxHeaderValueLength: Int, maxValueCount: Int, settings: HeaderParser.Settings)
private[parsing] class ModeledHeaderValueParser(headerName: String, maxHeaderValueLength: Int, maxValueCount: Int, log: LoggingAdapter, settings: HeaderParser.Settings)
extends HeaderValueParser(headerName, maxValueCount) {
def apply(hhp: HttpHeaderParser, input: ByteString, valueStart: Int, onIllegalHeader: ErrorInfo Unit): (HttpHeader, Int) = {
// TODO: optimize by running the header value parser directly on the input ByteString (rather than an extracted String); seems done?
val (headerValue, endIx) = scanHeaderValue(hhp, input, valueStart, valueStart + maxHeaderValueLength + 2)()
val (headerValue, endIx) = scanHeaderValue(hhp, input, valueStart, valueStart + maxHeaderValueLength + 2, log, settings.illegalResponseHeaderValueProcessingMode)()
val trimmedHeaderValue = headerValue.trim
val header = HeaderParser.parseFull(headerName, trimmedHeaderValue, settings) match {
case Right(h) h
@ -486,10 +494,10 @@ private[http] object HttpHeaderParser {
}
}
private[parsing] class RawHeaderValueParser(headerName: String, maxHeaderValueLength: Int, maxValueCount: Int)
extends HeaderValueParser(headerName, maxValueCount) {
private[parsing] class RawHeaderValueParser(headerName: String, maxHeaderValueLength: Int, maxValueCount: Int,
log: LoggingAdapter, mode: IllegalResponseHeaderValueProcessingMode) extends HeaderValueParser(headerName, maxValueCount) {
def apply(hhp: HttpHeaderParser, input: ByteString, valueStart: Int, onIllegalHeader: ErrorInfo Unit): (HttpHeader, Int) = {
val (headerValue, endIx) = scanHeaderValue(hhp, input, valueStart, valueStart + maxHeaderValueLength + 2)()
val (headerValue, endIx) = scanHeaderValue(hhp, input, valueStart, valueStart + maxHeaderValueLength + 2, log, mode)()
RawHeader(headerName, headerValue.trim) endIx
}
}
@ -503,15 +511,16 @@ private[http] object HttpHeaderParser {
}
else fail(s"HTTP header name exceeds the configured limit of ${limit - start - 1} characters")
@tailrec private def scanHeaderValue(hhp: HttpHeaderParser, input: ByteString, start: Int,
limit: Int)(sb: JStringBuilder = null, ix: Int = start): (String, Int) = {
@tailrec private def scanHeaderValue(hhp: HttpHeaderParser, input: ByteString, start: Int, limit: Int, log: LoggingAdapter,
mode: IllegalResponseHeaderValueProcessingMode)(sb: JStringBuilder = null, ix: Int = start): (String, Int) = {
def appended(c: Char) = (if (sb != null) sb else new JStringBuilder(asciiString(input, start, ix))).append(c)
def appended2(c: Int) = if ((c >> 16) != 0) appended(c.toChar).append((c >> 16).toChar) else appended(c.toChar)
if (ix < limit)
byteChar(input, ix) match {
case '\t' scanHeaderValue(hhp, input, start, limit)(appended(' '), ix + 1)
case '\t' scanHeaderValue(hhp, input, start, limit, log, mode)(appended(' '), ix + 1)
case '\r' if byteChar(input, ix + 1) == '\n'
if (WSP(byteChar(input, ix + 2))) scanHeaderValue(hhp, input, start, limit)(appended(' '), ix + 3)
if (WSP(byteChar(input, ix + 2))) scanHeaderValue(hhp, input, start, limit, log, mode)(appended(' '), ix + 3)
else (if (sb != null) sb.toString else asciiString(input, start, ix), ix + 2)
case c
var nix = ix + 1
@ -544,8 +553,21 @@ private[http] object HttpHeaderParser {
case -1 if (sb != null) sb.append(c).append(byteChar(input, ix + 1)).append(byteChar(input, ix + 2)).append(byteChar(input, ix + 3)) else null
case cc appended2(cc)
}
} else fail(s"Illegal character '${escape(c)}' in header value")
scanHeaderValue(hhp, input, start, limit)(nsb, nix)
} else {
mode match {
case ParserSettings.IllegalResponseHeaderValueProcessingMode.Error
fail(s"Illegal character '${escape(c)}' in header value")
case ParserSettings.IllegalResponseHeaderValueProcessingMode.Warn
// ignore the illegal character and log a warning message
log.warning(s"Illegal character '${escape(c)}' in header value")
sb
case ParserSettings.IllegalResponseHeaderValueProcessingMode.Ignore
// just ignore the illegal character
sb
}
}
scanHeaderValue(hhp, input, start, limit, log, mode)(nsb, nix)
}
else fail(s"HTTP header value exceeds the configured limit of ${limit - start - 2} characters")
}

View file

@ -211,7 +211,7 @@ private[http] object HttpServerBluePrint {
// the initial header parser we initially use for every connection,
// will not be mutated, all "shared copy" parsers copy on first-write into the header cache
val rootParser = new HttpRequestParser(parserSettings, rawRequestUriHeader,
HttpHeaderParser(parserSettings) { info
HttpHeaderParser(parserSettings, log) { info
if (parserSettings.illegalHeaderWarnings)
logParsingError(info withSummaryPrepended "Illegal request header", log, parserSettings.errorLoggingVerbosity)
})

View file

@ -62,7 +62,7 @@ object WebSocketClientBlueprint {
new GraphStageLogic(shape) with InHandler with OutHandler {
// a special version of the parser which only parses one message and then reports the remaining data
// if some is available
val parser = new HttpResponseParser(settings.parserSettings, HttpHeaderParser(settings.parserSettings)()) {
val parser = new HttpResponseParser(settings.parserSettings, HttpHeaderParser(settings.parserSettings, log)()) {
var first = true
override def handleInformationalResponses = false
override protected def parseMessage(input: ByteString, offset: Int): StateResult = {

View file

@ -6,6 +6,7 @@ package akka.http.impl.model.parser
import akka.http.scaladsl.settings.ParserSettings
import akka.http.scaladsl.settings.ParserSettings.CookieParsingMode
import akka.http.scaladsl.settings.ParserSettings.IllegalResponseHeaderValueProcessingMode
import akka.http.scaladsl.model.headers.HttpCookiePair
import akka.stream.impl.ConstantFun
import scala.util.control.NonFatal
@ -169,20 +170,26 @@ private[http] object HeaderParser {
def uriParsingMode: Uri.ParsingMode
def cookieParsingMode: ParserSettings.CookieParsingMode
def customMediaTypes: MediaTypes.FindCustom
def illegalResponseHeaderValueProcessingMode: IllegalResponseHeaderValueProcessingMode
}
def Settings(
uriParsingMode: Uri.ParsingMode = Uri.ParsingMode.Relaxed,
cookieParsingMode: ParserSettings.CookieParsingMode = ParserSettings.CookieParsingMode.RFC6265,
customMediaTypes: MediaTypes.FindCustom = ConstantFun.scalaAnyTwoToNone): Settings = {
uriParsingMode: Uri.ParsingMode = Uri.ParsingMode.Relaxed,
cookieParsingMode: ParserSettings.CookieParsingMode = ParserSettings.CookieParsingMode.RFC6265,
customMediaTypes: MediaTypes.FindCustom = ConstantFun.scalaAnyTwoToNone,
mode: IllegalResponseHeaderValueProcessingMode = ParserSettings.IllegalResponseHeaderValueProcessingMode.Error): Settings = {
val _uriParsingMode = uriParsingMode
val _cookieParsingMode = cookieParsingMode
val _customMediaTypes = customMediaTypes
val _illegalResponseHeaderValueProcessingMode = mode
new Settings {
def uriParsingMode: Uri.ParsingMode = _uriParsingMode
def cookieParsingMode: CookieParsingMode = _cookieParsingMode
def customMediaTypes: MediaTypes.FindCustom = _customMediaTypes
def illegalResponseHeaderValueProcessingMode: IllegalResponseHeaderValueProcessingMode =
_illegalResponseHeaderValueProcessingMode
}
}
val DefaultSettings: Settings = Settings()
}
}

View file

@ -5,7 +5,7 @@
package akka.http.impl.settings
import akka.http.scaladsl.settings.ParserSettings
import akka.http.scaladsl.settings.ParserSettings.{ ErrorLoggingVerbosity, CookieParsingMode }
import akka.http.scaladsl.settings.ParserSettings.{ IllegalResponseHeaderValueProcessingMode, ErrorLoggingVerbosity, CookieParsingMode }
import akka.stream.impl.ConstantFun
import com.typesafe.config.Config
import scala.collection.JavaConverters._
@ -14,24 +14,25 @@ import akka.http.impl.util._
/** INTERNAL API */
private[akka] final case class ParserSettingsImpl(
maxUriLength: Int,
maxMethodLength: Int,
maxResponseReasonLength: Int,
maxHeaderNameLength: Int,
maxHeaderValueLength: Int,
maxHeaderCount: Int,
maxContentLength: Long,
maxChunkExtLength: Int,
maxChunkSize: Int,
uriParsingMode: Uri.ParsingMode,
cookieParsingMode: CookieParsingMode,
illegalHeaderWarnings: Boolean,
errorLoggingVerbosity: ParserSettings.ErrorLoggingVerbosity,
headerValueCacheLimits: Map[String, Int],
includeTlsSessionInfoHeader: Boolean,
customMethods: String Option[HttpMethod],
customStatusCodes: Int Option[StatusCode],
customMediaTypes: MediaTypes.FindCustom)
maxUriLength: Int,
maxMethodLength: Int,
maxResponseReasonLength: Int,
maxHeaderNameLength: Int,
maxHeaderValueLength: Int,
maxHeaderCount: Int,
maxContentLength: Long,
maxChunkExtLength: Int,
maxChunkSize: Int,
uriParsingMode: Uri.ParsingMode,
cookieParsingMode: CookieParsingMode,
illegalHeaderWarnings: Boolean,
errorLoggingVerbosity: ErrorLoggingVerbosity,
illegalResponseHeaderValueProcessingMode: IllegalResponseHeaderValueProcessingMode,
headerValueCacheLimits: Map[String, Int],
includeTlsSessionInfoHeader: Boolean,
customMethods: String Option[HttpMethod],
customStatusCodes: Int Option[StatusCode],
customMediaTypes: MediaTypes.FindCustom)
extends akka.http.scaladsl.settings.ParserSettings {
require(maxUriLength > 0, "max-uri-length must be > 0")
@ -76,6 +77,7 @@ object ParserSettingsImpl extends SettingsCompanion[ParserSettingsImpl]("akka.ht
CookieParsingMode(c getString "cookie-parsing-mode"),
c getBoolean "illegal-header-warnings",
ErrorLoggingVerbosity(c getString "error-logging-verbosity"),
IllegalResponseHeaderValueProcessingMode(c getString "illegal-response-header-value-processing-mode"),
cacheConfig.entrySet.asScala.map(kvp kvp.getKey cacheConfig.getInt(kvp.getKey))(collection.breakOut),
c getBoolean "tls-session-info-header",
noCustomMethods,

View file

@ -33,6 +33,7 @@ abstract class ParserSettings private[akka] () extends BodyPartParser.Settings {
def getCookieParsingMode: ParserSettings.CookieParsingMode
def getIllegalHeaderWarnings: Boolean
def getErrorLoggingVerbosity: ParserSettings.ErrorLoggingVerbosity
def getIllegalResponseHeaderValueProcessingMode: ParserSettings.IllegalResponseHeaderValueProcessingMode
def getHeaderValueCacheLimits: ju.Map[String, Int]
def getIncludeTlsSessionInfoHeader: Boolean
def headerValueCacheLimits: Map[String, Int]
@ -81,6 +82,7 @@ abstract class ParserSettings private[akka] () extends BodyPartParser.Settings {
object ParserSettings extends SettingsCompanion[ParserSettings] {
trait CookieParsingMode
trait ErrorLoggingVerbosity
trait IllegalResponseHeaderValueProcessingMode
override def create(config: Config): ParserSettings = ParserSettingsImpl(config)
override def create(configOverrides: String): ParserSettings = ParserSettingsImpl(configOverrides)

View file

@ -34,6 +34,7 @@ abstract class ParserSettings private[akka] () extends akka.http.javadsl.setting
def cookieParsingMode: ParserSettings.CookieParsingMode
def illegalHeaderWarnings: Boolean
def errorLoggingVerbosity: ParserSettings.ErrorLoggingVerbosity
def illegalResponseHeaderValueProcessingMode: ParserSettings.IllegalResponseHeaderValueProcessingMode
def headerValueCacheLimits: Map[String, Int]
def includeTlsSessionInfoHeader: Boolean
def customMethods: String Option[HttpMethod]
@ -56,6 +57,7 @@ abstract class ParserSettings private[akka] () extends akka.http.javadsl.setting
override def getMaxUriLength = maxUriLength
override def getMaxMethodLength = maxMethodLength
override def getErrorLoggingVerbosity: js.ParserSettings.ErrorLoggingVerbosity = errorLoggingVerbosity
override def getIllegalResponseHeaderValueProcessingMode = illegalResponseHeaderValueProcessingMode
override def getCustomMethods = new Function[String, Optional[akka.http.javadsl.model.HttpMethod]] {
override def apply(t: String) = OptionConverters.toJava(customMethods(t))
@ -100,10 +102,12 @@ abstract class ParserSettings private[akka] () extends akka.http.javadsl.setting
val map = types.map(c (c.mainType, c.subType) c).toMap
self.copy(customMediaTypes = (main, sub) map.get((main, sub)))
}
def withIllegalResponseHeaderValueProcessingMode(newValue: ParserSettings.IllegalResponseHeaderValueProcessingMode): ParserSettings =
self.copy(illegalResponseHeaderValueProcessingMode = newValue)
}
object ParserSettings extends SettingsCompanion[ParserSettings] {
trait CookieParsingMode extends akka.http.javadsl.settings.ParserSettings.CookieParsingMode
sealed trait CookieParsingMode extends akka.http.javadsl.settings.ParserSettings.CookieParsingMode
object CookieParsingMode {
case object RFC6265 extends CookieParsingMode
case object Raw extends CookieParsingMode
@ -114,7 +118,7 @@ object ParserSettings extends SettingsCompanion[ParserSettings] {
}
}
trait ErrorLoggingVerbosity extends akka.http.javadsl.settings.ParserSettings.ErrorLoggingVerbosity
sealed trait ErrorLoggingVerbosity extends akka.http.javadsl.settings.ParserSettings.ErrorLoggingVerbosity
object ErrorLoggingVerbosity {
case object Off extends ErrorLoggingVerbosity
case object Simple extends ErrorLoggingVerbosity
@ -129,6 +133,21 @@ object ParserSettings extends SettingsCompanion[ParserSettings] {
}
}
sealed trait IllegalResponseHeaderValueProcessingMode extends akka.http.javadsl.settings.ParserSettings.IllegalResponseHeaderValueProcessingMode
object IllegalResponseHeaderValueProcessingMode {
case object Error extends IllegalResponseHeaderValueProcessingMode
case object Warn extends IllegalResponseHeaderValueProcessingMode
case object Ignore extends IllegalResponseHeaderValueProcessingMode
def apply(string: String): IllegalResponseHeaderValueProcessingMode =
string.toRootLowerCase match {
case "error" Error
case "warn" Warn
case "ignore" Ignore
case x throw new IllegalArgumentException(s"[$x] is not a legal `illegal-response-header-value-processing-mode` setting")
}
}
override def apply(config: Config): ParserSettings = ParserSettingsImpl(config)
override def apply(configOverrides: String): ParserSettings = ParserSettingsImpl(configOverrides)
}

View file

@ -4,6 +4,8 @@
package akka.http.impl.engine.client
import com.typesafe.config.ConfigFactory
import scala.concurrent.duration._
import scala.reflect.ClassTag
import org.scalatest.Inside
@ -326,6 +328,65 @@ class LowLevelOutgoingConnectionSpec extends AkkaSpec("akka.loggers = []\n akka.
}
}
"process the illegal response header value properly" which {
val illegalChar = '\u0001'
val escapeChar = "\\u%04x" format illegalChar.toInt
"catch illegal response header value by default" in new TestSetup {
sendStandardRequest()
sendWireData(
s"""HTTP/1.1 200 OK
|Some-Header: value1$illegalChar
|Other-Header: value2
|
|""")
responsesSub.request(1)
val error @ IllegalResponseException(info) = responses.expectError()
info.summary shouldEqual s"""Illegal character '$escapeChar' in header value"""
netOut.expectError(error)
requestsSub.expectCancellation()
netInSub.expectCancellation()
}
val ignoreConfig =
"""
akka.http.parsing.illegal-response-header-value-processing-mode = ignore
"""
"ignore illegal response header value if setting the config to ignore" in new TestSetup(config = ignoreConfig) {
sendStandardRequest()
sendWireData(
s"""HTTP/1.1 200 OK
|Some-Header: value1$illegalChar
|Other-Header: value2
|
|""")
val HttpResponse(_, headers, _, _) = expectResponse()
val headerStr = headers.map(h s"${h.name}: ${h.value}").mkString(",")
headerStr shouldEqual "Some-Header: value1,Other-Header: value2"
}
val warnConfig =
"""
akka.http.parsing.illegal-response-header-value-processing-mode = warn
"""
"ignore illegal response header value and log a warning message if setting the config to warn" in new TestSetup(config = warnConfig) {
sendStandardRequest()
sendWireData(
s"""HTTP/1.1 200 OK
|Some-Header: value1$illegalChar
|Other-Header: value2
|
|""")
val HttpResponse(_, headers, _, _) = expectResponse()
val headerStr = headers.map(h s"${h.name}: ${h.value}").mkString(",")
headerStr shouldEqual "Some-Header: value1,Other-Header: value2"
}
}
"produce proper errors" which {
"catch the request entity stream being shorter than the Content-Length" in new TestSetup {
@ -808,13 +869,14 @@ class LowLevelOutgoingConnectionSpec extends AkkaSpec("akka.loggers = []\n akka.
}
}
class TestSetup(maxResponseContentLength: Int = -1) {
class TestSetup(maxResponseContentLength: Int = -1, config: String = "") {
val requests = TestPublisher.manualProbe[HttpRequest]()
val responses = TestSubscriber.manualProbe[HttpResponse]()
def settings = {
val s = ClientConnectionSettings(system)
.withUserAgentHeader(Some(`User-Agent`(List(ProductVersion("akka-http", "test")))))
val s = ClientConnectionSettings(
ConfigFactory.parseString(config).withFallback(system.settings.config)
).withUserAgentHeader(Some(`User-Agent`(List(ProductVersion("akka-http", "test")))))
if (maxResponseContentLength < 0) s
else s.withParserSettings(s.parserSettings.withMaxContentLength(maxResponseContentLength))
}
@ -873,5 +935,6 @@ class LowLevelOutgoingConnectionSpec extends AkkaSpec("akka.loggers = []\n akka.
responsesSub.request(1)
responses.expectNext()
}
}
}

View file

@ -246,6 +246,7 @@ class HttpHeaderParserSpec extends WordSpec with Matchers with BeforeAndAfterAll
val parser = {
val p = HttpHeaderParser.unprimed(
settings = ParserSettings(system),
system.log,
warnOnIllegalHeader = info system.log.warning(info.formatPretty))
if (primed) HttpHeaderParser.prime(p) else p
}

View file

@ -15,7 +15,7 @@ object HttpHeaderParserTestBed extends App {
val system = ActorSystem("HttpHeaderParserTestBed", testConf)
val parser = HttpHeaderParser.prime {
HttpHeaderParser.unprimed(ParserSettings(system), warnOnIllegalHeader = info system.log.warning(info.formatPretty))
HttpHeaderParser.unprimed(ParserSettings(system), system.log, warnOnIllegalHeader = info system.log.warning(info.formatPretty))
}
println {

View file

@ -300,7 +300,7 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
"support `rawRequestUriHeader` setting" in new Test {
override protected def newParser: HttpRequestParser =
new HttpRequestParser(parserSettings, rawRequestUriHeader = true, headerParser = HttpHeaderParser(parserSettings)())
new HttpRequestParser(parserSettings, rawRequestUriHeader = true, headerParser = HttpHeaderParser(parserSettings, system.log)())
"""GET /f%6f%6fbar?q=b%61z HTTP/1.1
|Host: ping
@ -582,7 +582,7 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
.awaitResult(awaitAtMost)
protected def parserSettings: ParserSettings = ParserSettings(system)
protected def newParser = new HttpRequestParser(parserSettings, false, HttpHeaderParser(parserSettings)())
protected def newParser = new HttpRequestParser(parserSettings, false, HttpHeaderParser(parserSettings, system.log)())
private def compactEntity(entity: RequestEntity): Future[RequestEntity] =
entity match {

View file

@ -320,7 +320,7 @@ class ResponseParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
protected def parserSettings: ParserSettings = ParserSettings(system)
def newParserStage(requestMethod: HttpMethod = GET) = {
val parser = new HttpResponseParser(parserSettings, HttpHeaderParser(parserSettings)())
val parser = new HttpResponseParser(parserSettings, HttpHeaderParser(parserSettings, system.log)())
parser.setContextForNextResponse(HttpResponseParser.ResponseContext(requestMethod, None))
parser.stage
}

View file

@ -907,7 +907,11 @@ object MiMa extends AutoPlugin {
),
"2.4.9" -> Seq(
// #20994 adding new decode method, since we're on JDK7+ now
ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.util.ByteString.decodeString")
ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.util.ByteString.decodeString"),
// #20976 provide different options to deal with the illegal response header value
ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.http.javadsl.settings.ParserSettings.getIllegalResponseHeaderValueProcessingMode"),
ProblemFilters.exclude[ReversedMissingMethodProblem]("akka.http.scaladsl.settings.ParserSettings.illegalResponseHeaderValueProcessingMode")
)
)
}