Merge pull request #18752 from 2beaucoup/missing-reason-phrase

=htp #17971 parse responses with missing reason phrase
This commit is contained in:
Roland Kuhn 2015-10-26 22:15:17 +01:00
commit e331e390d3
2 changed files with 30 additions and 17 deletions

View file

@ -34,8 +34,7 @@ private[http] class HttpResponseParser(_settings: ParserSettings, _headerParser:
if (requestMethodForCurrentResponse.isDefined) {
var cursor = parseProtocol(input, offset)
if (byteChar(input, cursor) == ' ') {
cursor = parseStatusCode(input, cursor + 1)
cursor = parseReason(input, cursor)()
cursor = parseStatus(input, cursor + 1)
parseHeaderLines(input, cursor)
} else badProtocol
} else {
@ -50,13 +49,13 @@ private[http] class HttpResponseParser(_settings: ParserSettings, _headerParser:
def badProtocol = throw new ParsingException("The server-side HTTP version is not supported")
def parseStatusCode(input: ByteString, cursor: Int): Int = {
def parseStatus(input: ByteString, cursor: Int): Int = {
def badStatusCode = throw new ParsingException("Illegal response status code")
def parseStatusCode() = {
def intValue(offset: Int): Int = {
val c = byteChar(input, cursor + offset)
if (CharacterClasses.DIGIT(c)) c - '0' else badStatusCode
}
if (byteChar(input, cursor + 3) == ' ') {
val code = intValue(0) * 100 + intValue(1) * 10 + intValue(2)
statusCode = code match {
case 200 StatusCodes.OK
@ -65,16 +64,21 @@ private[http] class HttpResponseParser(_settings: ParserSettings, _headerParser:
case None customStatusCodes(code) getOrElse badStatusCode
}
}
cursor + 4
} else badStatusCode
}
@tailrec private def parseReason(input: ByteString, startIx: Int)(cursor: Int = startIx): Int =
if (cursor - startIx <= maxResponseReasonLength)
if (byteChar(input, cursor) == '\r' && byteChar(input, cursor + 1) == '\n') cursor + 2
else parseReason(input, startIx)(cursor + 1)
if (byteChar(input, cursor + 3) == ' ') {
parseStatusCode()
val startIdx = cursor + 4
@tailrec def skipReason(idx: Int): Int =
if (idx - startIdx <= maxResponseReasonLength)
if (byteChar(input, idx) == '\r' && byteChar(input, idx + 1) == '\n') idx + 2
else skipReason(idx + 1)
else throw new ParsingException("Response reason phrase exceeds the configured limit of " +
maxResponseReasonLength + " characters")
skipReason(startIdx)
} else if (byteChar(input, cursor + 3) == '\r' && byteChar(input, cursor + 4) == '\n') {
throw new ParsingException("Status code misses trailing space")
} else badStatusCode
}
// http://tools.ietf.org/html/rfc7230#section-3.3
def parseEntity(headers: List[HttpHeader], protocol: HttpProtocol, input: ByteString, bodyStart: Int,

View file

@ -14,7 +14,6 @@ import org.scalatest.matchers.Matcher
import akka.util.ByteString
import akka.actor.ActorSystem
import akka.stream.scaladsl._
import akka.stream.scaladsl.FlattenStrategy
import akka.stream.ActorMaterializer
import akka.http.scaladsl.util.FastFuture._
import akka.http.impl.util._
@ -79,6 +78,11 @@ class ResponseParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
closeAfterResponseCompletion shouldEqual Seq(false)
}
"a response with a missing reason phrase" in new Test {
"HTTP/1.1 200 \r\nContent-Length: 0\r\n\r\n" should parseTo(HttpResponse(OK))
closeAfterResponseCompletion shouldEqual Seq(false)
}
"a response funky `Transfer-Encoding` header" in new Test {
override def parserSettings: ParserSettings =
super.parserSettings.withCustomStatusCodes(ServerOnTheMove)
@ -227,6 +231,11 @@ class ResponseParserSpec extends FreeSpec with Matchers with BeforeAndAfterAll {
MessageStartError(400: StatusCode, ErrorInfo("Response reason phrase exceeds the configured limit of 21 characters"))))
}
"with a missing reason phrase and no trailing space" in new Test {
Seq("HTTP/1.1 200\r\nContent-Length: 0\r\n\r\n") should generalMultiParseTo(Left(MessageStartError(
400: StatusCode, ErrorInfo("Status code misses trailing space"))))
}
"with entity length > max-content-length" - {
def response(dataElements: ByteString*) = HttpResponse(200, Nil,
HttpEntity.Chunked(`application/octet-stream`, Source(dataElements.map(ChunkStreamPart(_)).toVector)))