diff --git a/CHANGELOG.md b/CHANGELOG.md index a4eb5a6f..acce35b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ All notable changes to this project will be documented in this file. Changes not - Fix misspell `serialise`. ([#473](https://github.com/httpswift/swifter/pull/473)) by [@mtgto](https://github.com/mtgto) - Fix an issue causing Danger was not working properly. ([#486](https://github.com/httpswift/swifter/pull/486)) by [@Vkt0r](https://github.com/Vkt0r) - Set Swift version to 5.0 in podspec. ([#475](https://github.com/httpswift/swifter/pull/475)) by [@p-krasnobrovkin-tcs](https://github.com/p-krasnobrovkin-tcs) +- only escaping invalid data, keep valid escaping untouched ([#484](https://github.com/httpswift/swifter/pull/484)) by [@SolaWing](https://github.com/SolaWing) ## Changed diff --git a/Xcode/Sources/HttpParser.swift b/Xcode/Sources/HttpParser.swift index 5c1abfa9..e88fe11a 100644 --- a/Xcode/Sources/HttpParser.swift +++ b/Xcode/Sources/HttpParser.swift @@ -24,7 +24,7 @@ public class HttpParser { } let request = HttpRequest() request.method = statusLineTokens[0] - let encodedPath = statusLineTokens[1].addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? statusLineTokens[1] + let encodedPath = Self.escapingInvalidURL(statusLineTokens[1]) let urlComponents = URLComponents(string: encodedPath) request.path = urlComponents?.path ?? "" request.queryParams = urlComponents?.queryItems?.map { ($0.name, $0.value ?? "") } ?? [] @@ -38,7 +38,17 @@ public class HttpParser { request.body = try readBody(socket, size: contentLengthValue) } return request + } + + /// only escaping invalid chars,valid encodedPath keep untouched + static func escapingInvalidURL(_ url: String) -> String { + var urlAllowed: CharacterSet { + var allow = CharacterSet.urlQueryAllowed + allow.insert(charactersIn: "?#%") + return allow } + return url.addingPercentEncoding(withAllowedCharacters: urlAllowed) ?? url + } private func readBody(_ socket: Socket, size: Int) throws -> [UInt8] { return try socket.read(length: size) diff --git a/Xcode/Tests/SwifterTestsHttpParser.swift b/Xcode/Tests/SwifterTestsHttpParser.swift index b28c2190..991fdc76 100644 --- a/Xcode/Tests/SwifterTestsHttpParser.swift +++ b/Xcode/Tests/SwifterTestsHttpParser.swift @@ -175,7 +175,7 @@ class SwifterTestsHttpParser: XCTestCase { XCTAssertEqual(resp?.headers["header2"], "2", "Parser should extract multiple headers from the request.") resp = try? parser.readHttpRequest(TestSocket("GET /some/path?subscript_query[]=1&subscript_query[]=2 HTTP/1.0\nContent-Length: 10\n\n1234567890")) - let queryPairs = resp?.queryParams ?? [] + var queryPairs = resp?.queryParams ?? [] XCTAssertEqual(queryPairs.count, 2) XCTAssertEqual(queryPairs.first?.0, "subscript_query[]") XCTAssertEqual(queryPairs.first?.1, "1") @@ -185,5 +185,19 @@ class SwifterTestsHttpParser: XCTestCase { XCTAssertEqual(resp?.path, "/some/path", "Parser should extract HTTP path value from the status line.") XCTAssertEqual(resp?.headers["content-length"], "10", "Parser should extract Content-Length header value.") + resp = try? parser.readHttpRequest(TestSocket("GET /path[]/param?a[]=1&a[]=2&b=%20 HTTP/1.0\r\nContent-Length: 0\r\n\r\n")) + queryPairs = resp?.queryParams ?? [] + + XCTAssertEqual(resp?.path, "/path[]/param") + if queryPairs.count == 3 { + XCTAssertEqual(queryPairs[0].0, "a[]") + XCTAssertEqual(queryPairs[0].1, "1") + XCTAssertEqual(queryPairs[1].0, "a[]") + XCTAssertEqual(queryPairs[1].1, "2") + XCTAssertEqual(queryPairs[2].0, "b") + XCTAssertEqual(queryPairs[2].1, " ") + } else { + XCTFail("queryPairs count should be 3") + } } }