in http-core/src/main/scala/org/apache/pekko/http/impl/engine/parsing/HttpResponseParser.scala [73:134]
override final def onBadProtocol(input: ByteString) =
throw new ParsingException(
"The server-side protocol or HTTP version is not supported",
s"start of response: [${LogByteStringTools.printByteString(input.take(16), 16, addPrefix = false, indent = "")}]")
private def parseStatus(input: ByteString, cursor: Int): Int = {
def badStatusCode() = throw new ParsingException("Illegal response status code")
def badStatusCodeSpecific(code: Int) = throw new ParsingException("Illegal response status code: " + code)
def parseStatusCode(reasonStartIdx: Int = -1, reasonEndIdx: Int = -1): Unit = {
def intValue(offset: Int): Int = {
val c = byteChar(input, cursor + offset)
if (CharacterClasses.DIGIT(c)) c - '0' else badStatusCode()
}
val code = intValue(0) * 100 + intValue(1) * 10 + intValue(2)
statusCode = code match {
case 200 => StatusCodes.OK
case code => StatusCodes.getForKey(code) match {
case Some(x) => x
case None => customStatusCodes(code).getOrElse {
// A client must understand the class of any status code, as indicated by the first digit, and
// treat an unrecognized status code as being equivalent to the x00 status code of that class
// https://tools.ietf.org/html/rfc7231#section-6
try {
val reason = asciiString(input, reasonStartIdx, reasonEndIdx)
StatusCodes.custom(code, reason)
} catch {
case NonFatal(_) => badStatusCodeSpecific(code)
}
}
}
}
}
def isLF(idx: Int) = byteChar(input, idx) == '\n'
def isCRLF(idx: Int) = byteChar(input, idx) == '\r' && isLF(idx + 1)
def isNewLine(idx: Int) = isLF(idx) || isCRLF(idx)
def skipNewLine(idx: Int) = {
if (isCRLF(idx)) idx + 2
else if (isLF(idx)) idx + 1
else idx
}
if (byteChar(input, cursor + 3) == ' ') {
val startIdx = cursor + 4
@tailrec def scanNewLineIdx(idx: Int): Int =
if (idx - startIdx <= maxResponseReasonLength)
if (isNewLine(idx)) idx
else scanNewLineIdx(idx + 1)
else throw new ParsingException("Response reason phrase exceeds the configured limit of " +
maxResponseReasonLength + " characters")
val newLineIdx = scanNewLineIdx(startIdx)
parseStatusCode(startIdx, newLineIdx)
skipNewLine(newLineIdx)
} else if (isNewLine(cursor + 3)) {
parseStatusCode()
// Status format with no reason phrase and no trailing space accepted, diverging from the spec
// See https://github.com/apache/pekko-http/pull/989
skipNewLine(cursor + 3)
} else badStatusCode()
}