override final def onBadProtocol()

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/incubator-pekko-http/pull/989
      skipNewLine(cursor + 3)
    } else badStatusCode()
  }