Skip to content

Commit

Permalink
Merge pull request #48 from guoye-zhang/lenient-legalize
Browse files Browse the repository at this point in the history
Support lenient legalization of header field values
  • Loading branch information
guoye-zhang authored May 13, 2024
2 parents a584b11 + c835700 commit 8f1ba42
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 0 deletions.
26 changes: 26 additions & 0 deletions Sources/HTTPTypes/HTTPField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ public struct HTTPField: Sendable, Hashable {
self.rawValue = Self.legalizeValue(ISOLatin1String(value))
}

/// Create an HTTP field from a name and a value. Leniently legalize the value.
/// - Parameters:
/// - name: The HTTP field name.
/// - lenientValue: The HTTP field value. Newlines and NULs are converted into space
/// characters.
public init(name: Name, lenientValue: some Collection<UInt8>) {
self.name = name
self.rawValue = Self.lenientLegalizeValue(ISOLatin1String(lenientValue))
}

init(name: Name, uncheckedValue: ISOLatin1String) {
self.name = name
self.rawValue = uncheckedValue
Expand Down Expand Up @@ -162,6 +172,22 @@ public struct HTTPField: Sendable, Hashable {
}
}

static func lenientLegalizeValue(_ value: ISOLatin1String) -> ISOLatin1String {
if value._storage.utf8.allSatisfy({ $0 != 0x00 && $0 != 0x0A && $0 != 0x0D }) {
return value
} else {
let bytes = value._storage.utf8.lazy.map { byte -> UInt8 in
switch byte {
case 0x00, 0x0A, 0x0D:
return 0x20
default:
return byte
}
}
return ISOLatin1String(unchecked: String(decoding: bytes, as: UTF8.self))
}
}

/// Whether the string is valid for an HTTP field value based on RFC 9110.
///
/// https://www.rfc-editor.org/rfc/rfc9110.html#name-field-values
Expand Down
1 change: 1 addition & 0 deletions Tests/HTTPTypesTests/HTTPTypesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ final class HTTPTypesTests: XCTestCase {
XCTAssertEqual(HTTPField(name: .accept, value: " a 😀 \t\n b \t \r ").value, "a 😀 \t b")
XCTAssertEqual(HTTPField(name: .accept, value: "").value, "")
XCTAssertFalse(HTTPField.isValidValue(" "))
XCTAssertEqual(HTTPField(name: .accept, lenientValue: " \r\n\0\t ".utf8).value, " \t ")
}

func testRequest() {
Expand Down

0 comments on commit 8f1ba42

Please sign in to comment.