Repository: ktorio/ktor
File: ktor-http/common/src/io/ktor/http/header/utils.kt (Kotlin)

Code before:
 */
internal val NON_LIST_HEADERS: Set<String> = setOf(
    HttpHeaders.SetCookie,
    HttpHeaders.Cookie,
    HttpHeaders.Authorization,
    HttpHeaders.ProxyAuthorization,
    HttpHeaders.ETag,
    HttpHeaders.IfRange,
    HttpHeaders.Date,
    HttpHeaders.LastModified,
    HttpHeaders.Expires,
    HttpHeaders.RetryAfter,
    HttpHeaders.ContentDisposition,
    HttpHeaders.Location,
    HttpHeaders.ContentLocation,
).map { it.lowercase() }.toSet()

/**
 * Returns `true` when [name] should be treated as a comma-separated list header.
 */
internal fun isCommaSeparatedHeader(name: String): Boolean = name.lowercase() !in NON_LIST_HEADERS

/**
 * Splits header's values on commas when the header is treated as a comma-separated list.
 */
internal fun splitValuesForHeader(values: Map<String, List<String>>) = values.entries.associate { (k, v) ->
    k to splitValuesForHeader(k, v)
}

/**
 * Splits header values on commas when the header is treated as a comma-separated list.
 */
internal fun splitValuesForHeader(name: String, values: List<String>): List<String> {
    if (values.isEmpty() || !isCommaSeparatedHeader(name)) return values

    return splitCommaHeaderValue(values)
}

private fun splitCommaHeaderValue(values: List<String>) = values.flatMap(::splitCommaHeaderValue)

/**
 * Comma splitter for a header value.
 *
 * Rules:
 * - Splits only on commas that are outside double-quoted strings.
 * - Supports backslash escaping inside quotes (e.g., `\"`).
 * - Trims optional whitespace around items.
 * - Skips empty items produced by consecutive separators.
 * - Preserves original quoting/escaping.
 */
private fun splitCommaHeaderValue(values: String): List<String> {

Review comment (performance):
Please also consider specifying the type explicitly. It would also be nice to have separate method names. `splitValueorHeader` has 2 overloads with different complexity

Code after:
 * If [splitInsideQuotes] is true, the function ignores quotes entirely and splits everywhere the [separator] appears.
 * Otherwise, [separator] that occurs inside a double-quoted string isn't treated as a split point.
 *
 * Rules:
 * - Supports backslash escaping inside quotes (e.g., `\"`).
 * - Trims optional whitespace around items.
 * - Skips empty items produced by consecutive separators.
 * - Preserves original quoting/escaping.
 *
 *  @param value The raw header value string.
 *  @param separator The character on which to split (e.g., ',' or ';').
 *  @param splitInsideQuotes If `true`, quotes are ignored and splitting occurs at every [separator].
 *                           If `false`, separators inside quoted strings are not considered split points.
 */
private fun splitHeaderValue(value: String, separator: Char, splitInsideQuotes: Boolean): List<String> {
    if (splitInsideQuotes) {
        return value.split(separator).map { it.trim() }.filter { it.isNotEmpty() }
    }

    val result = mutableListOf<String>()
    var start = 0
    var i = 0
    var inQuotes = false
    var escape = false

    fun emit(start: Int, end: Int) {
        val token = value.substring(start, end).trim()
        if (token.isNotEmpty()) result.add(token)
    }

    while (i < value.length) {
        val ch = value[i]
        if (inQuotes) {
            when {
                escape -> escape = false
                ch == '\\' -> escape = true
                ch == '"' -> inQuotes = false
            }
            i++
            continue
        }

        when (ch) {
            '"' -> {
                inQuotes = true
                i++
            }

            separator -> {
                emit(start, i)
                i++