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

Encoder: handle invalid types gracefully #592

Merged
merged 22 commits into from
Apr 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5153d2a
Test: JSON encoder using invalid types
ricardopereira Apr 11, 2017
d5bc0f5
Test: should handle and emit the invalid data error
ricardopereira Apr 11, 2017
a889cc4
Fix: handle and emit the invalid data encoder error
ricardopereira Apr 11, 2017
659fc60
Update existing tests
ricardopereira Apr 11, 2017
c4de4b9
Test: should decode data with malformed JSON
ricardopereira Apr 11, 2017
f4619aa
fixup! Fix: handle and emit the invalid data encoder error
ricardopereira Apr 11, 2017
4c29e26
Test: should decode data with malformed MsgPack
ricardopereira Apr 12, 2017
657f82c
Test: incoming invalid/non-encodeable payloads and messages
ricardopereira Apr 12, 2017
9423f23
Add error argument on every encode/decode method
ricardopereira Apr 12, 2017
aa9b4ce
Update tests
ricardopereira Apr 12, 2017
dbcf66a
fixup! Add error argument on every encode/decode method
ricardopereira Apr 12, 2017
29a7a59
TestProxyTransport: sendWithData needs to capture protocol messages
ricardopereira Apr 12, 2017
df0990c
Add missing authDetailsFromDictionary
ricardopereira Apr 12, 2017
6981ade
fixup! Add error argument on every encode/decode method
ricardopereira Apr 12, 2017
7288dce
Fix: invalid type cast
ricardopereira Apr 12, 2017
cab47d2
Fix: bad access crash
ricardopereira Apr 13, 2017
8c6e232
Fix test
ricardopereira Apr 13, 2017
09b7e8e
fixup! Fix: bad access crash
ricardopereira Apr 13, 2017
f3eb7ac
Fix: missing encoder fields
ricardopereira Apr 13, 2017
843b2de
If message error is empty then use the reason prop
ricardopereira Apr 13, 2017
72239d8
Keep the original error domain to give more context
ricardopereira Apr 13, 2017
05cc875
Transport: use only one way to send data
ricardopereira Apr 13, 2017
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
9 changes: 7 additions & 2 deletions Source/ARTAuth.m
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,13 @@ - (void)executeTokenRequest:(ARTTokenRequest *)tokenRequest callback:(void (^)(A

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestUrl];
request.HTTPMethod = @"POST";

request.HTTPBody = [encoder encodeTokenRequest:tokenRequest];

NSError *encodeError = nil;
request.HTTPBody = [encoder encodeTokenRequest:tokenRequest error:&encodeError];
if (encodeError) {
callback(nil, encodeError);
return;
}
[request setValue:[encoder mimeType] forHTTPHeaderField:@"Accept"];
[request setValue:[encoder mimeType] forHTTPHeaderField:@"Content-Type"];

Expand Down
4 changes: 2 additions & 2 deletions Source/ARTBaseMessage.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ - (id)decodeWithEncoder:(ARTDataEncoder*)encoder error:(NSError **)error {
ARTDataEncoderOutput *decoded = [encoder decode:self.data encoding:self.encoding];
if (decoded.errorInfo && error) {
*error = [NSError errorWithDomain:ARTAblyErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"decoding failed",
NSLocalizedFailureReasonErrorKey: decoded.errorInfo}];
NSLocalizedFailureReasonErrorKey: decoded.errorInfo.message}];
}
id ret = [self copy];
((ARTBaseMessage *)ret).data = decoded.data;
Expand All @@ -49,7 +49,7 @@ - (id)encodeWithEncoder:(ARTDataEncoder*)encoder error:(NSError **)error {
ARTDataEncoderOutput *encoded = [encoder encode:self.data];
if (encoded.errorInfo && error) {
*error = [NSError errorWithDomain:ARTAblyErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey: @"encoding failed",
NSLocalizedFailureReasonErrorKey: encoded.errorInfo}];
NSLocalizedFailureReasonErrorKey: encoded.errorInfo.message}];
}
id ret = [self copy];
((ARTBaseMessage *)ret).data = encoded.data;
Expand Down
1 change: 0 additions & 1 deletion Source/ARTChannel+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ ART_ASSUME_NONNULL_BEGIN
@property (nonatomic, strong, art_null_resettable) ARTChannelOptions *options;
@property (nonatomic, strong, readonly) ARTDataEncoder *dataEncoder;

- (ARTMessage *__art_nonnull)encodeMessageIfNeeded:(ARTMessage *__art_nonnull)message;
- (void)internalPostMessages:(id)data callback:(art_nullable void (^)(ARTErrorInfo *__art_nullable error))callback;

