Skip to content

Commit

Permalink
[Issue Alamofire#206] Fixed percent encoding issue for long chinese s…
Browse files Browse the repository at this point in the history
…trings.
  • Loading branch information
cnoon committed Sep 20, 2015
1 parent 71a26d6 commit 4f6b295
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 3 deletions.
6 changes: 6 additions & 0 deletions Alamofire.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
4C341BBA1B1A865A00C1B34D /* CacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C341BB91B1A865A00C1B34D /* CacheTests.swift */; };
4C341BBB1B1A865A00C1B34D /* CacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C341BB91B1A865A00C1B34D /* CacheTests.swift */; };
4C3C53B21BAC5D40004F7F68 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8111E3319A95C8B0040E7D1 /* Alamofire.framework */; settings = {ASSET_TAGS = (); }; };
4C4CBE7B1BAF700C0024D659 /* String+AlamofireTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4CBE7A1BAF700C0024D659 /* String+AlamofireTests.swift */; settings = {ASSET_TAGS = (); }; };
4C4CBE7C1BAF700C0024D659 /* String+AlamofireTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4CBE7A1BAF700C0024D659 /* String+AlamofireTests.swift */; settings = {ASSET_TAGS = (); }; };
4C7C8D221B9D0D9000948136 /* NSURLSessionConfiguration+AlamofireTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7C8D211B9D0D9000948136 /* NSURLSessionConfiguration+AlamofireTests.swift */; settings = {ASSET_TAGS = (); }; };
4C7C8D231B9D0D9000948136 /* NSURLSessionConfiguration+AlamofireTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7C8D211B9D0D9000948136 /* NSURLSessionConfiguration+AlamofireTests.swift */; settings = {ASSET_TAGS = (); }; };
4C811F8D1B51856D00E0F59A /* ServerTrustPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C811F8C1B51856D00E0F59A /* ServerTrustPolicy.swift */; };
Expand Down Expand Up @@ -149,6 +151,7 @@
4C33A1241B5207DB00873DFF /* unicorn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unicorn.png; sourceTree = "<group>"; };
4C33A1421B52089C00873DFF /* ServerTrustPolicyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServerTrustPolicyTests.swift; sourceTree = "<group>"; };
4C341BB91B1A865A00C1B34D /* CacheTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CacheTests.swift; sourceTree = "<group>"; };
4C4CBE7A1BAF700C0024D659 /* String+AlamofireTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+AlamofireTests.swift"; sourceTree = "<group>"; };
4C7C8D211B9D0D9000948136 /* NSURLSessionConfiguration+AlamofireTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSURLSessionConfiguration+AlamofireTests.swift"; sourceTree = "<group>"; };
4C811F8C1B51856D00E0F59A /* ServerTrustPolicy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServerTrustPolicy.swift; sourceTree = "<group>"; };
4C812C3A1B535F220017E0BF /* alamofire-root-ca.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = "alamofire-root-ca.cer"; path = "alamofire.org/alamofire-root-ca.cer"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -348,6 +351,7 @@
isa = PBXGroup;
children = (
4C7C8D211B9D0D9000948136 /* NSURLSessionConfiguration+AlamofireTests.swift */,
4C4CBE7A1BAF700C0024D659 /* String+AlamofireTests.swift */,
);
name = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -765,6 +769,7 @@
4C3238E71B3604DB00FE04AE /* MultipartFormDataTests.swift in Sources */,
4C33A1431B52089C00873DFF /* ServerTrustPolicyTests.swift in Sources */,
4C341BBA1B1A865A00C1B34D /* CacheTests.swift in Sources */,
4C4CBE7B1BAF700C0024D659 /* String+AlamofireTests.swift in Sources */,
4CA028C51B7466C500C84163 /* ResultTests.swift in Sources */,
4CCFA79A1B2BE71600B6F460 /* URLProtocolTests.swift in Sources */,
F86AEFE71AE6A312007D9C76 /* TLSEvaluationTests.swift in Sources */,
Expand All @@ -789,6 +794,7 @@
4C3238E81B3604DB00FE04AE /* MultipartFormDataTests.swift in Sources */,
4C33A1441B52089C00873DFF /* ServerTrustPolicyTests.swift in Sources */,
4C341BBB1B1A865A00C1B34D /* CacheTests.swift in Sources */,
4C4CBE7C1BAF700C0024D659 /* String+AlamofireTests.swift in Sources */,
4CA028C61B7466C500C84163 /* ResultTests.swift in Sources */,
4CCFA79B1B2BE71600B6F460 /* URLProtocolTests.swift in Sources */,
F829C6BE1A7A950600A2CD59 /* ParameterEncodingTests.swift in Sources */,
Expand Down
30 changes: 29 additions & 1 deletion Source/ParameterEncoding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,34 @@ public enum ParameterEncoding {
let allowedCharacterSet = NSCharacterSet.URLQueryAllowedCharacterSet().mutableCopy() as! NSMutableCharacterSet
allowedCharacterSet.removeCharactersInString(generalDelimitersToEncode + subDelimitersToEncode)

return string.stringByAddingPercentEncodingWithAllowedCharacters(allowedCharacterSet) ?? ""
//==========================================================================================================
//
// Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few
// hundred Chinense characters causes various malloc error crashes. To avoid this issue until iOS 8 is no
// longer supported, batching MUST be used for encoding. This introduces roughly a 20% overhead. For more
// info, please refer to:
//
// - https://github.com/Alamofire/Alamofire/issues/206
//
//==========================================================================================================

let batchSize = 50
var index = string.startIndex

var escaped = ""

while index != string.endIndex {
let startIndex = index
let endIndex = index.advancedBy(batchSize, limit: string.endIndex)
let range = Range(start: startIndex, end: endIndex)

let substring = string.substringWithRange(range)

escaped += substring.stringByAddingPercentEncodingWithAllowedCharacters(allowedCharacterSet) ?? substring

index = endIndex
}

return escaped
}
}
19 changes: 17 additions & 2 deletions Tests/ParameterEncodingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ class ParameterEncodingTestCase: BaseTestCase {
// MARK: -

class URLParameterEncodingTestCase: ParameterEncodingTestCase {
// MARK: Properties

let encoding: ParameterEncoding = .URL

// MARK: Tests - Parameter Types
Expand Down Expand Up @@ -350,6 +348,23 @@ class URLParameterEncodingTestCase: ParameterEncodingTestCase {
XCTAssertEqual(URLRequest.URL?.query ?? "", "hd=%5B1%5D&%2Bfoo%2B=%2Bbar%2B", "query is incorrect")
}

func testURLParameterEncodeStringWithThousandsOfChineseCharacters() {
// Given
let repeatedCount = 2_000
let URL = NSURL(string: "https://example.com/movies")!
let parameters = ["chinese": String(count: repeatedCount, repeatedString: "一二三四五六七八九十")]

// When
let (URLRequest, _) = encoding.encode(NSURLRequest(URL: URL), parameters: parameters)

// Then
var expected = "chinese="
for _ in 0..<repeatedCount {
expected += "%E4%B8%80%E4%BA%8C%E4%B8%89%E5%9B%9B%E4%BA%94%E5%85%AD%E4%B8%83%E5%85%AB%E4%B9%9D%E5%8D%81"
}
XCTAssertEqual(URLRequest.URL?.query ?? "", expected, "query is incorrect")
}

// MARK: Tests - Varying HTTP Methods

func testThatURLParameterEncodingEncodesGETParametersInURL() {
Expand Down
31 changes: 31 additions & 0 deletions Tests/String+AlamofireTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// NSURLSessionConfiguration+AlamofireTests.swift
//
// Copyright (c) 2014–2015 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import Foundation

extension String {
init(count: Int, repeatedString: String) {
var value = ""
for _ in 0..<count { value += repeatedString }
self = value
}
}

0 comments on commit 4f6b295

Please sign in to comment.