-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
swift: add conversion from Request to headers (#288)
Adds converters to go from `Request` to a set of headers that upstream Envoy understands. This will be utilized by the request logic in the `Envoy` class. Previous consideration: envoyproxy/envoy-mobile#275 Signed-off-by: Michael Rebello <me@michaelrebello.com> Signed-off-by: JP Simard <jp@jpsim.com>
- Loading branch information
Showing
6 changed files
with
129 additions
and
3 deletions.
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,25 @@ | ||
private let kRestrictedHeaderPrefix = ":" | ||
|
||
extension Request { | ||
/// Returns a set of outbound headers that include HTTP | ||
/// information on the URL, method, and additional headers. | ||
/// | ||
/// - returns: Outbound headers to send with an HTTP request. | ||
func outboundHeaders() -> [String: String] { | ||
var headers = self.headers | ||
.filter { !$0.key.hasPrefix(kRestrictedHeaderPrefix) } | ||
.mapValues { $0.joined(separator: ",") } | ||
.reduce(into: [ | ||
":method": self.method.stringValue, | ||
":scheme": self.scheme, | ||
":authority": self.authority, | ||
":path": self.path, | ||
]) { $0[$1.key] = $1.value } | ||
|
||
if let retryPolicy = self.retryPolicy { | ||
headers = headers.merging(retryPolicy.outboundHeaders()) { _, retryHeader in retryHeader } | ||
} | ||
|
||
return headers | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
@testable import Envoy | ||
import XCTest | ||
|
||
final class RequestMapperTests: XCTestCase { | ||
func testAddsMethodToHeaders() { | ||
let headers = RequestBuilder(method: .post, scheme: "https", authority: "x.y.z", path: "/foo") | ||
.build() | ||
.outboundHeaders() | ||
XCTAssertEqual("POST", headers[":method"]) | ||
} | ||
|
||
func testAddsSchemeToHeaders() { | ||
let headers = RequestBuilder(method: .post, scheme: "https", authority: "x.y.z", path: "/foo") | ||
.build() | ||
.outboundHeaders() | ||
XCTAssertEqual("https", headers[":scheme"]) | ||
} | ||
|
||
func testAddsAuthorityToHeaders() { | ||
let headers = RequestBuilder(method: .post, scheme: "https", authority: "x.y.z", path: "/foo") | ||
.build() | ||
.outboundHeaders() | ||
XCTAssertEqual("x.y.z", headers[":authority"]) | ||
} | ||
|
||
func testAddsPathToHeaders() { | ||
let headers = RequestBuilder(method: .post, scheme: "https", authority: "x.y.z", path: "/foo") | ||
.build() | ||
.outboundHeaders() | ||
XCTAssertEqual("/foo", headers[":path"]) | ||
} | ||
|
||
func testJoinsHeaderValuesWithTheSameKey() { | ||
let headers = RequestBuilder(method: .post, scheme: "https", authority: "x.y.z", path: "/foo") | ||
.addHeader(name: "foo", value: "1") | ||
.addHeader(name: "foo", value: "2") | ||
.build() | ||
.outboundHeaders() | ||
XCTAssertEqual("1,2", headers["foo"]) | ||
} | ||
|
||
func testStripsHeadersWithSemicolonPrefix() { | ||
let headers = RequestBuilder(method: .post, scheme: "https", authority: "x.y.z", path: "/foo") | ||
.addHeader(name: ":restricted", value: "someValue") | ||
.build() | ||
.outboundHeaders() | ||
XCTAssertNil(headers[":restricted"]) | ||
} | ||
|
||
func testCannotOverrideStandardRestrictedHeaders() { | ||
let headers = RequestBuilder(method: .post, scheme: "https", authority: "x.y.z", path: "/foo") | ||
.addHeader(name: ":scheme", value: "override") | ||
.addHeader(name: ":authority", value: "override") | ||
.addHeader(name: ":path", value: "override") | ||
.build() | ||
.outboundHeaders() | ||
|
||
XCTAssertEqual("https", headers[":scheme"]) | ||
XCTAssertEqual("x.y.z", headers[":authority"]) | ||
XCTAssertEqual("/foo", headers[":path"]) | ||
} | ||
|
||
func testIncludesRetryPolicyHeaders() { | ||
let retryPolicy = RetryPolicy(maxRetryCount: 123, retryOn: RetryRule.allCases, | ||
perRetryTimeoutMS: 9001) | ||
let retryHeaders = retryPolicy.outboundHeaders() | ||
let requestHeaders = RequestBuilder(method: .post, scheme: "https", | ||
authority: "x.y.z", path: "/foo") | ||
.addHeader(name: "foo", value: "bar") | ||
.addRetryPolicy(retryPolicy) | ||
.build() | ||
.outboundHeaders() | ||
|
||
XCTAssertEqual("bar", requestHeaders["foo"]) | ||
XCTAssertFalse(retryHeaders.isEmpty) | ||
for (retryHeader, expectedValue) in retryHeaders { | ||
XCTAssertEqual(expectedValue, requestHeaders[retryHeader]) | ||
} | ||
} | ||
|
||
func testRetryPolicyTakesPrecedenceOverManuallySetRetryHeaders() { | ||
let retryPolicy = RetryPolicy(maxRetryCount: 123, retryOn: RetryRule.allCases, | ||
perRetryTimeoutMS: 9001) | ||
let requestHeaders = RequestBuilder(method: .post, scheme: "https", | ||
authority: "x.y.z", path: "/foo") | ||
.addHeader(name: "x-envoy-max-retries", value: "override") | ||
.addRetryPolicy(retryPolicy) | ||
.build() | ||
.outboundHeaders() | ||
|
||
XCTAssertEqual("123", requestHeaders["x-envoy-max-retries"]) | ||
} | ||
} |
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