@end
Expand Down
45 changes: 32 additions & 13 deletions Source/ARTChannel.m
Original file line number Diff line number Diff line change
Expand Up @@ -45,38 +45,57 @@ - (void)publish:(NSString *)name data:(id)data {
}

- (void)publish:(art_nullable NSString *)name data:(art_nullable id)data callback:(art_nullable void (^)(ARTErrorInfo *__art_nullable error))callback {
[self internalPostMessages:[self encodeMessageIfNeeded:[[ARTMessage alloc] initWithName:name data:data]]
callback:callback];
NSError *error;
ARTMessage *messagesWithDataEncoded = [self encodeMessageIfNeeded:[[ARTMessage alloc] initWithName:name data:data] error:&error];
if (error) {
if (callback) callback([ARTErrorInfo createFromNSError:error]);
return;
}
[self internalPostMessages:messagesWithDataEncoded callback:callback];
}

- (void)publish:(NSString *)name data:(id)data clientId:(NSString *)clientId {
[self publish:name data:data clientId:clientId callback:nil];
}

- (void)publish:(NSString *)name data:(id)data clientId:(NSString *)clientId callback:(void (^)(ARTErrorInfo * _Nullable))callback {
[self internalPostMessages:[self encodeMessageIfNeeded:[[ARTMessage alloc] initWithName:name data:data clientId:clientId]]
callback:callback];
NSError *error;
ARTMessage *messagesWithDataEncoded = [self encodeMessageIfNeeded:[[ARTMessage alloc] initWithName:name data:data clientId:clientId] error:&error];
if (error) {
if (callback) callback([ARTErrorInfo createFromNSError:error]);
return;
}
[self internalPostMessages:messagesWithDataEncoded callback:callback];
}

- (void)publish:(NSArray<ARTMessage *> *)messages {
[self publish:messages callback:nil];
}

- (void)publish:(__GENERIC(NSArray, ARTMessage *) *)messages callback:(art_nullable void (^)(ARTErrorInfo *__art_nullable error))callback {
[self internalPostMessages:[messages artMap:^id(ARTMessage *message) {
return [self encodeMessageIfNeeded:message];
}] callback:callback];
NSError *error;
NSMutableArray<ARTMessage *> *messagesWithDataEncoded = [NSMutableArray new];
for (ARTMessage *message in messages) {
[messagesWithDataEncoded addObject:[self encodeMessageIfNeeded:message error:&error]];
}
if (error) {
callback([ARTErrorInfo createFromNSError:error]);
return;
}
[self internalPostMessages:messagesWithDataEncoded callback:callback];
}

