@@ -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