in http-core/src/main/scala/org/apache/pekko/http/impl/engine/parsing/HttpHeaderParser.scala [109:165]
def createShallowCopy(): HttpHeaderParser =
new HttpHeaderParser(settings, log, onIllegalHeader, nodes, nodeCount, branchData, branchDataCount, values,
valueCount)
/**
* Parses a header line and returns the line start index of the subsequent line.
* The parsed header instance is written to the `resultHeader` member.
* If the trie still has space for this type of header (and as a whole) the parsed header is cached.
* Throws a `NotEnoughDataException` if the given input doesn't contain enough data to fully parse the given header
* line. Note that there must be at least one byte available after a CRLF sequence, in order to distinguish a true
* line ending from a line fold.
* If the header is invalid a respective `ParsingException` is thrown.
*/
@tailrec
def parseHeaderLine(input: ByteString, lineStart: Int = 0)(cursor: Int = lineStart, nodeIx: Int = 0): Int = {
def startValueBranch(rootValueIx: Int, valueParser: HeaderValueParser) = {
val (header, endIx) = valueParser(this, input, cursor, onIllegalHeader)
if (valueParser.cachingEnabled)
try {
val valueIx = newValueIndex // compute early in order to trigger OutOfTrieSpaceExceptions before any change
unshareIfRequired()
val nodeIx = nodeCount
insertRemainingCharsAsNewNodes(input, header)(cursor, endIx, valueIx)
values(rootValueIx) = ValueBranch(rootValueIx, valueParser, branchRootNodeIx = nodeIx, valueCount = 1)
} catch {
case OutOfTrieSpaceException => // if we cannot insert a value then we simply don't
}
resultHeader = header
endIx
}
val node = nodes(nodeIx)
node & 0xFF match {
case 0 => // leaf node (or intermediate ValueBranch pointer)
val valueIx = (node >>> 8) - 1
values(valueIx) match {
case branch: ValueBranch => parseHeaderValue(input, cursor, branch)()
case valueParser: HeaderValueParser => startValueBranch(valueIx, valueParser) // no header yet of this type
case EmptyHeader => resultHeader = EmptyHeader; cursor
}
case nodeChar =>
val char = toLowerCase(byteChar(input, cursor))
if (char == node) // fast match, advance and descend
parseHeaderLine(input, lineStart)(cursor + 1, nodeIx + 1)
else node >>> 8 match {
case 0 => // header doesn't exist yet and has no model (since we have not yet seen a colon)
parseRawHeader(input, lineStart, cursor, nodeIx)
case msb => // branching node
val signum = math.signum(char - nodeChar)
branchData(rowIx(msb) + 1 + signum) match {
case 0 => // header doesn't exist yet and has no model (otherwise we'd arrive at a value)
parseRawHeader(input, lineStart, cursor, nodeIx)
case subNodeIx => // descend into branch and advance on char matches (otherwise descend but don't advance)
parseHeaderLine(input, lineStart)(cursor + 1 - math.abs(signum), subNodeIx)
}
}
}
}