- (ARTMessage *)encodeMessageIfNeeded:(ARTMessage *)message {
- (ARTMessage *)encodeMessageIfNeeded:(ARTMessage *)message error:(NSError **)error {
if (!self.dataEncoder) {
return message;
}
NSError *error = nil;
message = [message encodeWithEncoder:self.dataEncoder error:&error];
if (error != nil) {
[self.logger error:@"ARTChannel: error encoding data: %@", error];
[NSException raise:NSInvalidArgumentException format:@"ARTChannel: error encoding data: %@", error];
NSError *e = nil;
message = [message encodeWithEncoder:self.dataEncoder error:&e];
if (e) {
[self.logger error:@"ARTChannel: error encoding data: %@", e];
}
if (error) {
*error = e;
}
return message;
}
Expand Down
42 changes: 21 additions & 21 deletions Source/ARTEncoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,27 @@ ART_ASSUME_NONNULL_BEGIN
- (ARTEncoderFormat)format;
- (NSString *)formatAsString;

- (art_nullable NSData *)encodeTokenRequest:(ARTTokenRequest *)request;
- (art_nullable NSData *)encodeTokenDetails:(ARTTokenDetails *)tokenDetails;

- (art_nullable ARTTokenDetails *)decodeTokenDetails:(NSData *)data error:(NSError * __autoreleasing *)error;
- (art_nullable ARTTokenRequest *)decodeTokenRequest:(NSData *)data error:(NSError * __autoreleasing *)error;
- (art_nullable ARTMessage *)decodeMessage:(NSData *)data;
- (art_nullable NSArray *)decodeMessages:(NSData *)data;
- (art_nullable NSData *)encodeMessage:(ARTMessage *)message;
- (art_nullable NSData *)encodeMessages:(NSArray *)messages;

- (art_nullable ARTPresenceMessage *)decodePresenceMessage:(NSData *)data;
- (art_nullable NSArray *)decodePresenceMessages:(NSData *)data;
- (art_nullable NSData *)encodePresenceMessage:(ARTPresenceMessage *)message;
- (art_nullable NSData *)encodePresenceMessages:(NSArray *)messages;

- (art_nullable NSData *)encodeProtocolMessage:(ARTProtocolMessage *)message;
- (art_nullable ARTProtocolMessage *)decodeProtocolMessage:(NSData *)data;

- (art_nullable NSDate *)decodeTime:(NSData *)data;
- (art_nullable NSError *)decodeError:(NSData *)error;
- (art_nullable NSArray *)decodeStats:(NSData *)data;
- (nullable NSData *)encodeTokenRequest:(ARTTokenRequest *)request error:(NSError *_Nullable *_Nullable)error;
- (nullable NSData *)encodeTokenDetails:(ARTTokenDetails *)tokenDetails error:(NSError *_Nullable *_Nullable)error;

- (nullable ARTTokenDetails *)decodeTokenDetails:(NSData *)data error:(NSError *_Nullable *_Nullable)error;
- (nullable ARTTokenRequest *)decodeTokenRequest:(NSData *)data error:(NSError *_Nullable *_Nullable)error;
- (nullable ARTMessage *)decodeMessage:(NSData *)data error:(NSError *_Nullable *_Nullable)error;
- (nullable NSArray *)decodeMessages:(NSData *)data error:(NSError *_Nullable *_Nullable)error;
- (nullable NSData *)encodeMessage:(ARTMessage *)message error:(NSError *_Nullable *_Nullable)error;
- (nullable NSData *)encodeMessages:(NSArray *)messages error:(NSError *_Nullable *_Nullable)error;

- (nullable ARTPresenceMessage *)decodePresenceMessage:(NSData *)data error:(NSError *_Nullable *_Nullable)error;
- (nullable NSArray *)decodePresenceMessages:(NSData *)data error:(NSError *_Nullable *_Nullable)error;
- (nullable NSData *)encodePresenceMessage:(ARTPresenceMessage *)message error:(NSError *_Nullable *_Nullable)error;
- (nullable NSData *)encodePresenceMessages:(NSArray *)messages error:(NSError *_Nullable *_Nullable)error;

- (nullable NSData *)encodeProtocolMessage:(ARTProtocolMessage *)message error:(NSError *_Nullable *_Nullable)error;
- (nullable ARTProtocolMessage *)decodeProtocolMessage:(NSData *)data error:(NSError *_Nullable *_Nullable)error;

- (nullable NSDate *)decodeTime:(NSData *)data error:(NSError *_Nullable *_Nullable)error;
- (nullable NSError *)decodeError:(NSData *)error error:(NSError *_Nullable *_Nullable)error;
- (nullable NSArray *)decodeStats:(NSData *)data error:(NSError *_Nullable *_Nullable)error;

@end

Expand Down
16 changes: 12 additions & 4 deletions Source/ARTJsonEncoder.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,20 @@ - (NSString *)formatAsString {
return @"json";
}

- (id)decode:(NSData *)data {
return [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
- (id)decode:(NSData *)data error:(NSError **)error {
return [NSJSONSerialization JSONObjectWithData:data options:0 error:error];
}

- (NSData *)encode:(id)obj {
return [NSJSONSerialization dataWithJSONObject:obj options:0 error:nil];
- (NSData *)encode:(id)obj error:(NSError **)error {
@try {
return [NSJSONSerialization dataWithJSONObject:obj options:0 error:error];
}
@catch (NSException *exception) {
if (error) {
*error = [[NSError alloc] initWithDomain:ARTAblyErrorDomain code:ARTClientCodeErrorInvalidType userInfo:@{NSLocalizedDescriptionKey: exception.reason}];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mattheworiordan I decided to not use the isValidJSONObject method because it doesn't tell us why it isn't valid. On the other hand, catching the exception gives us more details about the failure.

}
return nil;
}
}

@end
4 changes: 2 additions & 2 deletions Source/ARTJsonLikeEncoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ ART_ASSUME_NONNULL_BEGIN
- (ARTEncoderFormat)format;
- (NSString *)formatAsString;

- (id)decode:(NSData *)data;
- (NSData *)encode:(id)obj;
- (nullable id)decode:(NSData *)data error:(NSError * _Nullable __autoreleasing * _Nullable)error;
- (nullable NSData *)encode:(id)obj error:(NSError * _Nullable __autoreleasing * _Nullable)error;

@end

Expand Down
Loading