diff --git a/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpMessageParser.scala b/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpMessageParser.scala index 781873cdfb..46c997d238 100644 --- a/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpMessageParser.scala +++ b/akka-http-core/src/main/scala/akka/http/impl/engine/parsing/HttpMessageParser.scala @@ -84,6 +84,8 @@ private[http] abstract class HttpMessageParser[Output >: MessageOutput <: Parser case NotEnoughDataException ⇒ // we are missing a try/catch{continue} wrapper somewhere throw new IllegalStateException("unexpected NotEnoughDataException", NotEnoughDataException) + case IllegalHeaderException(error) ⇒ + failMessageStart(StatusCodes.BadRequest, error) }) match { case Trampoline(x) ⇒ run(x) case x ⇒ x diff --git a/akka-http-core/src/test/scala/akka/http/impl/engine/parsing/RequestParserSpec.scala b/akka-http-core/src/test/scala/akka/http/impl/engine/parsing/RequestParserSpec.scala index a20c8994b2..17dc6ae6bc 100644 --- a/akka-http-core/src/test/scala/akka/http/impl/engine/parsing/RequestParserSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/impl/engine/parsing/RequestParserSpec.scala @@ -175,6 +175,28 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll { |""" should parseTo(HttpRequest(GET, Uri("http://x//foo").toHttpRequestTargetOriginForm, protocol = `HTTP/1.0`)) closeAfterResponseCompletion shouldEqual Seq(true) } + + "with additional fields in Strict-Transport-Security header" in new Test { + """GET /hsts HTTP/1.1 + |Host: x + |Strict-Transport-Security: max-age=1; preload; dummy + | + |""" should parseTo(HttpRequest( + GET, + "/hsts", + headers = List(Host("x"), `Strict-Transport-Security`(1, None)), + protocol = `HTTP/1.1`)) + + """GET /hsts HTTP/1.1 + |Host: x + |Strict-Transport-Security: max-age=1; dummy; preload + | + |""" should parseTo(HttpRequest( + GET, + "/hsts", + headers = List(Host("x"), `Strict-Transport-Security`(1, None)), + protocol = `HTTP/1.1`)) + } } "properly parse a chunked request" - { @@ -453,6 +475,36 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll { | |""" should parseToError(422: StatusCode, ErrorInfo("TRACE requests must not have an entity")) } + + "with additional fields in headers" in new Test { + """GET / HTTP/1.1 + |Host: x; dummy + | + |""" should parseToError( + BadRequest, + ErrorInfo("Illegal 'host' header: Invalid input ' ', expected 'EOI', ':', UPPER_ALPHA, lower-reg-name-char or pct-encoded (line 1, column 3)", "x; dummy\n ^")) + + """GET / HTTP/1.1 + |Content-length: 3; dummy + | + |""" should parseToError( + BadRequest, + ErrorInfo("Illegal `Content-Length` header value")) + + """GET / HTTP/1.1 + |Connection:keep-alive; dummy + | + |""" should parseToError( + BadRequest, + ErrorInfo("Illegal 'connection' header: Invalid input ';', expected tchar, OWS, listSep or 'EOI' (line 1, column 11)", "keep-alive; dummy\n ^")) + + """GET / HTTP/1.1 + |Transfer-Encoding: chunked; dummy + | + |""" should parseToError( + BadRequest, + ErrorInfo("Illegal 'transfer-encoding' header: Invalid input ';', expected OWS, listSep or 'EOI' (line 1, column 8)", "chunked; dummy\n ^")) + } } } diff --git a/akka-http-core/src/test/scala/akka/http/scaladsl/model/headers/HeaderSpec.scala b/akka-http-core/src/test/scala/akka/http/scaladsl/model/headers/HeaderSpec.scala index 4d3f62733d..b84d0d104b 100644 --- a/akka-http-core/src/test/scala/akka/http/scaladsl/model/headers/HeaderSpec.scala +++ b/akka-http-core/src/test/scala/akka/http/scaladsl/model/headers/HeaderSpec.scala @@ -68,6 +68,12 @@ class HeaderSpec extends FreeSpec with Matchers { headers.`Strict-Transport-Security`.parseFromValueString("max-age=30; includeSubDomains") shouldEqual Right(headers.`Strict-Transport-Security`(30, true)) headers.`Strict-Transport-Security`.parseFromValueString("max-age=30; includeSubDomains; preload") shouldEqual Right(headers.`Strict-Transport-Security`(30, true)) } + "successful parse run with additional values" in { + headers.`Strict-Transport-Security`.parseFromValueString("max-age=30; includeSubDomains; preload; dummy") shouldEqual + Right(headers.`Strict-Transport-Security`(30, true)) + headers.`Strict-Transport-Security`.parseFromValueString("max-age=30; includeSubDomains; dummy; preload") shouldEqual + Right(headers.`Strict-Transport-Security`(30, true)) + } "failing parse run" in { val Left(List(ErrorInfo(summary, detail))) = `Strict-Transport-Security`.parseFromValueString("max-age=30; includeSubDomains; preload;") summary shouldEqual "Illegal HTTP header 'Strict-Transport-Security': Invalid input 'EOI', expected OWS or token0 (line 1, column 40)"