Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extending ErrorInfo with href and requestId #1147

Merged
merged 15 commits into from
Jul 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 32 additions & 16 deletions Ably.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions Source/ARTNSError+ARTUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// NSError+ARTUtils.h
// Ably
//
// Created by Łukasz Szyszkowski on 05/07/2021.
// Copyright © 2021 Ably. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSError (ARTUtils)

@property (nullable, readonly) NSString *requestId;

+ (nullable NSError *)copyFromError:(NSError *)error withRequestId:(nullable NSString *)requestId;

@end

NS_ASSUME_NONNULL_END
29 changes: 29 additions & 0 deletions Source/ARTNSError+ARTUtils.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// NSError+ARTUtils.m
// Ably
//
// Created by Łukasz Szyszkowski on 05/07/2021.
// Copyright © 2021 Ably. All rights reserved.
//

#import "ARTNSError+ARTUtils.h"
#import "ARTStatus.h"

@implementation NSError (ARTUtils)

+ (nullable NSError *)copyFromError:(NSError *)error withRequestId:(nullable NSString *)requestId {
if (error == nil) {
return nil;
}

maratal marked this conversation as resolved.
Show resolved Hide resolved
NSMutableDictionary *mutableInfo = [NSMutableDictionary dictionaryWithDictionary:error.userInfo];
mutableInfo[ARTErrorInfoRequestIdKey] = requestId;

return [NSError errorWithDomain:error.domain code:error.code userInfo:mutableInfo];
}

- (NSString *)requestId {
return self.userInfo[ARTErrorInfoRequestIdKey];
}

@end
22 changes: 0 additions & 22 deletions Source/ARTNSMutableURLRequest+ARTUtil.m

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
//
// NSMutableURLRequest+ARTUtil.h
// NSMutableURLRequest+ARTUtils.h
// Ably
//
// Created by Łukasz Szyszkowski on 09/07/2021.
// Created by Łukasz Szyszkowski on 05/07/2021.
// Copyright © 2021 Ably. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSMutableURLRequest (ARTUtil)
@interface NSMutableURLRequest (ARTUtils)

/**
Note: this method is using URLComponents to deconstruct URL of this request then it replacing `host` with new one.
If for some reasons new URL constructed by URLComponents is `nil`, old URL is a valiid URL for this request.
*/
- (void)replaceHostWith:(NSString *)host;
- (void)appendQueryItem:(NSURLQueryItem *)item;

@end

Expand Down
38 changes: 38 additions & 0 deletions Source/ARTNSMutableURLRequest+ARTUtils.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// NSMutableURLRequest+ARTUtils.m
// Ably
//
// Created by Łukasz Szyszkowski on 05/07/2021.
// Copyright © 2021 Ably. All rights reserved.
//

#import "ARTNSMutableURLRequest+ARTUtils.h"

@implementation NSMutableURLRequest (ARTUtils)

- (void)appendQueryItem:(NSURLQueryItem *)item {
NSURLComponents *components = [NSURLComponents componentsWithURL:self.URL resolvingAgainstBaseURL:YES];
maratal marked this conversation as resolved.
Show resolved Hide resolved
if(components == nil) {
return;
}

NSMutableArray<NSURLQueryItem *> *mutableQueryItems = [NSMutableArray arrayWithArray:components.queryItems];
[mutableQueryItems addObject:item];
components.queryItems = mutableQueryItems;

NSURL *modifiedURL = components.URL;
if (modifiedURL != nil) {
self.URL = modifiedURL;
}
}

- (void)replaceHostWith:(NSString *)host {
NSURLComponents *components = [NSURLComponents componentsWithURL:self.URL resolvingAgainstBaseURL:YES];
components.host = host;

if(components != nil) {
self.URL = components.URL;
}
}

@end
6 changes: 4 additions & 2 deletions Source/ARTRest+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ NS_ASSUME_NONNULL_BEGIN
/// ARTRest private methods that are used internally and for internal testing
@interface ARTRestInternal : NSObject <ARTRestProtocol, ARTHTTPAuthenticatedExecutor>

typedef void (^CompletionBlock)(NSHTTPURLResponse * _Nullable, NSData * _Nullable, NSError * _Nullable);

maratal marked this conversation as resolved.
Show resolved Hide resolved
@property (nonatomic, strong, readonly) ARTRestChannelsInternal *channels;
@property (nonatomic, strong, readonly) ARTAuthInternal *auth;
@property (nonatomic, strong, readonly) ARTPushInternal *push;
Expand Down Expand Up @@ -59,11 +61,11 @@ NS_ASSUME_NONNULL_BEGIN

// MARK: ARTHTTPExecutor

- (nullable NSObject<ARTCancellable> *)executeRequest:(NSURLRequest *)request completion:(nullable void (^)(NSHTTPURLResponse *_Nullable, NSData *_Nullable, NSError *_Nullable))callback;
- (nullable NSObject<ARTCancellable> *)executeRequest:(NSURLRequest *)request completion:(nullable CompletionBlock)callback;

// MARK: Internal

- (nullable NSObject<ARTCancellable> *)executeRequest:(NSMutableURLRequest *)request withAuthOption:(ARTAuthentication)authOption completion:(void (^)(NSHTTPURLResponse *_Nullable, NSData * _Nullable, NSError * _Nullable))callback;
- (nullable NSObject<ARTCancellable> *)executeRequest:(NSMutableURLRequest *)request withAuthOption:(ARTAuthentication)authOption completion:(CompletionBlock)callback;

- (nullable NSObject<ARTCancellable> *)internetIsUp:(void (^)(BOOL isUp))cb;

