Skip to content

Commit

Permalink
Better Cookie Parsing (#2504) (#2511)
Browse files Browse the repository at this point in the history
* still return cookies if some fail to parse values, and accept % in directive name

* added tests for cookie parsing
  • Loading branch information
gregoryyoung2 committed Dec 11, 2020
1 parent 44320a8 commit c18eb56
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 9 deletions.
14 changes: 6 additions & 8 deletions Sources/Vapor/HTTP/Headers/HTTPCookies.swift
Expand Up @@ -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)
}
}
Expand Down Expand Up @@ -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`.
Expand Down
5 changes: 4 additions & 1 deletion Sources/Vapor/HTTP/Headers/HTTPHeaders+Directive.swift
Expand Up @@ -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
}
}

Expand Down
21 changes: 21 additions & 0 deletions Tests/VaporTests/HTTPHeaderTests.swift
Expand Up @@ -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: "")
Expand Down

0 comments on commit c18eb56

Please sign in to comment.