Skip to content

Commit

Permalink
Improve performance of HTTPHeaders.subscript(canonicalForm:) (#1952)
Browse files Browse the repository at this point in the history
Motivation:

When getting the canonical form of header values any ascii whitespace
is stripped from the values. The current implementation does this by
doing equality checks on `Character` which is quite expensive.

Modifications:

- Update the `Substring.trimWhitespace()` function to trim on a UTF8
  view

Result:

Retrieving the canonical form of header values is cheaper, significantly
so when values contain whitespace.
  • Loading branch information
glbrntt committed Sep 13, 2021
1 parent 7e1ca33 commit 10d9790
Showing 1 changed file with 21 additions and 12 deletions.
33 changes: 21 additions & 12 deletions Sources/NIOHTTP1/HTTPTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -540,28 +540,37 @@ extension HTTPHeaders: RandomAccessCollection {
}
}

extension Character {
extension UTF8.CodeUnit {
var isASCIIWhitespace: Bool {
return self == " " || self == "\t" || self == "\r" || self == "\n" || self == "\r\n"
switch self {
case UInt8(ascii: " "),
UInt8(ascii: "\t"),
UInt8(ascii: "\r"),
UInt8(ascii: "\n"):
return true

default:
return false
}
}
}

extension String {
func trimASCIIWhitespace() -> Substring {
return self.dropFirst(0).trimWhitespace()
return Substring(self).trimWhitespace()
}
}

private extension Substring {
func trimWhitespace() -> Substring {
var me = self
while me.first?.isASCIIWhitespace == .some(true) {
me = me.dropFirst()
}
while me.last?.isASCIIWhitespace == .some(true) {
me = me.dropLast()
extension Substring {
fileprivate func trimWhitespace() -> Substring {
guard let firstNonWhitespace = self.utf8.firstIndex(where: { !$0.isASCIIWhitespace }) else {
// The whole substring is ASCII whitespace.
return Substring()
}
return me

// There must be at least one non-ascii whitespace character, so banging here is safe.
let lastNonWhitespace = self.utf8.lastIndex(where: { !$0.isASCIIWhitespace })!
return Substring(self.utf8[firstNonWhitespace...lastNonWhitespace])
}
}

Expand Down

0 comments on commit 10d9790

Please sign in to comment.