=htc #16482 preserve header order during parse
This commit is contained in:
parent
bd3ee6b54f
commit
f0c83631e1
4 changed files with 19 additions and 19 deletions
|
|
@ -97,7 +97,7 @@ private[http] abstract class HttpMessageParser[Output >: MessageOutput <: Parser
|
|||
|
||||
def badProtocol: Nothing
|
||||
|
||||
@tailrec final def parseHeaderLines(input: ByteString, lineStart: Int, headers: List[HttpHeader] = Nil,
|
||||
@tailrec final def parseHeaderLines(input: ByteString, lineStart: Int, headers: ListBuffer[HttpHeader] = ListBuffer[HttpHeader](),
|
||||
headerCount: Int = 0, ch: Option[Connection] = None,
|
||||
clh: Option[`Content-Length`] = None, cth: Option[`Content-Type`] = None,
|
||||
teh: Option[`Transfer-Encoding`] = None, e100c: Boolean = false,
|
||||
|
|
@ -117,7 +117,7 @@ private[http] abstract class HttpMessageParser[Output >: MessageOutput <: Parser
|
|||
case HttpHeaderParser.EmptyHeader ⇒
|
||||
val close = HttpMessage.connectionCloseExpected(protocol, ch)
|
||||
setCompletionHandling(CompletionIsEntityStreamError)
|
||||
parseEntity(headers, protocol, input, lineEnd, clh, cth, teh, e100c, hh, close)
|
||||
parseEntity(headers.toList, protocol, input, lineEnd, clh, cth, teh, e100c, hh, close)
|
||||
|
||||
case h: `Content-Length` ⇒ clh match {
|
||||
case None ⇒ parseHeaderLines(input, lineEnd, headers, headerCount + 1, ch, Some(h), cth, teh, e100c, hh)
|
||||
|
|
@ -134,21 +134,21 @@ private[http] abstract class HttpMessageParser[Output >: MessageOutput <: Parser
|
|||
case Some(x) ⇒ parseHeaderLines(input, lineEnd, headers, headerCount, ch, clh, cth, Some(x append h.encodings), e100c, hh)
|
||||
}
|
||||
case h: Connection ⇒ ch match {
|
||||
case None ⇒ parseHeaderLines(input, lineEnd, h :: headers, headerCount + 1, Some(h), clh, cth, teh, e100c, hh)
|
||||
case None ⇒ parseHeaderLines(input, lineEnd, headers += h, headerCount + 1, Some(h), clh, cth, teh, e100c, hh)
|
||||
case Some(x) ⇒ parseHeaderLines(input, lineEnd, headers, headerCount, Some(x append h.tokens), clh, cth, teh, e100c, hh)
|
||||
}
|
||||
case h: Host ⇒
|
||||
if (!hh) parseHeaderLines(input, lineEnd, h :: headers, headerCount + 1, ch, clh, cth, teh, e100c, hh = true)
|
||||
if (!hh) parseHeaderLines(input, lineEnd, headers += h, headerCount + 1, ch, clh, cth, teh, e100c, hh = true)
|
||||
else failMessageStart("HTTP message must not contain more than one Host header")
|
||||
|
||||
case h: Expect ⇒ parseHeaderLines(input, lineEnd, h :: headers, headerCount + 1, ch, clh, cth, teh, e100c = true, hh)
|
||||
case h: Expect ⇒ parseHeaderLines(input, lineEnd, headers += h, headerCount + 1, ch, clh, cth, teh, e100c = true, hh)
|
||||
|
||||
case h ⇒ parseHeaderLines(input, lineEnd, h :: headers, headerCount + 1, ch, clh, cth, teh, e100c, hh)
|
||||
case h ⇒ parseHeaderLines(input, lineEnd, headers += h, headerCount + 1, ch, clh, cth, teh, e100c, hh)
|
||||
}
|
||||
} else failMessageStart(s"HTTP message contains more than the configured limit of $maxHeaderCount headers")
|
||||
|
||||
// work-around for compiler complaining about non-tail-recursion if we inline this method
|
||||
def parseHeaderLinesAux(headers: List[HttpHeader], headerCount: Int, ch: Option[Connection],
|
||||
def parseHeaderLinesAux(headers: ListBuffer[HttpHeader], headerCount: Int, ch: Option[Connection],
|
||||
clh: Option[`Content-Length`], cth: Option[`Content-Type`], teh: Option[`Transfer-Encoding`],
|
||||
e100c: Boolean, hh: Boolean)(input: ByteString, lineStart: Int): StateResult =
|
||||
parseHeaderLines(input, lineStart, headers, headerCount, ch, clh, cth, teh, e100c, hh)
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class ClientServerSpec extends WordSpec with Matchers with BeforeAndAfterAll {
|
|||
|
||||
val serverInSub = serverIn.expectSubscription()
|
||||
serverInSub.request(1)
|
||||
private val HttpRequest(POST, uri, List(`User-Agent`(_), Host(_, _), Accept(Vector(MediaRanges.`*/*`))),
|
||||
private val HttpRequest(POST, uri, List(Accept(Seq(MediaRanges.`*/*`)), Host(_, _), `User-Agent`(_)),
|
||||
Chunked(`chunkedContentType`, chunkStream), HttpProtocols.`HTTP/1.1`) = serverIn.expectNext()
|
||||
uri shouldEqual Uri(s"http://$hostname:$port/chunked")
|
||||
Await.result(chunkStream.grouped(4).runWith(Sink.head), 100.millis) shouldEqual chunks
|
||||
|
|
@ -107,7 +107,7 @@ class ClientServerSpec extends WordSpec with Matchers with BeforeAndAfterAll {
|
|||
|
||||
val clientInSub = clientIn.expectSubscription()
|
||||
clientInSub.request(1)
|
||||
val HttpResponse(StatusCodes.PartialContent, List(Date(_), Server(_), RawHeader("Age", "42")),
|
||||
val HttpResponse(StatusCodes.PartialContent, List(RawHeader("Age", "42"), Server(_), Date(_)),
|
||||
Chunked(`chunkedContentType`, chunkStream2), HttpProtocols.`HTTP/1.1`) = clientIn.expectNext()
|
||||
Await.result(chunkStream2.grouped(1000).runWith(Sink.head), 100.millis) shouldEqual chunks
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
|
|||
|Content-length: 17
|
||||
|
|
||||
|Shake your BOODY!""" should parseTo {
|
||||
HttpRequest(POST, "/resource/yes", List(Connection("keep-alive"), `User-Agent`("curl/7.19.7 xyz")),
|
||||
HttpRequest(POST, "/resource/yes", List(`User-Agent`("curl/7.19.7 xyz"), Connection("keep-alive")),
|
||||
"Shake your BOODY!", `HTTP/1.0`)
|
||||
}
|
||||
closeAfterResponseCompletion shouldEqual Seq(false)
|
||||
|
|
@ -91,7 +91,7 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
|
|||
|Shake your BOODY!GET / HTTP/1.0
|
||||
|
|
||||
|""" should parseTo(
|
||||
HttpRequest(POST, "/resource/yes", List(Connection("keep-alive"), `User-Agent`("curl/7.19.7 xyz")),
|
||||
HttpRequest(POST, "/resource/yes", List(`User-Agent`("curl/7.19.7 xyz"), Connection("keep-alive")),
|
||||
"Shake your BOODY!".getBytes, `HTTP/1.0`),
|
||||
HttpRequest(protocol = `HTTP/1.0`))
|
||||
closeAfterResponseCompletion shouldEqual Seq(false, true)
|
||||
|
|
@ -107,8 +107,8 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
|
|||
| fancy
|
||||
|
|
||||
|""" should parseTo {
|
||||
HttpRequest(DELETE, "/abc", List(Connection("close", "fancy"), Accept(MediaRanges.`*/*`),
|
||||
`User-Agent`("curl/7.19.7 abc xyz")), protocol = `HTTP/1.0`)
|
||||
HttpRequest(DELETE, "/abc", List(`User-Agent`("curl/7.19.7 abc xyz"), Accept(MediaRanges.`*/*`),
|
||||
Connection("close", "fancy")), protocol = `HTTP/1.0`)
|
||||
}
|
||||
closeAfterResponseCompletion shouldEqual Seq(true)
|
||||
}
|
||||
|
|
@ -165,7 +165,7 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
|
|||
|Host: ping
|
||||
|
|
||||
|"""
|
||||
val baseRequest = HttpRequest(PATCH, "/data", List(Host("ping"), Connection("lalelu")))
|
||||
val baseRequest = HttpRequest(PATCH, "/data", List(Connection("lalelu"), Host("ping")))
|
||||
|
||||
"request start" in new Test {
|
||||
Seq(start, "rest") should generalMultiParseTo(
|
||||
|
|
@ -217,7 +217,7 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
|
|||
|
|
||||
|""") should generalMultiParseTo(
|
||||
Right(baseRequest.withEntity(Chunked(`application/pdf`,
|
||||
source(LastChunk("nice=true", List(RawHeader("Bar", "xyz"), RawHeader("Foo", "pip apo"))))))))
|
||||
source(LastChunk("nice=true", List(RawHeader("Foo", "pip apo"), RawHeader("Bar", "xyz"))))))))
|
||||
closeAfterResponseCompletion shouldEqual Seq(false)
|
||||
}
|
||||
|
||||
|
|
@ -276,7 +276,7 @@ class RequestParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
|
|||
|Host: ping
|
||||
|
|
||||
|"""
|
||||
val baseRequest = HttpRequest(PATCH, "/data", List(Host("ping"), Connection("lalelu")),
|
||||
val baseRequest = HttpRequest(PATCH, "/data", List(Connection("lalelu"), Host("ping")),
|
||||
HttpEntity.Chunked(`application/octet-stream`, source()))
|
||||
|
||||
"an illegal char after chunk size" in new Test {
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ class ResponseParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
|
|||
|Content-Type: text/plain; charset=UTF-8
|
||||
|
|
||||
|Sh""", "ake your BOODY!HTTP/1.") should generalMultiParseTo(
|
||||
Right(HttpResponse(InternalServerError, List(Connection("close"), `User-Agent`("curl/7.19.7 xyz")),
|
||||
Right(HttpResponse(InternalServerError, List(`User-Agent`("curl/7.19.7 xyz"), Connection("close")),
|
||||
"Shake your BOODY!")))
|
||||
closeAfterResponseCompletion shouldEqual Seq(true)
|
||||
}
|
||||
|
|
@ -130,7 +130,7 @@ class ResponseParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
|
|||
|Server: spray-can
|
||||
|
|
||||
|"""
|
||||
val baseResponse = HttpResponse(headers = List(Server("spray-can"), Connection("lalelu")))
|
||||
val baseResponse = HttpResponse(headers = List(Connection("lalelu"), Server("spray-can")))
|
||||
|
||||
"response start" in new Test {
|
||||
Seq(start, "rest") should generalMultiParseTo(
|
||||
|
|
@ -181,7 +181,7 @@ class ResponseParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
|
|||
|
|
||||
|HT""") should generalMultiParseTo(
|
||||
Right(baseResponse.withEntity(Chunked(`application/pdf`,
|
||||
source(LastChunk("nice=true", List(RawHeader("Bar", "xyz"), RawHeader("Foo", "pip apo"))))))),
|
||||
source(LastChunk("nice=true", List(RawHeader("Foo", "pip apo"), RawHeader("Bar", "xyz"))))))),
|
||||
Left(MessageStartError(400: StatusCode, ErrorInfo("Illegal HTTP message start"))))
|
||||
closeAfterResponseCompletion shouldEqual Seq(false)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue