Skip to content

Commit 3ee0014

Browse files
committed
buildRequest function to avoid duplication while preparing rest requests.
1 parent 9d6fd3f commit 3ee0014

9 files changed

Lines changed: 162 additions & 128 deletions

File tree

Source/ARTAuth.m

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -493,21 +493,19 @@ - (void)handleAuthUrlResponse:(NSHTTPURLResponse *)response
493493
- (NSObject<ARTCancellable> *)executeTokenRequest:(ARTTokenRequest *)tokenRequest
494494
callback:(ARTTokenDetailsCallback)callback {
495495
id<ARTEncoder> encoder = _rest.defaultEncoder;
496-
497-
NSURL *requestUrl = [NSURL URLWithString:[NSString stringWithFormat:@"/keys/%@/requestToken?format=%@", tokenRequest.keyName, [encoder formatAsString]]
498-
relativeToURL:_rest.baseUrl];
499-
500-
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestUrl];
501-
request.HTTPMethod = @"POST";
502-
503496
NSError *encodeError = nil;
504-
request.HTTPBody = [encoder encodeTokenRequest:tokenRequest error:&encodeError];
497+
NSData *bodyData = [encoder encodeTokenRequest:tokenRequest error:&encodeError];
505498
if (encodeError) {
506499
callback(nil, encodeError);
507500
return nil;
508501
}
509-
[request setValue:[encoder mimeType] forHTTPHeaderField:@"Accept"];
510-
[request setValue:[encoder mimeType] forHTTPHeaderField:@"Content-Type"];
502+
503+
NSMutableURLRequest *request = [_rest buildRequest:@"POST"
504+
path:[NSString stringWithFormat:@"/keys/%@/requestToken", tokenRequest.keyName]
505+
baseUrl:nil
506+
params:@{ @"format": encoder.formatAsString }
507+
body:bodyData
508+
headers:nil];
511509

