-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
228 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import Foundation | ||
|
||
@propertyWrapper | ||
public struct RequestCookies { | ||
public var wrappedValue: [HTTPCookie] | ||
|
||
public init(wrappedValue: [HTTPCookie] = []) { | ||
self.wrappedValue = wrappedValue | ||
} | ||
} | ||
|
||
// MARK: Encodable | ||
|
||
extension RequestCookies: Encodable { | ||
public func encode(to encoder: Encoder) throws { | ||
// This method needs to defined because `HTTPCookie` does not conform to `Encodable`, but should never be called anyways | ||
preconditionFailure("\(Self.self).encode(to encoder:) should not be called") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import Foundation | ||
|
||
@propertyWrapper | ||
public struct ResponseCookies { | ||
|
||
public var wrappedValue: [HTTPCookie] | ||
|
||
public init(wrappedValue: [HTTPCookie] = []) { | ||
self.wrappedValue = wrappedValue | ||
} | ||
} | ||
|
||
extension ResponseCookies: Decodable { | ||
|
||
public init(from decoder: Decoder) throws { | ||
// Check if the decoder is response decoder, otherwise throw fatal error, because this property wrapper must use the correct decoder | ||
guard let responseDecoding = decoder as? ResponseDecoding else { | ||
preconditionFailure("\(Self.self) can only be used with \(ResponseDecoding.self)") | ||
} | ||
guard let url = responseDecoding.response.url, let allHeaderFields = responseDecoding.response.allHeaderFields as? [String: String] else { | ||
throw APIError.invalidResponse | ||
} | ||
self.wrappedValue = HTTPCookie.cookies(withResponseHeaderFields: allHeaderFields, for: url) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
Tests/PostieTests/Cookies/RequestCookiesCodingTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// swiftlint:disable nesting | ||
@testable import Postie | ||
import XCTest | ||
|
||
class RequestCookiesCodingTests: XCTestCase { | ||
let baseURL = URL(string: "https://local.url")! | ||
let cookies = [ | ||
HTTPCookie(properties: [ | ||
.domain: "local.url", | ||
.path: "/some/path", | ||
.name: "key", | ||
.value: "value" | ||
])! | ||
] | ||
|
||
func testEncoding_cookies_shouldBeSetInHeaders() { | ||
struct Request: Postie.Request { | ||
typealias Response = EmptyResponse | ||
|
||
@RequestCookies var cookies | ||
} | ||
|
||
var request = Request() | ||
request.cookies = cookies | ||
|
||
let encoder = RequestEncoder(baseURL: baseURL) | ||
let encoded: URLRequest | ||
do { | ||
encoded = try encoder.encode(request) | ||
} catch { | ||
XCTFail("Failed to encode: " + error.localizedDescription) | ||
return | ||
} | ||
XCTAssertEqual(encoded.value(forHTTPHeaderField: "Cookie"), "key=value") | ||
} | ||
|
||
func testEncoding_emptyCookiesCustomHeader_shouldNotAffectExistingCookieHeaders() { | ||
struct Request: Postie.Request { | ||
typealias Response = EmptyResponse | ||
|
||
@RequestCookies var cookies | ||
|
||
@RequestHeader(name: "Cookie") var cookieHeader | ||
} | ||
|
||
var request = Request() | ||
request.cookieHeader = "some header" | ||
|
||
let encoder = RequestEncoder(baseURL: baseURL) | ||
let encoded: URLRequest | ||
do { | ||
encoded = try encoder.encode(request) | ||
} catch { | ||
XCTFail("Failed to encode: " + error.localizedDescription) | ||
return | ||
} | ||
XCTAssertEqual(encoded.value(forHTTPHeaderField: "Cookie"), "some header") | ||
} | ||
|
||
func testEncoding_cookiesAndCustomHeaders_shouldBeMergedIntoHeaders() { | ||
struct Request: Postie.Request { | ||
typealias Response = EmptyResponse | ||
|
||
@RequestCookies var cookies | ||
|
||
@RequestHeader(name: "Some-Header") var someHeader | ||
} | ||
|
||
var request = Request() | ||
request.cookies = cookies | ||
request.someHeader = "some header" | ||
|
||
let encoder = RequestEncoder(baseURL: baseURL) | ||
let encoded: URLRequest | ||
do { | ||
encoded = try encoder.encode(request) | ||
} catch { | ||
XCTFail("Failed to encode: " + error.localizedDescription) | ||
return | ||
} | ||
XCTAssertEqual(encoded.value(forHTTPHeaderField: "Cookie"), "key=value") | ||
XCTAssertEqual(encoded.value(forHTTPHeaderField: "Some-Header"), "some header") | ||
} | ||
|
||
func testEncoding_cookiesCustomHeader_shouldBeOverwrittenByCustomHeaders() { | ||
struct Request: Postie.Request { | ||
typealias Response = EmptyResponse | ||
|
||
@RequestCookies var cookies | ||
|
||
@RequestHeader(name: "Cookie") var cookieHeader | ||
} | ||
|
||
var request = Request() | ||
request.cookies = cookies | ||
request.cookieHeader = "some header" | ||
|
||
let encoder = RequestEncoder(baseURL: baseURL) | ||
let encoded: URLRequest | ||
do { | ||
encoded = try encoder.encode(request) | ||
} catch { | ||
XCTFail("Failed to encode: " + error.localizedDescription) | ||
return | ||
} | ||
XCTAssertEqual(encoded.value(forHTTPHeaderField: "Cookie"), "some header") | ||
} | ||
} | ||
|
||
// swiftlint:enable nesting |
35 changes: 35 additions & 0 deletions
35
Tests/PostieTests/Cookies/ResponseCookiesCodingTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
@testable import Postie | ||
import XCTest | ||
|
||
private struct Response: Decodable { | ||
@ResponseCookies var cookies | ||
} | ||
|
||
class ResponseCookiesCodingTests: XCTestCase { | ||
let response = HTTPURLResponse(url: URL(string: "https://example.local")!, statusCode: 200, httpVersion: nil, headerFields: [ | ||
// swiftlint:disable:next line_length | ||
"Set-Cookie": "UserSession=xyz123; Domain=example.local; Path=/some/path; Expires=Wed, 06 Dec 2023 09:38:21 GMT; Max-Age=3600; Secure; HttpOnly; SameSite=Strict" | ||
])! | ||
let cookie = HTTPCookie(properties: [ | ||
.version: "0", | ||
.name: "UserSession", | ||
.value: "xyz123", | ||
.domain: "example.local", | ||
.path: "/some/path", | ||
|
||
.expires: Date(timeIntervalSince1970: 1_701_859_806), | ||
.maximumAge: "3600", | ||
|
||
.secure: true, | ||
.sameSitePolicy: "Strict" | ||
])! | ||
|
||
func testDecoding_defaultStrategy_shouldDecodeCaseInSensitiveResponseHeaders() { | ||
let decoder = ResponseDecoder() | ||
guard let decoded = try CheckNoThrow(decoder.decode(Response.self, from: (Data(), response))) else { | ||
return | ||
} | ||
XCTAssertEqual(decoded.cookies.first?.name, "UserSession") | ||
XCTAssertEqual(decoded.cookies.first?.value, "xyz123") | ||
} | ||
} |