@tailrec private def scanHeaderValue()

in http-core/src/main/scala/org/apache/pekko/http/impl/engine/parsing/HttpHeaderParser.scala [593:662]


  @tailrec private def scanHeaderValue(hhp: HttpHeaderParser, input: ByteString, start: Int, limit: Int,
      log: LoggingAdapter,
      mode: IllegalResponseHeaderValueProcessingMode)(sb: JStringBuilder = null, ix: Int = start): (String, Int) = {
    hhp.byteBuffer.clear()

    def appended(c: Char) = (if (sb != null) sb else new JStringBuilder(asciiString(input, start, ix))).append(c)
    def appended2(c: Int) = if ((c >> 16) != 0) appended(c.toChar).append((c >> 16).toChar) else appended(c.toChar)
    if (ix < limit)
      byteChar(input, ix) match {
        case '\t' => scanHeaderValue(hhp, input, start, limit, log, mode)(appended(' '), ix + 1)
        case '\r' if byteChar(input, ix + 1) == '\n' =>
          if (WSP(byteChar(input, ix + 2))) scanHeaderValue(hhp, input, start, limit, log, mode)(appended(' '), ix + 3)
          else (if (sb != null) sb.toString else asciiString(input, start, ix), ix + 2)
        case '\n' =>
          if (WSP(byteChar(input, ix + 1))) scanHeaderValue(hhp, input, start, limit, log, mode)(appended(' '), ix + 2)
          else (if (sb != null) sb.toString else asciiString(input, start, ix), ix + 1)
        case c =>
          var nix = ix + 1
          val nsb =
            if (' ' <= c && c <= '\u007F') if (sb != null) sb.append(c) else null // legal 7-Bit ASCII
            else if ((c & 0xE0) == 0xC0) { // 2-byte UTF-8 sequence?
              hhp.byteBuffer.put(c.toByte)
              hhp.byteBuffer.put(byteAt(input, ix + 1))
              nix = ix + 2
              hhp.decodeByteBuffer() match { // if we cannot decode as UTF8 we don't decode but simply copy
                case -1 => if (sb != null) sb.append(c).append(byteChar(input, ix + 1)) else null
                case cc => appended2(cc)
              }
            } else if ((c & 0xF0) == 0xE0) { // 3-byte UTF-8 sequence?
              hhp.byteBuffer.put(c.toByte)
              hhp.byteBuffer.put(byteAt(input, ix + 1))
              hhp.byteBuffer.put(byteAt(input, ix + 2))
              nix = ix + 3
              hhp.decodeByteBuffer() match { // if we cannot decode as UTF8 we don't decode but simply copy
                case -1 =>
                  if (sb != null) sb.append(c).append(byteChar(input, ix + 1)).append(byteChar(input, ix + 2)) else null
                case cc => appended2(cc)
              }
            } else if ((c & 0xF8) == 0xF0) { // 4-byte UTF-8 sequence?
              hhp.byteBuffer.put(c.toByte)
              hhp.byteBuffer.put(byteAt(input, ix + 1))
              hhp.byteBuffer.put(byteAt(input, ix + 2))
              hhp.byteBuffer.put(byteAt(input, ix + 3))
              nix = ix + 4
              hhp.decodeByteBuffer() match { // if we cannot decode as UTF8 we don't decode but simply copy
                case -1 =>
                  if (sb != null) sb.append(c).append(byteChar(input, ix + 1)).append(byteChar(input, ix + 2)).append(
                    byteChar(input, ix + 3))
                  else null
                case cc => appended2(cc)
              }
            } else {
              mode match {
                case ParserSettings.IllegalResponseHeaderValueProcessingMode.Error =>
                  fail(s"Illegal character '${escape(c)}' in header value")
                case ParserSettings.IllegalResponseHeaderValueProcessingMode.Warn =>
                  // ignore the illegal character and log a warning message
                  log.warning(s"Illegal character '${escape(c)}' in header value")
                  sb
                case ParserSettings.IllegalResponseHeaderValueProcessingMode.Ignore =>
                  // just ignore the illegal character
                  sb
              }

            }
          scanHeaderValue(hhp, input, start, limit, log, mode)(nsb, nix)
      }
    else fail(s"HTTP header value exceeds the configured limit of ${limit - start - 2} characters",
      StatusCodes.RequestHeaderFieldsTooLarge)
  }