Coverage Report

Created: 2025-07-23 06:54

/src/swift-nio/Sources/NIOHTTP1/ByteCollectionUtils.swift
Line
Count
Source (jump to first uncovered line)
1
//===----------------------------------------------------------------------===//
2
//
3
// This source file is part of the SwiftNIO open source project
4
//
5
// Copyright (c) 2017-2021 Apple Inc. and the SwiftNIO project authors
6
// Licensed under Apache License v2.0
7
//
8
// See LICENSE.txt for license information
9
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
10
//
11
// SPDX-License-Identifier: Apache-2.0
12
//
13
//===----------------------------------------------------------------------===//
14
15
import NIOCore
16
17
0
private let defaultWhitespaces = [" ", "\t"].map({ $0.utf8.first! })
18
19
extension ByteBufferView {
20
0
    internal func trim(limitingElements: [UInt8]) -> ByteBufferView {
21
0
        guard let lastNonWhitespaceIndex = self.lastIndex(where: { !limitingElements.contains($0) }),
22
0
            let firstNonWhitespaceIndex = self.firstIndex(where: { !limitingElements.contains($0) })
23
0
        else {
24
0
            // This buffer is entirely trimmed elements, so trim it to nothing.
25
0
            return self[self.startIndex..<self.startIndex]
26
0
        }
27
0
        return self[firstNonWhitespaceIndex..<index(after: lastNonWhitespaceIndex)]
28
0
    }
29
30
0
    internal func trimSpaces() -> ByteBufferView {
31
0
        trim(limitingElements: defaultWhitespaces)
32
0
    }
33
}
34
35
extension Sequence where Self.Element == UInt8 {
36
    /// Compares the collection of `UInt8`s to a case insensitive collection.
37
    ///
38
    /// This collection could be get from applying the `UTF8View`
39
    ///   property on the string protocol.
40
    ///
41
    /// - Parameter bytes: The string constant in the form of a collection of `UInt8`
42
    /// - Returns: Whether the collection contains **EXACTLY** this array or no, but by ignoring case.
43
    internal func compareCaseInsensitiveASCIIBytes<T: Sequence>(to: T) -> Bool
44
0
    where T.Element == UInt8 {
45
0
        // fast path: we can get the underlying bytes of both
46
0
        let maybeMaybeResult = self.withContiguousStorageIfAvailable { lhsBuffer -> Bool? in
47
0
            to.withContiguousStorageIfAvailable { rhsBuffer in
48
0
                if lhsBuffer.count != rhsBuffer.count {
49
0
                    return false
50
0
                }
51
0
52
0
                for idx in 0..<lhsBuffer.count {
53
0
                    // let's hope this gets vectorised ;)
54
0
                    if lhsBuffer[idx] & 0xdf != rhsBuffer[idx] & 0xdf {
55
0
                        return false
56
0
                    }
57
0
                }
58
0
                return true
59
0
            }
60
0
        }
61
0
62
0
        if let maybeResult = maybeMaybeResult, let result = maybeResult {
63
0
            return result
64
0
        } else {
65
0
            return self.elementsEqual(to, by: { ($0 & 0xdf) == ($1 & 0xdf) })
66
0
        }
67
0
    }
68
}
69
70
extension String {
71
0
    internal func isEqualCaseInsensitiveASCIIBytes(to: String) -> Bool {
72
0
        self.utf8.compareCaseInsensitiveASCIIBytes(to: to.utf8)
73
0
    }
74
}