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

Conversation

ricardopereira
Copy link
Contributor

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

[self.logger error:@"ARTChannel: error encoding data: %@", error];
[NSException raise:NSInvalidArgumentException format:@"ARTChannel: error encoding data: %@", error];
message = [message encodeWithEncoder:self.dataEncoder error:error];
if (error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

error && *error; error alone will be true just by passing a non-null NSError **.

In fact, so that we always log this, and not only when error is passed, we should do something like:

NSError *e = nil;
message = [message encodeWithEncoder:self.dataEncoder error:&e];
if (e) {
    [self.logger error:@"ARTChannel: error encoding data: %@", e];
}
 if (error) {
    *error = e;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done f4619aa

@@ -43,8 +43,8 @@ ART_ASSUME_NONNULL_BEGIN
- (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 NSData *)encodeProtocolMessage:(ARTProtocolMessage *)message error:(NSError * __autoreleasing *)error;
Copy link
Contributor

@tcard tcard Apr 11, 2017

Choose a reason for hiding this comment

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

I'm not sure __autoreleasing is necessary, but I think __Nullable is: NSError *_Nullable *_Nullable

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did that because I took a look at the NSJSONSerialization header file that returns errors as well 😅 [NSJSONSerialization JSONObjectWithData:<#(nonnull NSData *)#> options:<#(NSJSONReadingOptions)#> error:<#(NSError * _Nullable __autoreleasing * _Nullable)#>]

@@ -810,12 +811,28 @@ - (BOOL)isActive {
- (void)sendImpl:(ARTProtocolMessage *)msg callback:(void (^)(ARTStatus *))cb {
if (msg.ackRequired) {
msg.msgSerial = [NSNumber numberWithLongLong:self.msgSerial++];
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be moved below the error handling, so that errors don't increase msgSerial.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tcard Ah you're right. So I need to encode it twice?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What about decrementing the msgSerial if the encode fails?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah right, I didn't notice we need the updated value. I think msg.msgSerial = [NSNumber numberWithLongLong:self.msgSerial + 1] here and then below just self.msgSerial++; would be the simplest.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done f4619aa. Thanks

done()
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing a test for incoming malformed JSON.

Copy link
Contributor

Choose a reason for hiding this comment

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

(Also for malformed MsgPack, BTW.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done: c4de4b9

@mattheworiordan
Copy link
Member

Ok, so we would like to extend these tests so that they additionally cover incoming invalid/non-encodeable payloads for both binary (msgpack) and text (JSON) transports i.e. if the client library receives a payload that causes a native encoding fault / exception, then the library must handle that in a way that does not cause it to crash. We need to test that both for REST and Realtime.

@ricardopereira ricardopereira merged commit 32918ed into master Apr 13, 2017
@ricardopereira ricardopereira deleted the fix-json-encoder branch April 13, 2017 12:18
ricardopereira added a commit that referenced this pull request Apr 13, 2017
* Test: JSON encoder using invalid types

* Test: should handle and emit the invalid data error

* Fix: handle and emit the invalid data encoder error

* Update existing tests

* Test: should decode data with malformed JSON

* fixup! Fix: handle and emit the invalid data encoder error

* Test: should decode data with malformed MsgPack

* Test: incoming invalid/non-encodeable payloads and messages

* Add error argument on every encode/decode method

* Update tests

* fixup! Add error argument on every encode/decode method

* TestProxyTransport: sendWithData needs to capture protocol messages

* Add missing authDetailsFromDictionary

* fixup! Add error argument on every encode/decode method

* Fix: invalid type cast

* Fix: bad access crash

* Fix test

* fixup! Fix: bad access crash

* Fix: missing encoder fields

* If message error is empty then use the reason prop

* Keep the original error domain to give more context

* Transport: use only one way to send data
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants