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)
}