@tailrec protected final def parseHeaderLines()

in http-core/src/main/scala/org/apache/pekko/http/impl/engine/parsing/HttpMessageParser.scala [148:229]


  @tailrec protected final def parseHeaderLines(input: ByteString, lineStart: Int,
      headers: ListBuffer[HttpHeader] = initialHeaderBuffer,
      headerCount: Int = 0, ch: Option[Connection] = None,
      clh: Option[`Content-Length`] = None, cth: Option[`Content-Type`] = None,
      isChunked: Boolean = false, e100c: Boolean = false,
      hh: Boolean = false): StateResult =
    if (headerCount < settings.maxHeaderCount) {
      var lineEnd = 0
      val resultHeader =
        try {
          lineEnd = headerParser.parseHeaderLine(input, lineStart)()
          headerParser.resultHeader
        } catch {
          case NotEnoughDataException => null
        }
      resultHeader match {
        case null =>
          continue(input, lineStart)(parseHeaderLinesAux(headers, headerCount, ch, clh, cth, isChunked, e100c, hh))

        case EmptyHeader =>
          val close = HttpMessage.connectionCloseExpected(protocol, ch)
          setCompletionHandling(CompletionIsEntityStreamError)
          parseEntity(headers.toList, protocol, input, lineEnd, clh, cth, isChunked, e100c, hh, close, lastSession)

        case h: `Content-Length` => clh match {
            case None =>
              parseHeaderLines(input, lineEnd, headers, headerCount + 1, ch, Some(h), cth, isChunked, e100c, hh)
            case Some(`h`) => parseHeaderLines(input, lineEnd, headers, headerCount, ch, clh, cth, isChunked, e100c, hh)
            case _         => failMessageStart("HTTP message must not contain more than one Content-Length header")
          }
        case h: `Content-Type` => cth match {
            case None =>
              parseHeaderLines(input, lineEnd, headers, headerCount + 1, ch, clh, Some(h), isChunked, e100c, hh)
            case Some(`h`) =>
              parseHeaderLines(input, lineEnd, headers, headerCount, ch, clh, cth, isChunked, e100c, hh)
            case Some(`Content-Type`(ContentTypes.`NoContentType`)) => // never encountered except when parsing conflicting headers (see below)
              parseHeaderLines(input, lineEnd, headers += h, headerCount + 1, ch, clh, cth, isChunked, e100c, hh)
            case Some(x) =>
              import ConflictingContentTypeHeaderProcessingMode._
              settings.conflictingContentTypeHeaderProcessingMode match {
                case Error => failMessageStart("HTTP message must not contain more than one Content-Type header")
                case First =>
                  parseHeaderLines(input, lineEnd, headers += h, headerCount + 1, ch, clh, cth, isChunked, e100c, hh)
                case Last => parseHeaderLines(input, lineEnd, headers += x, headerCount + 1, ch, clh, Some(h),
                    isChunked, e100c, hh)
                case NoContentType => parseHeaderLines(input, lineEnd, headers += x += h, headerCount + 1, ch, clh,
                    Some(`Content-Type`(ContentTypes.`NoContentType`)), isChunked, e100c, hh)
              }
          }
        case h: `Transfer-Encoding` =>
          if (!isChunked) {
            h.encodings match {
              case Seq(TransferEncodings.chunked) =>
                // A single chunked is the only one we support
                parseHeaderLines(input, lineEnd, headers, headerCount + 1, ch, clh, cth, isChunked = true, e100c, hh)
              case Seq(unknown) =>
                failMessageStart(s"Unsupported Transfer-Encoding '${unknown.name}'")
              case _ =>
                failMessageStart("Multiple Transfer-Encoding entries not supported")

            }
          } else {
            // only allow one 'chunked'
            failMessageStart("Multiple Transfer-Encoding entries not supported")
          }
        case h: Connection => ch match {
            case None =>
              parseHeaderLines(input, lineEnd, headers += h, headerCount + 1, Some(h), clh, cth, isChunked, e100c, hh)
            case Some(x) => parseHeaderLines(input, lineEnd, headers, headerCount, Some(x.append(h.tokens)), clh, cth,
                isChunked, e100c, hh)
          }
        case h: Host =>
          if (!hh || isResponseParser)
            parseHeaderLines(input, lineEnd, headers += h, headerCount + 1, ch, clh, cth, isChunked, e100c, hh = true)
          else failMessageStart("HTTP message must not contain more than one Host header")

        case h: Expect =>
          parseHeaderLines(input, lineEnd, headers += h, headerCount + 1, ch, clh, cth, isChunked, e100c = true, hh)

        case h => parseHeaderLines(input, lineEnd, headers += h, headerCount + 1, ch, clh, cth, isChunked, e100c, hh)
      }
    } else