512510
return [_rest executeAblyRequest:request withAuthOption:ARTAuthenticationOff wrapperSDKAgents:nil completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
513511
if (error) {

Source/ARTDataQuery.m

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ - (NSMutableArray *)asQueryItems:(NSError *_Nullable*)error {
3838
return items;
3939
}
4040

41+
- (NSStringDictionary *)asQueryParams {
42+
NSMutableDictionary *items = [NSMutableDictionary dictionary];
43+
44+
if (self.start) {
45+
items[@"start"] = [NSString stringWithFormat:@"%llu", dateToMilliseconds(self.start)];
46+
}
47+
if (self.end) {
48+
items[@"end"] = [NSString stringWithFormat:@"%llu", dateToMilliseconds(self.end)];
49+
}
50+
51+
items[@"limit"] = [NSString stringWithFormat:@"%hu", self.limit];
52+
items[@"direction"] = queryDirectionToString(self.direction);
53+
54+
return items;
55+
}
56+
4157
@end
4258

4359
@implementation ARTRealtimeHistoryQuery

Source/ARTNSString+ARTUtil.m

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,18 @@ - (BOOL)isNotEmptyString {
1717
return ![self isEmptyString];
1818
}
1919

20+
- (NSString *)encodePathSegment {
21+
// Source: https://datatracker.ietf.org/doc/html/rfc3986#section-3.3
22+
// i.e. segment = unreserved / pct-encoded / sub-delims / ":" / "@", where
23+
// unreserved = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~
24+
// pct-encoded = %XX
25+
// sub-delims = !$&'()*+,;=
26+
NSCharacterSet *allowedSet = [NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&'()*+,;=:@"];
27+
NSString *escaped = [self stringByAddingPercentEncodingWithAllowedCharacters:allowedSet];
28+
if (!escaped) {
29+
[NSException raise:NSInternalInconsistencyException format:@"String '%@' can't be percent encoded.", self];
30+
}
31+
return escaped;
32+
}
33+
2034
@end

Source/ARTRest.m

Lines changed: 70 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,9 @@ - (NSString *)agentIdentifierWithWrapperSDKAgents:(nullable NSDictionary<NSStrin
495495
if (![mutableRequest valueForHTTPHeaderField:@"X-Ably-Version"]) {
496496
[mutableRequest setValue:[ARTDefault apiVersion] forHTTPHeaderField:@"X-Ably-Version"];
497497
}
498+
498499
[mutableRequest setValue:[self agentIdentifierWithWrapperSDKAgents:wrapperSDKAgents] forHTTPHeaderField:@"Ably-Agent"];
500+
499501
if (_options.clientId && !self.auth.isTokenAuth) {
500502
[mutableRequest setValue:encodeBase64(_options.clientId) forHTTPHeaderField:@"X-Ably-ClientId"];
501503
}
@@ -607,11 +609,12 @@ - (void)timeWithWrapperSDKAgents:(nullable NSStringDictionary *)wrapperSDKAgents
607609

608610
- (NSObject<ARTCancellable> *)_timeWithWrapperSDKAgents:(nullable NSStringDictionary *)wrapperSDKAgents
609611
completion:(ARTDateTimeCallback)callback {
610-
NSURL *requestUrl = [NSURL URLWithString:@"/time" relativeToURL:self.baseUrl];
611-
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestUrl];
612-
request.HTTPMethod = @"GET";
613-
NSString *accept = [[_encoders.allValues valueForKeyPath:@"mimeType"] componentsJoinedByString:@","];
614-
[request setValue:accept forHTTPHeaderField:@"Accept"];
612+
NSMutableURLRequest *request = [self buildRequest:@"GET"
613+
path:@"/time"
614+
baseUrl:self.baseUrl
615+
params:nil
616+
body:nil
617+
headers:nil];
615618

616619
return [self executeAblyRequest:request withAuthOption:ARTAuthenticationOff wrapperSDKAgents:wrapperSDKAgents completion:^(NSHTTPURLResponse *response, NSData *data, NSError *error) {
617620
if (error) {
@@ -631,67 +634,41 @@ - (void)timeWithWrapperSDKAgents:(nullable NSStringDictionary *)wrapperSDKAgents
631634
}];
632635
}
633636

634-
- (BOOL)request:(NSString *)method
635-
path:(NSString *)path
636-
params:(nullable NSStringDictionary *)params
637-
body:(nullable id)body
638-
headers:(nullable NSStringDictionary *)headers
639-
wrapperSDKAgents:(nullable NSStringDictionary *)wrapperSDKAgents
640-
callback:(ARTHTTPPaginatedCallback)callback
641-
error:(NSError **)errorPtr {
642-
643-
if (callback) {
644-
void (^userCallback)(ARTHTTPPaginatedResponse *, ARTErrorInfo *) = callback;
645-
callback = ^(ARTHTTPPaginatedResponse *r, ARTErrorInfo *e) {
646-
art_dispatch_async(self->_userQueue, ^{
647-
userCallback(r, e);
648-
});
649-
};
637+
- (NSMutableURLRequest *)buildRequest:(NSString *)method
638+
path:(NSString *)path
639+
baseUrl:(nullable NSURL *)baseUrl
640+
params:(nullable NSStringDictionary *)params
641+
body:(nullable id)body
642+
headers:(nullable NSStringDictionary *)headers {
643+
if (![@[@"get", @"post", @"patch", @"put", @"delete"] containsObject:method.lowercaseString]) {
644+
@throw [NSException exceptionWithName:NSInternalInconsistencyException
645+
reason:[NSString stringWithFormat:@"Method %@ isn't valid.", method]
646+
userInfo:nil];
650647
}
651648

652-
if (![[method lowercaseString] isEqualToString:@"get"] &&
653-
![[method lowercaseString] isEqualToString:@"post"] &&
654-
![[method lowercaseString] isEqualToString:@"patch"] &&
655-
![[method lowercaseString] isEqualToString:@"put"] &&
656-
![[method lowercaseString] isEqualToString:@"delete"]) {
657-
if (errorPtr) {
658-
*errorPtr = [NSError errorWithDomain:ARTAblyErrorDomain
659-
code:ARTCustomRequestErrorInvalidMethod
660-
userInfo:@{NSLocalizedDescriptionKey:@"Method isn't valid."}];
661-
}
662-
return NO;
649+
if (body && ![body isKindOfClass:[NSDictionary class]] && ![body isKindOfClass:[NSArray class]]) {
650+
@throw [NSException exceptionWithName:NSInternalInconsistencyException
651+
reason:@"Body should be a Dictionary or an Array."
652+
userInfo:nil];
663653
}
664654

665-
if (body &&
666-
![body isKindOfClass:[NSDictionary class]] &&
667-
![body isKindOfClass:[NSArray class]]) {
668-
if (errorPtr) {
669-
*errorPtr = [NSError errorWithDomain:ARTAblyErrorDomain
670-
code:ARTCustomRequestErrorInvalidBody
671-
userInfo:@{NSLocalizedDescriptionKey:@"Body should be a Dictionary or an Array."}];
672-
}
673-
return NO;
655+
if ([[path stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet] isEqualToString:@""]) {
656+
@throw [NSException exceptionWithName:NSInternalInconsistencyException
657+
reason:@"Path cannot be empty."
658+
userInfo:nil];
674659
}
675-
676-
if ([[path stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] isEqualToString:@""]) {
677-
if (errorPtr) {
678-
*errorPtr = [NSError errorWithDomain:ARTAblyErrorDomain
679-
code:ARTCustomRequestErrorInvalidPath
680-
userInfo:@{NSLocalizedDescriptionKey:@"Path cannot be empty."}];
681-
}
682-
return NO;
660+
661+
if (baseUrl == nil) {
662+
baseUrl = self.baseUrl;
683663
}
684664

685-
NSURL *url = [NSURL URLWithString:path relativeToURL:self.baseUrl];
665+
NSURL *url = [NSURL URLWithString:path relativeToURL:baseUrl];
686666
// Should not happen in iOS 17 and above. See explanation in the "Important" section here:
687667
// https://developer.apple.com/documentation/foundation/nsurl/1572047-urlwithstring
688668
if (!url) {
689-
if (errorPtr) {
690-
*errorPtr = [NSError errorWithDomain:ARTAblyErrorDomain
691-
code:ARTCustomRequestErrorInvalidPath
692-
userInfo:@{NSLocalizedDescriptionKey:@"Path isn't valid for an URL."}];
693-
}
694-
return NO;
669+
@throw [NSException exceptionWithName:NSInternalInconsistencyException
670+
reason:@"Path isn't valid for an URL."
671+
userInfo:nil];
695672
}
696673

697674
NSURLComponents *components = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:YES];
@@ -705,7 +682,7 @@ - (BOOL)request:(NSString *)method
705682
components.queryItems = queryItems;
706683

707684
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[components URL]];
708-
request.HTTPMethod = method;
685+
request.HTTPMethod = method.uppercaseString;
709686

710687
[headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
711688
[request addValue:value forHTTPHeaderField:key];
@@ -717,13 +694,42 @@ - (BOOL)request:(NSString *)method
717694

718695
request.HTTPBody = bodyData;
719696
[request setValue:[self.defaultEncoder mimeType] forHTTPHeaderField:@"Content-Type"];
720-
if ([[method lowercaseString] isEqualToString:@"post"]) {
697+
if ([@[@"post", @"patch", @"put"] containsObject:method.lowercaseString]) {
721698
[request setValue:[NSString stringWithFormat:@"%d", (unsigned int)bodyData.length] forHTTPHeaderField:@"Content-Length"];
722699
}
723700
}
724701

702+
[request setTimeoutInterval:_options.httpRequestTimeout];
725703
[request setAcceptHeader:self.defaultEncoder encoders:self.encoders];
726704

705+
return request;
706+
}
707+
708+
- (BOOL)request:(NSString *)method
709+
path:(NSString *)path
710+
params:(nullable NSStringDictionary *)params
711+
body:(nullable id)body
712+
headers:(nullable NSStringDictionary *)headers
713+
wrapperSDKAgents:(nullable NSStringDictionary *)wrapperSDKAgents
714+
callback:(ARTHTTPPaginatedCallback)callback
715+
error:(NSError **)errorPtr {
716+
717+
if (callback) {
718+
void (^userCallback)(ARTHTTPPaginatedResponse *, ARTErrorInfo *) = callback;
719+
callback = ^(ARTHTTPPaginatedResponse *r, ARTErrorInfo *e) {
720+
art_dispatch_async(self->_userQueue, ^{
721+
userCallback(r, e);
722+
});
723+
};
724+
}
725+
726+
NSMutableURLRequest *request = [self buildRequest:method
727+
path:path
728+
baseUrl:self.baseUrl
729+
params:params
730+
body:body
731+
headers:headers];
732+
727733
ARTLogDebug(self.logger, @"request %@ %@", method, path);
728734
art_dispatch_async(_queue, ^{
729735
[ARTHTTPPaginatedResponse executePaginated:self withRequest:request wrapperSDKAgents:wrapperSDKAgents logger:self.logger callback:callback];
@@ -778,16 +784,12 @@ - (BOOL)stats:(ARTStatsQuery *)query wrapperSDKAgents:(nullable NSStringDictiona
778784
return NO;
779785
}
780786

781-
NSURLComponents *requestUrl = [NSURLComponents componentsWithString:@"/stats"];
782-
NSError *error = nil;
783-
requestUrl.queryItems = [query asQueryItems:&error];
784-
if (error) {
785-
if (errorPtr) {
786-
*errorPtr = error;
787-
}
788-
return NO;
789-
}
790-
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[requestUrl URLRelativeToURL:self.baseUrl]];
787+
NSMutableURLRequest *request = [self buildRequest:@"GET"
788+
path:@"/stats"
789+
baseUrl:self.baseUrl
790+
params:query.asQueryParams
791+
body:nil
792+
headers:nil];
791793

792794
// Override X-Ably-Version header to use protocol version 2 for stats
793795
[request setValue:@"2" forHTTPHeaderField:@"X-Ably-Version"];

0 commit comments

Comments
 (0)