[Issue #619] Sorting dictionary keys with caseInsensitiveCompare to ensure deterministic ordering of query string parameters, which may otherwise cause ambiguous representations of nested parameters
This commit is contained in:
parent
9cde4e4584
commit
5b32b45469
2 changed files with 10 additions and 3 deletions
|
|
@ -113,6 +113,8 @@ typedef enum {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The `AFHTTPClientParameterEncoding` value corresponding to how parameters are encoded into a request body. This is `AFFormURLParameterEncoding` by default.
|
The `AFHTTPClientParameterEncoding` value corresponding to how parameters are encoded into a request body. This is `AFFormURLParameterEncoding` by default.
|
||||||
|
|
||||||
|
@warning Some nested parameter structures, such as a keyed array of hashes containing inconsistent keys (i.e. `@{@"": @[@{@"a" : @(1)}, @{@"b" : @(2)}]}`), cannot be unambiguously represented in query strings. It is strongly recommended that an unambiguous encoding, such as `AFJSONParameterEncoding`, is used when posting complicated or nondeterministic parameter structures.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) AFHTTPClientParameterEncoding parameterEncoding;
|
@property (nonatomic, assign) AFHTTPClientParameterEncoding parameterEncoding;
|
||||||
|
|
||||||
|
|
@ -461,7 +463,7 @@ typedef enum {
|
||||||
}
|
}
|
||||||
|
|
||||||
`AFFormURLParameterEncoding`
|
`AFFormURLParameterEncoding`
|
||||||
Parameters are encoded into field/key pairs in the URL query string for `GET` `HEAD` and `DELETE` requests, and in the message body otherwise.
|
Parameters are encoded into field/key pairs in the URL query string for `GET` `HEAD` and `DELETE` requests, and in the message body otherwise. Dictionary keys are sorted with the `caseInsensitiveCompare:` selector of their description, in order to mitigate the possibility of ambiguous query strings being generated non-deterministically. See the warning for the `parameterEncoding` property for additional information.
|
||||||
|
|
||||||
`AFJSONParameterEncoding`
|
`AFJSONParameterEncoding`
|
||||||
Parameters are encoded into JSON in the message body.
|
Parameters are encoded into JSON in the message body.
|
||||||
|
|
|
||||||
|
|
@ -146,8 +146,13 @@ NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
|
||||||
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
|
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
|
||||||
|
|
||||||
if([value isKindOfClass:[NSDictionary class]]) {
|
if([value isKindOfClass:[NSDictionary class]]) {
|
||||||
[value enumerateKeysAndObjectsUsingBlock:^(id nestedKey, id nestedValue, BOOL *stop) {
|
// Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries
|
||||||
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
|
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(caseInsensitiveCompare:)];
|
||||||
|
[[[value allKeys] sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]] enumerateObjectsUsingBlock:^(id nestedKey, NSUInteger idx, BOOL *stop) {
|
||||||
|
id nestedValue = [value objectForKey:nestedKey];
|
||||||
|
if (nestedValue) {
|
||||||
|
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
|
||||||
|
}
|
||||||
}];
|
}];
|
||||||
} else if([value isKindOfClass:[NSArray class]]) {
|
} else if([value isKindOfClass:[NSArray class]]) {
|
||||||
[value enumerateObjectsUsingBlock:^(id nestedValue, NSUInteger idx, BOOL *stop) {
|
[value enumerateObjectsUsingBlock:^(id nestedValue, NSUInteger idx, BOOL *stop) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue