From 2ae7fa7fec8eb0c4bdcb335335c4f00fc4bfa87a Mon Sep 17 00:00:00 2001 From: gregoryy Date: Sun, 18 Oct 2020 18:19:17 -0400 Subject: [PATCH 1/2] still return cookies if some fail to parse values, and accept % in directive name --- Sources/Vapor/HTTP/Headers/HTTPCookies.swift | 14 ++++++-------- .../Vapor/HTTP/Headers/HTTPHeaders+Directive.swift | 5 ++++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Sources/Vapor/HTTP/Headers/HTTPCookies.swift b/Sources/Vapor/HTTP/Headers/HTTPCookies.swift index 72389b49dd..9ad597f598 100644 --- a/Sources/Vapor/HTTP/Headers/HTTPCookies.swift +++ b/Sources/Vapor/HTTP/Headers/HTTPCookies.swift @@ -3,7 +3,7 @@ extension HTTPHeaders { /// This accesses the `"Cookie"` header. public var cookie: HTTPCookies? { get { - self.parseDirectives(name: .cookie).first.flatMap { + self.parseDirectives(name: .cookie).first.map { HTTPCookies(directives: $0) } } @@ -238,14 +238,12 @@ public struct HTTPCookies: ExpressibleByDictionaryLiteral { self.cookies = [:] } - init?(directives: [HTTPHeaders.Directive]) { - self.cookies = [:] - for directive in directives { - guard let value = directive.parameter else { - return nil + init(directives: [HTTPHeaders.Directive]) { + self.cookies = directives.reduce(into: [:], { (cookies, directive) in + if let value = directive.parameter { + cookies[.init(directive.value)] = .init(string: .init(value)) } - self.cookies[.init(directive.value)] = .init(string: .init(value)) - } + }) } /// See `ExpressibleByDictionaryLiteral`. diff --git a/Sources/Vapor/HTTP/Headers/HTTPHeaders+Directive.swift b/Sources/Vapor/HTTP/Headers/HTTPHeaders+Directive.swift index c7f0eb1c75..e4e9e94177 100644 --- a/Sources/Vapor/HTTP/Headers/HTTPHeaders+Directive.swift +++ b/Sources/Vapor/HTTP/Headers/HTTPHeaders+Directive.swift @@ -245,9 +245,12 @@ private extension Character { static var space: Self { .init(" ") } + static var percent: Self { + .init("%") + } var isDirectiveKey: Bool { - self.isLetter || self.isNumber || self == .dash || self == .underscore || self == .period + self.isLetter || self.isNumber || self == .dash || self == .underscore || self == .period || self == .percent } } From cc2218ef7733d24614a698ebb771932399510b98 Mon Sep 17 00:00:00 2001 From: gregoryy Date: Sun, 18 Oct 2020 18:38:32 -0400 Subject: [PATCH 2/2] added tests for cookie parsing --- Tests/VaporTests/HTTPHeaderTests.swift | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Tests/VaporTests/HTTPHeaderTests.swift b/Tests/VaporTests/HTTPHeaderTests.swift index b630c75c05..f3c33f40a7 100644 --- a/Tests/VaporTests/HTTPHeaderTests.swift +++ b/Tests/VaporTests/HTTPHeaderTests.swift @@ -185,6 +185,27 @@ final class HTTPHeaderTests: XCTestCase { XCTAssertEqual(headers.cookie?["cookie_one"]?.string, "1") XCTAssertEqual(headers.cookie?["cookie.two"]?.string, "2") } + + func testCookie_percentParsing() throws { + let headers = HTTPHeaders([ + ("cookie", "cookie_one=1;cookie%40cookieCom=2;cookie_3=three") + ]) + + XCTAssertEqual(headers.cookie?["cookie_one"]?.string, "1") + XCTAssertEqual(headers.cookie?["cookie%40cookieCom"]?.string, "2") + XCTAssertEqual(headers.cookie?["cookie_3"]?.string, "three") + } + + func testCookie_invalidCookie() throws { + let headers = HTTPHeaders([ + ("cookie", "cookie_one=1;cookie\ntwo=2;cookie_three=3") + ]) + + XCTAssertEqual(headers.cookie?.all.count, 2) + XCTAssertEqual(headers.cookie?["cookie_one"]?.string, "1") + XCTAssertNil(headers.cookie?["cookie\ntwo"]) + XCTAssertEqual(headers.cookie?["cookie_three"]?.string, "3") + } func testMediaTypeMainTypeCaseInsensitive() throws { let lower = HTTPMediaType(type: "foo", subType: "")