Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion Sources/Sentry/PrivateSentrySDKOnly.m
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ + (void)captureEnvelope:(SentryEnvelope *)envelope

+ (nullable SentryEnvelope *)envelopeWithData:(NSData *)data
{
return [SentrySerialization envelopeWithData:data];
return [DataDeserialization envelopeWithData:data];
}

#if !SDK_V9
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/Public/SentryEnvelopeItemHeader.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ SENTRY_NO_INIT

- (instancetype)initWithType:(NSString *)type
length:(NSUInteger)length
contentType:(NSString *)contentType
contentType:(NSString *_Nullable)contentType
itemCount:(NSNumber *)itemCount;

/**
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryAttachment.m
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ - (instancetype)initWithPath:(NSString *)path
}

SentryAttachmentType
typeForSentryAttachmentName(NSString *name)
typeForSentryAttachmentName(NSString *_Nullable name)
{
if ([name isEqualToString:kSentryAttachmentTypeNameViewHierarchy]) {
return kSentryAttachmentTypeViewHierarchy;
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryFileManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,7 @@ - (void)handleEnvelopesLimit
[envelopePathsCopy removeObjectAtIndex:i];

NSData *envelopeData = [[NSFileManager defaultManager] contentsAtPath:envelopeFilePath];
SentryEnvelope *envelope = [SentrySerialization envelopeWithData:envelopeData];
SentryEnvelope *envelope = [DataDeserialization envelopeWithData:envelopeData];

BOOL didMigrateSessionInit =
[SentryMigrateSessionInit migrateSessionInit:envelope
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryHttpTransport.m
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ - (void)sendAllCachedEnvelopes

envelopeFilePath = envelopeFileContents.path;

envelope = [SentrySerialization envelopeWithData:envelopeFileContents.contents];
envelope = [DataDeserialization envelopeWithData:envelopeFileContents.contents];
if (nil == envelope) {
SENTRY_LOG_DEBUG(@"Envelope contained no deserializable data.");
[self deleteEnvelopeAndSendNext:envelopeFilePath];
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/SentryMigrateSessionInit.m
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ + (BOOL)setInitFlagOnNextEnvelopeWithSameSessionId:(SentrySession *)session
continue;
}

SentryEnvelope *envelope = [SentrySerialization envelopeWithData:envelopeData];
SentryEnvelope *envelope = [DataDeserialization envelopeWithData:envelopeData];

if (nil != envelope) {
BOOL didSetInitFlag = [self setInitFlagIfContainsSameSessionId:session.sessionId
Expand Down
159 changes: 0 additions & 159 deletions Sources/Sentry/SentrySerialization.m
Original file line number Diff line number Diff line change
Expand Up @@ -70,171 +70,12 @@
}
[envelopeData appendData:itemHeader];
[envelopeData appendData:newLineData];
[envelopeData appendData:envelope.items[i].data];

Check warning on line 73 in Sources/Sentry/SentrySerialization.m

View workflow job for this annotation

GitHub Actions / Build XCFramework Slices (Sentry, mh_dylib, -WithoutUIKitOrAppKit, WithoutUIKit, sentry-withoutui... / xros

implicit conversion from nullable pointer 'NSData * _Nullable' to non-nullable pointer type 'NSData * _Nonnull' [-Wnullable-to-nonnull-conversion]

Check warning on line 73 in Sources/Sentry/SentrySerialization.m

View workflow job for this annotation

GitHub Actions / Build XCFramework Slices (Sentry, mh_dylib, -WithoutUIKitOrAppKit, WithoutUIKit, sentry-withoutui... / watchos

implicit conversion from nullable pointer 'NSData * _Nullable' to non-nullable pointer type 'NSData * _Nonnull' [-Wnullable-to-nonnull-conversion]

Check warning on line 73 in Sources/Sentry/SentrySerialization.m

View workflow job for this annotation

GitHub Actions / Build XCFramework Slices (Sentry, mh_dylib, -WithoutUIKitOrAppKit, WithoutUIKit, sentry-withoutui... / appletvos

implicit conversion from nullable pointer 'NSData * _Nullable' to non-nullable pointer type 'NSData * _Nonnull' [-Wnullable-to-nonnull-conversion]

Check warning on line 73 in Sources/Sentry/SentrySerialization.m

View workflow job for this annotation

GitHub Actions / Build XCFramework Slices (Sentry, staticlib, sentry-static) / watchos

implicit conversion from nullable pointer 'NSData * _Nullable' to non-nullable pointer type 'NSData * _Nonnull' [-Wnullable-to-nonnull-conversion]

Check warning on line 73 in Sources/Sentry/SentrySerialization.m

View workflow job for this annotation

GitHub Actions / Sample watchOS-Swift WatchKit App Debug

implicit conversion from nullable pointer 'NSData * _Nullable' to non-nullable pointer type 'NSData * _Nonnull' [-Wnullable-to-nonnull-conversion]

Check warning on line 73 in Sources/Sentry/SentrySerialization.m

View workflow job for this annotation

GitHub Actions / Build XCFramework Slices (Sentry, mh_dylib, -Dynamic, sentry-dynamic) / watchos

implicit conversion from nullable pointer 'NSData * _Nullable' to non-nullable pointer type 'NSData * _Nonnull' [-Wnullable-to-nonnull-conversion]

Check warning on line 73 in Sources/Sentry/SentrySerialization.m

View workflow job for this annotation

GitHub Actions / Build XCFramework Slices (SentrySwiftUI, mh_dylib, sentry-swiftui) / watchos

implicit conversion from nullable pointer 'NSData * _Nullable' to non-nullable pointer type 'NSData * _Nonnull' [-Wnullable-to-nonnull-conversion]
}

return envelopeData;
}

+ (SentryEnvelope *_Nullable)envelopeWithData:(NSData *)data
{
SentryEnvelopeHeader *envelopeHeader = nil;
const unsigned char *bytes = [data bytes];
NSUInteger envelopeHeaderIndex = 0;

for (NSUInteger i = 0; i < data.length; ++i) {
if (bytes[i] == '\n') {
envelopeHeaderIndex = i;
// Envelope header end
NSData *headerData = [NSData dataWithBytes:bytes length:i];
#ifdef DEBUG
NSString *headerString = [[NSString alloc] initWithData:headerData
encoding:NSUTF8StringEncoding];
SENTRY_LOG_DEBUG(@"Header %@", headerString);
#endif
NSError *error = nil;
NSDictionary *headerDictionary = [NSJSONSerialization JSONObjectWithData:headerData
options:0
error:&error];
if (nil != error) {
SENTRY_LOG_ERROR(@"Failed to parse envelope header %@", error);
break;
}

SentryId *eventId = nil;
NSString *eventIdAsString = headerDictionary[@"event_id"];
if (nil != eventIdAsString) {
eventId = [[SentryId alloc] initWithUUIDString:eventIdAsString];
}

SentrySdkInfo *sdkInfo = nil;
if (nil != headerDictionary[@"sdk"] &&
[headerDictionary[@"sdk"] isKindOfClass:[NSDictionary class]]) {
sdkInfo = [[SentrySdkInfo alloc]
initWithDict:SENTRY_UNWRAP_NULLABLE(NSDictionary, headerDictionary[@"sdk"])];
}

SentryTraceContext *traceContext = nil;
if (nil != headerDictionary[@"trace"] &&
[headerDictionary[@"trace"] isKindOfClass:[NSDictionary class]]) {
traceContext = [[SentryTraceContext alloc]
initWithDict:SENTRY_UNWRAP_NULLABLE(NSDictionary, headerDictionary[@"trace"])];
}

envelopeHeader = [[SentryEnvelopeHeader alloc] initWithId:eventId
sdkInfo:sdkInfo
traceContext:traceContext];

if (headerDictionary[@"sent_at"] != nil &&
[headerDictionary[@"sent_at"] isKindOfClass:[NSString class]]) {
envelopeHeader.sentAt = sentry_fromIso8601String(
SENTRY_UNWRAP_NULLABLE(NSString, headerDictionary[@"sent_at"]));
}

break;
}
}

if (nil == envelopeHeader) {
SENTRY_LOG_ERROR(@"Invalid envelope. No header found.");
return nil;
}

if (envelopeHeaderIndex == 0) {
SENTRY_LOG_ERROR(@"EnvelopeHeader was parsed, its index is expected.");
return nil;
}

// Parse items
NSUInteger itemHeaderStart = envelopeHeaderIndex + 1;

NSMutableArray<SentryEnvelopeItem *> *items = [NSMutableArray new];
NSUInteger endOfEnvelope = data.length - 1;

for (NSUInteger i = itemHeaderStart; i <= endOfEnvelope; ++i) {
if (bytes[i] == '\n' || i == endOfEnvelope) {

NSData *itemHeaderData =
[data subdataWithRange:NSMakeRange(itemHeaderStart, i - itemHeaderStart)];
#ifdef DEBUG
NSString *itemHeaderString = [[NSString alloc] initWithData:itemHeaderData
encoding:NSUTF8StringEncoding];
SENTRY_LOG_DEBUG(@"Item Header %@", itemHeaderString);
#endif
NSError *error = nil;
NSDictionary *headerDictionary = [NSJSONSerialization JSONObjectWithData:itemHeaderData
options:0
error:&error];
if (nil != error) {
SENTRY_LOG_ERROR(@"Failed to parse envelope item header %@", error);
return nil;
}
NSString *_Nullable nullableType = [headerDictionary valueForKey:@"type"];
if (nil == nullableType) {
SENTRY_LOG_ERROR(@"Envelope item type is required.");
break;
}
NSString *_Nonnull type = SENTRY_UNWRAP_NULLABLE(NSString, nullableType);

NSNumber *bodyLengthNumber = [headerDictionary valueForKey:@"length"];
NSUInteger bodyLength = [bodyLengthNumber unsignedIntegerValue];
if (endOfEnvelope == i && bodyLength != 0) {
SENTRY_LOG_ERROR(
@"Envelope item has no data but header indicates it's length is %d.",
(int)bodyLength);
break;
}

NSString *filename = [headerDictionary valueForKey:@"filename"];
NSString *contentType = [headerDictionary valueForKey:@"content_type"];
NSString *attachmentType = [headerDictionary valueForKey:@"attachment_type"];
NSNumber *itemCount = [headerDictionary valueForKey:@"item_count"];

SentryEnvelopeItemHeader *itemHeader;
if (nil != filename) {
itemHeader = [[SentryEnvelopeAttachmentHeader alloc]
initWithType:type
length:bodyLength
filename:filename
contentType:contentType
attachmentType:typeForSentryAttachmentName(attachmentType)];
} else if (nil != itemCount) {
itemHeader = [[SentryEnvelopeItemHeader alloc] initWithType:type
length:bodyLength
contentType:contentType
itemCount:itemCount];
} else {
itemHeader = [[SentryEnvelopeItemHeader alloc] initWithType:type length:bodyLength];
}

if (endOfEnvelope == i) {
i++; // 0 byte attachment
}

if (bodyLength > 0 && data.length < (i + 1 + bodyLength)) {
SENTRY_LOG_ERROR(@"Envelope is corrupted or has invalid data. Trying to read %li "
@"bytes by skipping %li from a buffer of %li bytes.",
(unsigned long)data.length, (unsigned long)bodyLength, (long)(i + 1));
return nil;
}

NSData *itemBody = [data subdataWithRange:NSMakeRange(i + 1, bodyLength)];
SentryEnvelopeItem *envelopeItem = [[SentryEnvelopeItem alloc] initWithHeader:itemHeader
data:itemBody];
[items addObject:envelopeItem];
i = itemHeaderStart = i + 1 + [bodyLengthNumber integerValue];
}
}

if (items.count == 0) {
SENTRY_LOG_ERROR(@"Envelope has no items.");
return nil;
}

SentryEnvelope *envelope = [[SentryEnvelope alloc] initWithHeader:envelopeHeader items:items];
return envelope;
}

+ (NSData *_Nullable)dataWithSession:(SentrySession *)session
{
return [self dataWithJSONObject:[session serialize]];
Expand Down
2 changes: 1 addition & 1 deletion Sources/Sentry/include/SentryAttachment+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ typedef NS_ENUM(NSInteger, SentryAttachmentType) {

NSString *nameForSentryAttachmentType(SentryAttachmentType attachmentType);

SentryAttachmentType typeForSentryAttachmentName(NSString *name);
SentryAttachmentType typeForSentryAttachmentName(NSString *_Nullable name);

@interface SentryAttachment ()
SENTRY_NO_INIT
Expand Down
2 changes: 0 additions & 2 deletions Sources/Sentry/include/SentrySerialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ NS_ASSUME_NONNULL_BEGIN

+ (NSData *_Nullable)dataWithEnvelope:(SentryEnvelope *)envelope;

+ (SentryEnvelope *_Nullable)envelopeWithData:(NSData *)data;

/**
* Retrieves the json object from an event envelope item data.
*/
Expand Down
152 changes: 152 additions & 0 deletions Sources/Swift/Helper/DataDeserialization.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@_implementationOnly import _SentryPrivate

@_spi(Private) @objc public final class DataDeserialization: NSObject {
@objc(sessionWithData:) public static func session(with data: Data) -> SentrySession? {
do {
Expand Down Expand Up @@ -29,4 +31,154 @@
return nil
}
}

//swiftlint:disable cyclomatic_complexity function_body_length
@objc(envelopeWithData:) public static func envelope(with data: Data) -> SentryEnvelope? {
var envelopeHeader: SentryEnvelopeHeader?
let bytes = [UInt8](data)
var envelopeHeaderIndex: Int = 0

for i in 0..<data.count {
if bytes[i] == UInt8(ascii: "\n") {
envelopeHeaderIndex = i
// Envelope header end
let headerData = data.subdata(in: 0..<i)
#if DEBUG
if let headerString = String(data: headerData, encoding: .utf8) {
SentrySDKLog.debug("Header \(headerString)")
}
#endif
do {
let headerDictionary = try JSONSerialization.jsonObject(with: headerData) as? [String: Any]
var eventId: SentryId?
if let eventIdAsString = headerDictionary?["event_id"] as? String {
eventId = SentryId(uuidString: eventIdAsString)
}

var sdkInfo: SentrySdkInfo?
if let sdkDict = headerDictionary?["sdk"] as? [String: Any] {
sdkInfo = SentrySdkInfo(dict: sdkDict)
}

var traceContext: TraceContext?
if let traceDict = headerDictionary?["trace"] as? [String: Any] {
traceContext = TraceContext(dict: traceDict)
}

envelopeHeader = SentryEnvelopeHeader(id: eventId,
sdkInfo: sdkInfo,
traceContext: traceContext)

if let sentAtStr = headerDictionary?["sent_at"] as? String {
envelopeHeader?.sentAt = sentry_fromIso8601String(sentAtStr)
}
break
} catch {
SentrySDKLog.error("Failed to parse envelope header \(error)")
break
}
}
}

guard let envelopeHeaderUnwrapped = envelopeHeader else {
SentrySDKLog.error("Invalid envelope. No header found.")
return nil
}

if envelopeHeaderIndex == 0 {
SentrySDKLog.error("EnvelopeHeader was parsed, its index is expected.")
return nil
}

// Parse items
var itemHeaderStart = envelopeHeaderIndex + 1
var items: [SentryEnvelopeItem] = []
let endOfEnvelope = data.count - 1

var i = itemHeaderStart
while i <= endOfEnvelope {
defer {
i += 1
}
if bytes[i] == UInt8(ascii: "\n") || i == endOfEnvelope {
let itemHeaderData = (data as NSData).subdata(with: NSRange(location: itemHeaderStart, length: i - itemHeaderStart))

#if DEBUG
if let itemHeaderString = String(data: itemHeaderData, encoding: .utf8) {
SentrySDKLog.debug("Item Header \(itemHeaderString)")
}
#endif

do {
let headerDictionary = try JSONSerialization.jsonObject(with: itemHeaderData) as? [String: Any]

guard let type = headerDictionary?["type"] as? String else {
SentrySDKLog.error("Envelope item type is required.")
break
}

let bodyLength = (headerDictionary?["length"] as? NSNumber)?.uintValue ?? 0

if i == endOfEnvelope && bodyLength != 0 {
SentrySDKLog.error("Envelope item has no data but header indicates its length is \(bodyLength).")
break
}

let filename = headerDictionary?["filename"] as? String
let contentType = headerDictionary?["content_type"] as? String
let attachmentType = headerDictionary?["attachment_type"] as? String
let itemCount = headerDictionary?["item_count"] as? NSNumber

let itemHeader: SentryEnvelopeItemHeader
if let filename = filename {
itemHeader = SentryEnvelopeAttachmentHeader(
type: type,
length: bodyLength,
filename: filename,
contentType: contentType,
attachmentType: typeForSentryAttachmentName(attachmentType)
)
} else if let itemCount = itemCount {
itemHeader = SentryEnvelopeItemHeader(
type: type,
length: bodyLength,
contentType: contentType,
itemCount: itemCount
)
} else {
itemHeader = SentryEnvelopeItemHeader(type: type, length: bodyLength)
}

if i == endOfEnvelope {
i += 1 // 0-byte attachment
}

if bodyLength > 0 && data.count < (i + 1 + Int(bodyLength)) {
SentrySDKLog.error(
"Envelope is corrupted or has invalid data. Trying to read \(bodyLength) bytes by skipping \(i + 1) from a buffer of \(data.count) bytes."
)
return nil
}

let itemBody = (data as NSData).subdata(with: NSRange(location: i + 1, length: Int(bodyLength)))
let envelopeItem = SentryEnvelopeItem(header: itemHeader, data: itemBody)
items.append(envelopeItem)

i = i + 1 + Int(bodyLength)
itemHeaderStart = i
} catch {
SentrySDKLog.error("Failed to parse envelope item header \(error)")
return nil
}
}
}

if items.isEmpty {
SentrySDKLog.error("Envelope has no items.")
return nil
}

return SentryEnvelope(header: envelopeHeaderUnwrapped, items: items)
}
//swiftlint:enable cyclomatic_complexity function_body_length
}
Loading
Loading