Skip to content

Commit

Permalink
Make sure we consume all data.
Browse files Browse the repository at this point in the history
Non-whitespace after processing is treated as an error.
  • Loading branch information
schwa committed Jul 11, 2013
1 parent 925e8b7 commit bfffb73
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 42 deletions.
1 change: 1 addition & 0 deletions Source/CJSONDeserializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ typedef enum {
kJSONDeserializerErrorCode_CouldNotDecodeData = -12,
kJSONDeserializerErrorCode_CouldNotScanObject = -15,
kJSONDeserializerErrorCode_ScanningFragmentsNotAllowed = -16,
kJSONDeserializerErrorCode_DidNotConsumeAllData = -17,

// Dictionary scanning
kJSONDeserializerErrorCode_DictionaryStartCharacterMissing = -101,
Expand Down
52 changes: 49 additions & 3 deletions Source/CJSONDeserializer.m
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,22 @@ - (id)deserialize:(NSData *)inData error:(NSError **)outError
}
}

// If we haven't consumed all the data...
if (_current != _end)
{
// Skip any remaining whitespace...
_current = _SkipWhiteSpace(_current, _end);
// And then error if we still haven't consumed all data...
if (_current != _end)
{
if (outError != NULL)
{
*outError = [self _error:kJSONDeserializerErrorCode_DidNotConsumeAllData description:@"Did not consume all data."];
}
return(NULL);
}
}

return (theObject);
}

Expand Down Expand Up @@ -244,19 +260,49 @@ - (BOOL)_scanJSONObject:(id *)outObject error:(NSError **)outError
case 't':
{
theResult = _ScanUTF8String(self, "true", 4);
theObject = (__bridge id) kCFBooleanTrue;
if (theResult != NO)
{
theObject = (__bridge id) kCFBooleanTrue;
}
else
{
if (outError)
{
*outError = [self _error:kJSONDeserializerErrorCode_CouldNotScanObject description:@"Could not scan object. Character not a valid JSON character."];
}
}
break;
}
case 'f':
{
theResult = _ScanUTF8String(self, "false", 5);
theObject = (__bridge id) kCFBooleanFalse;
if (theResult != NO)
{
theObject = (__bridge id) kCFBooleanFalse;
}
else
{
if (outError)
{
*outError = [self _error:kJSONDeserializerErrorCode_CouldNotScanObject description:@"Could not scan object. Character not a valid JSON character."];
}
}
}
break;
case 'n':
{
theResult = _ScanUTF8String(self, "null", 4);
theObject = _nullObject ?: [NSNull null];
if (theResult != NO)
{
theObject = _nullObject ?: [NSNull null];
}
else
{
if (outError)
{
*outError = [self _error:kJSONDeserializerErrorCode_CouldNotScanObject description:@"Could not scan object. Character not a valid JSON character."];
}
}
}
break;
case '\"':
Expand Down

This file was deleted.

101 changes: 101 additions & 0 deletions Support/UnitTests/CJSONDeserializer_UnitTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,108 @@ - (void)testFloatsWithGiantExponents
STAssertEqualObjects(theDeseralizedValue, [NSDecimalNumber decimalNumberWithString:theString], @"");
}

- (void)testBadTrueValue1
{
NSData *theData = [@"troo" dataUsingEncoding:NSUTF8StringEncoding];
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.options |= kJSONDeserializationOptions_AllowFragments;
NSError *theError = NULL;
id theDeseralizedValue = [theDeserializer deserialize:theData error:&theError];
STAssertNil(theDeseralizedValue, @"This test should return nil");
STAssertNotNil(theError, @"This test should return an error");
}

- (void)testBadTrueValue2
{
NSData *theData = [@"true_not_really" dataUsingEncoding:NSUTF8StringEncoding];
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.options |= kJSONDeserializationOptions_AllowFragments;
NSError *theError = NULL;
id theDeseralizedValue = [theDeserializer deserialize:theData error:&theError];
STAssertNil(theDeseralizedValue, @"This test should return nil");
STAssertNotNil(theError, @"This test should return an error");
}

- (void)testBadTrueValue3
{
NSData *theData = [@"[true_not_really,true]" dataUsingEncoding:NSUTF8StringEncoding];
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.options |= kJSONDeserializationOptions_AllowFragments;
NSError *theError = NULL;
id theDeseralizedValue = [theDeserializer deserialize:theData error:&theError];
STAssertNil(theDeseralizedValue, @"This test should return nil");
STAssertNotNil(theError, @"This test should return an error");
}

- (void)testTrue
{
NSData *theData = [@"true" dataUsingEncoding:NSUTF8StringEncoding];
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.options |= kJSONDeserializationOptions_AllowFragments;
NSError *theError = NULL;
id theDeseralizedValue = [theDeserializer deserialize:theData error:&theError];
STAssertNotNil(theDeseralizedValue, @"This test should not return nil");
STAssertNil(theError, @"This test should not return an error");
STAssertEqualObjects(theDeseralizedValue, @(YES), NULL);
}

- (void)testFalse
{
NSData *theData = [@"false" dataUsingEncoding:NSUTF8StringEncoding];
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.options |= kJSONDeserializationOptions_AllowFragments;
NSError *theError = NULL;
id theDeseralizedValue = [theDeserializer deserialize:theData error:&theError];
STAssertNotNil(theDeseralizedValue, @"This test should not return nil");
STAssertNil(theError, @"This test should not return an error");
STAssertEqualObjects(theDeseralizedValue, @(NO), NULL);
}

- (void)testConsumingAllData1
{
NSData *theData = [@"true " dataUsingEncoding:NSUTF8StringEncoding];
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.options |= kJSONDeserializationOptions_AllowFragments;
NSError *theError = NULL;
id theDeseralizedValue = [theDeserializer deserialize:theData error:&theError];
STAssertNotNil(theDeseralizedValue, @"This test should not return nil");
STAssertNil(theError, @"This test should not return an error");
STAssertEqualObjects(theDeseralizedValue, @(YES), NULL);
}

- (void)testConsumingAllData2
{
NSData *theData = [@"[] " dataUsingEncoding:NSUTF8StringEncoding];
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.options |= kJSONDeserializationOptions_AllowFragments;
NSError *theError = NULL;
id theDeseralizedValue = [theDeserializer deserialize:theData error:&theError];
STAssertNotNil(theDeseralizedValue, @"This test should not return nil");
STAssertNil(theError, @"This test should not return an error");
STAssertEqualObjects(theDeseralizedValue, @[], NULL);
}

- (void)testNotConsumingAllData1
{
NSData *theData = [@"true x" dataUsingEncoding:NSUTF8StringEncoding];
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.options |= kJSONDeserializationOptions_AllowFragments;
NSError *theError = NULL;
id theDeseralizedValue = [theDeserializer deserialize:theData error:&theError];
STAssertNil(theDeseralizedValue, @"This test should return nil");
STAssertNotNil(theError, @"This test should return an error");
}

- (void)testNotConsumingAllData2
{
NSData *theData = [@"[] x" dataUsingEncoding:NSUTF8StringEncoding];
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.options |= kJSONDeserializationOptions_AllowFragments;
NSError *theError = NULL;
id theDeseralizedValue = [theDeserializer deserialize:theData error:&theError];
STAssertNil(theDeseralizedValue, @"This test should return nil");
STAssertNotNil(theError, @"This test should return an error");
}

#pragma mark Old tests - these are still being reviewed for value and possibly due for clean up.

Expand Down

0 comments on commit bfffb73

Please sign in to comment.