Skip to content
This repository was archived by the owner on Jul 22, 2020. It is now read-only.

Commit e05d2ab

Browse files
authored
Encodes special characters in query params with percent encoding. (#35)
* Encodes special characters in query params with percent encoding. * Abstracted out encode url into its own function and only creates the character set once. * Intiantiate a mutable copy of the characterSet then store an immutable set. Per https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/CharacterSets.html * updating return logic for encodeUrlParam * adds unit tests for the queryParamRewrite * code review changes
1 parent 0639640 commit e05d2ab

File tree

2 files changed

+68
-3
lines changed

2 files changed

+68
-3
lines changed

Iterable-iOS-SDK/IterableAPI.m

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ @implementation IterableAPI {
4040
// the API endpoint
4141
NSString * const endpoint = @"https://api.iterable.com/api/";
4242

43+
NSCharacterSet* encodedCharacterSet = nil;
4344

4445
//////////////////////////
4546
/// @name Internal methods
@@ -72,6 +73,13 @@ + (NSString *)pushServicePlatformToString:(PushServicePlatform)pushServicePlatfo
7273
return result;
7374
}
7475

76+
- (NSCharacterSet *)getEncodedSubset
77+
{
78+
NSMutableCharacterSet* workingSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
79+
[workingSet removeCharactersInString:@"+"];
80+
return [workingSet copy];
81+
}
82+
7583
/**
7684
@method
7785
@@ -99,19 +107,36 @@ - (NSURL *)getUrlForAction:(NSString *)action
99107
- (NSURL *)getUrlForGetAction:(NSString *)action withArgs:(NSDictionary *)args
100108
{
101109
NSString *urlCombined = [NSString stringWithFormat:@"%@%@?api_key=%@", endpoint, action, self.apiKey];
102-
//updated this to take in a dictionary are parse values
103-
104110

105111
for (NSString* paramKey in args) {
106112
NSString* paramValue = args[paramKey];
107113

108-
NSString *params = [NSString stringWithFormat:@"&%@=%@", paramKey, paramValue];
114+
NSString *params = [NSString stringWithFormat:@"&%@=%@", paramKey, [self encodeURLParam:paramValue]];
109115
urlCombined = [urlCombined stringByAppendingString:params];
110116
}
111117

112118
return [NSURL URLWithString:urlCombined];
113119
}
114120

121+
/**
122+
@method
123+
124+
@abstract Percent encodes the url query parameters
125+
126+
@param paramValue The value to encode
127+
128+
@return an `NSString` containing the encoded value
129+
*/
130+
- (NSString *)encodeURLParam:(NSString *)paramValue
131+
{
132+
if ([paramValue isKindOfClass:[NSString class]])
133+
{
134+
return [paramValue stringByAddingPercentEncodingWithAllowedCharacters:encodedCharacterSet];
135+
} else {
136+
return paramValue;
137+
}
138+
}
139+
115140
/**
116141
@method
117142
@@ -329,6 +354,8 @@ - (instancetype)createSession:(NSDictionary *)launchOptions useCustomLaunchOptio
329354
// if it gets instantiated again that's fine; we don't need to reconfigure the session, just keep using the old singleton
330355
[self createUrlSession];
331356

357+
encodedCharacterSet = [self getEncodedSubset];
358+
332359
// Automatically try to track a pushOpen
333360
if (launchOptions) {
334361
if (useCustomLaunchOptions) {

Iterable-iOS-SDKTests/IterableAPITests.m

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ @interface IterableAPI (Test)
1717
+ (NSString *)pushServicePlatformToString:(PushServicePlatform)pushServicePlatform;
1818
+ (NSString *)dictToJson:(NSDictionary *)dict;
1919
+ (NSString *)userInterfaceIdiomEnumToString:(UIUserInterfaceIdiom)idiom;
20+
21+
- (NSString *)encodeURLParam:(NSString *)paramValue;
2022
@end
2123

2224
@interface IterableAPITests : XCTestCase
@@ -184,4 +186,40 @@ - (void)testUniversalDeepLinkHttps {
184186
}];
185187
}
186188

189+
- (void)testURLQueryParamRewrite {
190+
[IterableAPI sharedInstanceWithApiKey:@"" andEmail:@"" launchOptions:nil];
191+
192+
NSCharacterSet* set = [NSCharacterSet URLQueryAllowedCharacterSet];
193+
194+
NSMutableString* strSet =[NSMutableString string];
195+
for (int plane = 0; plane <= 16; plane++) {
196+
if ([set hasMemberInPlane:plane]) {
197+
UTF32Char c;
198+
for (c = plane << 16; c < (plane+1) << 16; c++) {
199+
if ([set longCharacterIsMember:c]) {
200+
UTF32Char c1 = OSSwapHostToLittleInt32(c);
201+
NSString *s = [[NSString alloc] initWithBytes:&c1 length:4 encoding:NSUTF32LittleEndianStringEncoding];
202+
[strSet appendString:s];
203+
}
204+
}
205+
}
206+
}
207+
208+
//Test full set of possible URLQueryAllowedCharacterSet characters
209+
NSString* encodedSet = [[IterableAPI sharedInstance] encodeURLParam:strSet];
210+
XCTAssertNotEqual(encodedSet, strSet);
211+
XCTAssert([encodedSet isEqualToString:@"!$&'()*%2B,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"]);
212+
213+
NSString* encoded = [[IterableAPI sharedInstance] encodeURLParam:@"[email protected]"];
214+
XCTAssertNotEqual(encoded, @"[email protected]");
215+
XCTAssert([encoded isEqualToString:@"you%[email protected]"]);
216+
217+
NSString* emptySet = [[IterableAPI sharedInstance] encodeURLParam:@""];
218+
XCTAssertEqual(emptySet, @"");
219+
XCTAssert([emptySet isEqualToString:@""]);
220+
221+
NSString* nilSet = [[IterableAPI sharedInstance] encodeURLParam:nil];
222+
XCTAssertEqual(nilSet, nil);
223+
}
224+
187225
@end

0 commit comments

Comments
 (0)