Expand Down
50 changes: 39 additions & 11 deletions Source/ARTRest.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@
#import "ARTLocalDeviceStorage.h"
#import "ARTNSMutableRequest+ARTRest.h"
#import "ARTHTTPPaginatedResponse+Private.h"
#import "ARTNSError+ARTUtils.h"
#import "ARTNSMutableURLRequest+ARTUtils.h"
#import "ARTNSURL+ARTUtils.h"
#import "ARTNSMutableURLRequest+ARTUtil.h"
#import "ARTTime.h"

@implementation ARTRest {
Expand Down Expand Up @@ -224,7 +225,7 @@ - (NSString *)description {
return [NSString stringWithFormat:@"%@ - \n\t %@;", [super description], info];
}

- (NSObject<ARTCancellable> *)executeRequest:(NSMutableURLRequest *)request withAuthOption:(ARTAuthentication)authOption completion:(void (^)(NSHTTPURLResponse *_Nullable, NSData *_Nullable, NSError *_Nullable))callback {
- (NSObject<ARTCancellable> *)executeRequest:(NSMutableURLRequest *)request withAuthOption:(ARTAuthentication)authOption completion:(CompletionBlock)callback {
request.URL = [NSURL URLWithString:request.URL.relativeString relativeToURL:self.baseUrl];

switch (authOption) {
Expand Down Expand Up @@ -285,15 +286,22 @@ - (NSString *)description {
return task;
}

- (NSObject<ARTCancellable> *)executeRequest:(NSURLRequest *)request completion:(void (^)(NSHTTPURLResponse *_Nullable, NSData *_Nullable, NSError *_Nullable))callback {
return [self executeRequest:request completion:callback fallbacks:nil retries:0];
- (NSObject<ARTCancellable> *)executeRequest:(NSURLRequest *)request completion:(CompletionBlock)callback {
return [self executeRequest:request completion:callback fallbacks:nil retries:0 originalRequestId:nil];
}

- (NSObject<ARTCancellable> *)executeRequest:(NSURLRequest *)request completion:(void (^)(NSHTTPURLResponse *_Nullable, NSData *_Nullable, NSError *_Nullable))callback fallbacks:(ARTFallback *)fallbacks retries:(NSUInteger)retries {
/**
originalRequestId is used only for fallback requests. It should never be used to execute request by yourself, it's passed from within below method.
*/
maratal marked this conversation as resolved.
Show resolved Hide resolved
- (NSObject<ARTCancellable> *)executeRequest:(NSURLRequest *)request
completion:(CompletionBlock)callback
fallbacks:(ARTFallback *)fallbacks
retries:(NSUInteger)retries
originalRequestId:(nullable NSString *)originalRequestId {

maratal marked this conversation as resolved.
Show resolved Hide resolved
[ARTTime timeSinceBoot];
NSString *requestId = nil;
__block ARTFallback *blockFallbacks = fallbacks;

if ([request isKindOfClass:[NSMutableURLRequest class]]) {
NSMutableURLRequest *mutableRequest = (NSMutableURLRequest *)request;
[mutableRequest setAcceptHeader:self.defaultEncoder encoders:self.encoders];
Expand All @@ -304,6 +312,17 @@ - (NSString *)description {
[mutableRequest setValue:encodeBase64(_options.clientId) forHTTPHeaderField:@"X-Ably-ClientId"];
}

if (_options.addRequestIds) {
if (fallbacks != nil) {
requestId = originalRequestId;
} else {
NSString *randomId = [NSUUID new].UUIDString;
requestId = [[randomId dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0];
}
maratal marked this conversation as resolved.
Show resolved Hide resolved

[mutableRequest appendQueryItem:[NSURLQueryItem queryItemWithName:@"request_id" value:requestId]];
}

// RSC15f - reset the successed fallback host on fallbackRetryTimeout expiration
// change URLRequest host from `fallback host` to `default host`
//
Expand Down Expand Up @@ -335,7 +354,7 @@ - (NSString *)description {
if (!validContentType) {
NSString *plain = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// Construct artificial error
error = [ARTErrorInfo createWithCode:response.statusCode * 100 status:response.statusCode message:[plain art_shortString]];
error = [ARTErrorInfo createWithCode:response.statusCode * 100 status:response.statusCode message:[plain art_shortString] requestId:requestId];
data = nil; // Discard data; format is unreliable.
[self.logger error:@"Request %@ failed with %@", request, error];
}
Expand All @@ -362,7 +381,11 @@ - (NSString *)description {
}
if (!error) {
// Return error with HTTP StatusCode if ARTErrorStatusCode does not exist
error = [ARTErrorInfo createWithCode:response.statusCode*100 status:response.statusCode message:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]];
error = [ARTErrorInfo
createWithCode:response.statusCode*100
status:response.statusCode
message:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]
requestId:requestId];
}

} else {
Expand All @@ -386,15 +409,20 @@ - (NSString *)description {
NSMutableURLRequest *newRequest = [request copy];
[newRequest setValue:host forHTTPHeaderField:@"Host"];
newRequest.URL = [NSURL copyFromURL:request.URL withHost:host];
task = [self executeRequest:newRequest completion:callback fallbacks:blockFallbacks retries:retries + 1];
task = [self executeRequest:newRequest completion:callback fallbacks:blockFallbacks retries:retries + 1 originalRequestId:originalRequestId];

return;
}
}
}
if (callback) {
// Error object that indicates why the request failed
callback(response, data, error);
if ([error isKindOfClass:[ARTErrorInfo class]]) {
callback(response, data, error);
} else {
callback(response, data, [NSError copyFromError:error withRequestId:requestId]);
}

}
}];

Expand Down
Loading