Skip to content

Commit 9d11142

Browse files
authored
fix: Escape special characters in URL path prior to constructing URL (#442)
1 parent 88b9bd6 commit 9d11142

File tree

2 files changed

+21
-2
lines changed

2 files changed

+21
-2
lines changed

Packages/ClientRuntime/Sources/Networking/Http/SdkHttpRequest.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
* SPDX-License-Identifier: Apache-2.0.
44
*/
5-
5+
import struct Foundation.CharacterSet
66
import struct Foundation.URLQueryItem
77
import struct Foundation.URLComponents
88
import AwsCommonRuntimeKit
@@ -29,12 +29,22 @@ public class SdkHttpRequest {
2929
}
3030
}
3131

32+
// Create a `CharacterSet` of the characters that need not be percent encoded in the
33+
// resulting URL. This set consists of alphanumerics plus underscore, dash, tilde, and
34+
// period. Any other character should be percent-encoded when used in a path segment.
35+
// Forward-slash is added as well because the segments have already been joined into a path.
36+
//
37+
// See, for URL-allowed characters:
38+
// https://www.rfc-editor.org/rfc/rfc3986#section-2.3
39+
private let allowed = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "/_-.~"))
40+
3241
extension SdkHttpRequest {
3342
public func toHttpRequest(bufferSize: Int = 1024) -> HttpRequest {
3443
let httpHeaders = headers.toHttpHeaders()
3544
let httpRequest = HttpRequest()
3645
httpRequest.method = method.rawValue
37-
httpRequest.path = "\(endpoint.path)\(endpoint.queryItemString)"
46+
let encodedPath = endpoint.path.addingPercentEncoding(withAllowedCharacters: allowed) ?? endpoint.path
47+
httpRequest.path = "\(encodedPath)\(endpoint.queryItemString)"
3848
httpRequest.addHeaders(headers: httpHeaders)
3949
httpRequest.body = body.toAwsInputStream()
4050
return httpRequest

Packages/ClientRuntime/Tests/NetworkingTests/HttpRequestTests.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ class HttpRequestTests: NetworkingTestUtils {
9393
XCTAssert(updatedRequest.queryItems.contains(queryItem2))
9494
XCTAssert(updatedRequest.queryItems.contains(URLQueryItem(name: "signedthing", value: "signed")))
9595
}
96+
97+
func testPathInInHttpRequestIsEscapedPerRFC3986() throws {
98+
let builder = SdkHttpRequestBuilder()
99+
.withHeader(name: "Host", value: "xctest.amazon.com")
100+
.withPath("/space /colon:/dollar$/tilde~/dash-/underscore_/period.")
101+
let httpRequest = builder.build().toHttpRequest()
102+
let escapedPath = "/space%20/colon%3A/dollar%24/tilde~/dash-/underscore_/period."
103+
XCTAssertEqual(httpRequest.path, escapedPath)
104+
}
96105

97106
func testConversionToUrlRequestFailsWithInvalidEndpoint() {
98107
// TODO:: When is the endpoint invalid or endpoint.url nil?

0 commit comments

Comments
 (0)