diff --git a/Podfile.lock b/Podfile.lock index 2cf3fb0e..0ad0b41d 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,18 +1,18 @@ PODS: - Amplitude (7.2.2) - - Appboy-iOS-SDK (4.4.2): - - Appboy-iOS-SDK/UI (= 4.4.2) - - Appboy-iOS-SDK/ContentCards (4.4.2): + - Appboy-iOS-SDK (4.5.4): + - Appboy-iOS-SDK/UI (= 4.5.4) + - Appboy-iOS-SDK/ContentCards (4.5.4): - Appboy-iOS-SDK/Core - SDWebImage (< 6, >= 5.8.2) - - Appboy-iOS-SDK/Core (4.4.2) - - Appboy-iOS-SDK/InAppMessage (4.4.2): + - Appboy-iOS-SDK/Core (4.5.4) + - Appboy-iOS-SDK/InAppMessage (4.5.4): - Appboy-iOS-SDK/Core - SDWebImage (< 6, >= 5.8.2) - - Appboy-iOS-SDK/NewsFeed (4.4.2): + - Appboy-iOS-SDK/NewsFeed (4.5.4): - Appboy-iOS-SDK/Core - SDWebImage (< 6, >= 5.8.2) - - Appboy-iOS-SDK/UI (4.4.2): + - Appboy-iOS-SDK/UI (4.5.4): - Appboy-iOS-SDK/ContentCards - Appboy-iOS-SDK/Core - Appboy-iOS-SDK/InAppMessage @@ -43,7 +43,7 @@ PODS: - GoogleUtilities/Reachability (~> 7.7) - GoogleUtilities/UserDefaults (~> 7.7) - nanopb (< 2.30910.0, >= 2.30908.0) - - GoogleDataTransport (9.2.2): + - GoogleDataTransport (9.2.3): - GoogleUtilities/Environment (~> 7.7) - nanopb (< 2.30910.0, >= 2.30908.0) - PromisesObjC (< 3.0, >= 1.2) @@ -70,16 +70,16 @@ PODS: - nanopb/decode (2.30909.0) - nanopb/encode (2.30909.0) - PromisesObjC (2.2.0) - - Rudder (1.13.2) + - Rudder (1.15.1) - Rudder-Amplitude (1.0.2): - Amplitude (~> 7.2.0) - Rudder - - Rudder-Braze (1.1.1): - - Appboy-iOS-SDK (= 4.4.2) - - Rudder (~> 1.0) - - SDWebImage (5.15.5): - - SDWebImage/Core (= 5.15.5) - - SDWebImage/Core (5.15.5) + - Rudder-Braze (1.2.0): + - Appboy-iOS-SDK (~> 4.5.4) + - Rudder (~> 1.12) + - SDWebImage (5.15.8): + - SDWebImage/Core (= 5.15.8) + - SDWebImage/Core (5.15.8) DEPENDENCIES: - Amplitude (~> 7.2.0) @@ -111,21 +111,21 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Amplitude: 517cdc7c485bda64b685174426ecbf17746eb16a - Appboy-iOS-SDK: 4a7dfe908639da81e5e85849355f6066b58b4cc6 + Appboy-iOS-SDK: 2fc5b290fe1caa85718b811a19b303d45caea975 FirebaseCore: 2082fffcd855f95f883c0a1641133eb9bbe76d40 FirebaseCoreDiagnostics: 99a495094b10a57eeb3ae8efa1665700ad0bdaa6 FirebaseCoreInternal: bca76517fe1ed381e989f5e7d8abb0da8d85bed3 FirebaseInstallations: 0a115432c4e223c5ab20b0dbbe4cbefa793a0e8e FirebaseMessaging: a4d7910e4af663c9cbfc1071c5bef34651690949 - GoogleDataTransport: 8378d1fa8ac49753ea6ce70d65a7cb70ce5f66e6 + GoogleDataTransport: f0308f5905a745f94fb91fea9c6cbaf3831cb1bd GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749 nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef - Rudder: 1353907b7323389ad213f3ef0a30969261f67773 + Rudder: 41040d4537a178e4e32477b68400f98ca0c354eb Rudder-Amplitude: f845cc125a1a58d4de6155391a2b0392815ae898 - Rudder-Braze: e8b8c76b7e7f0348c79f8cc359e43f4c6cd7ac9b - SDWebImage: fd7e1a22f00303e058058278639bf6196ee431fe + Rudder-Braze: e42eb914a03cb418ed8b7a3cd90b724a91476631 + SDWebImage: cb032eba469c54e0000e78bcb0a13cdde0a52798 PODFILE CHECKSUM: 42bfa6ba9271b8d9518a669daca1fd9a7bbf9f6e -COCOAPODS: 1.12.0 +COCOAPODS: 1.12.1 diff --git a/Rudder.xcodeproj/project.pbxproj b/Rudder.xcodeproj/project.pbxproj index 006d8535..8e2d0e06 100644 --- a/Rudder.xcodeproj/project.pbxproj +++ b/Rudder.xcodeproj/project.pbxproj @@ -18,6 +18,8 @@ ED38D39D29CB04C7003A7544 /* EventRepositoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED38D36E29CB01A0003A7544 /* EventRepositoryTests.swift */; }; ED38D39E29CB04C7003A7544 /* TestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED38D37D29CB01A0003A7544 /* TestUtils.swift */; }; ED38D39F29CB04C7003A7544 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED38D37029CB01A0003A7544 /* Extensions.swift */; }; + ED3CC19F2A14A78200F34082 /* NSData+GZIP.h in Headers */ = {isa = PBXBuildFile; fileRef = ED3CC19D2A14A78200F34082 /* NSData+GZIP.h */; settings = {ATTRIBUTES = (Public, ); }; }; + ED3CC1A02A14A78200F34082 /* NSData+GZIP.m in Sources */ = {isa = PBXBuildFile; fileRef = ED3CC19E2A14A78200F34082 /* NSData+GZIP.m */; }; ED7DFE38298C091800ED5A8E /* RSServerConfigSource.m in Sources */ = {isa = PBXBuildFile; fileRef = ED7DFD85298C091800ED5A8E /* RSServerConfigSource.m */; }; ED7DFE39298C091800ED5A8E /* RSTraits.m in Sources */ = {isa = PBXBuildFile; fileRef = ED7DFD86298C091800ED5A8E /* RSTraits.m */; }; ED7DFE3A298C091800ED5A8E /* RSLibraryInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = ED7DFD87298C091800ED5A8E /* RSLibraryInfo.m */; }; @@ -250,6 +252,8 @@ ED38D37129CB01A0003A7544 /* RudderUtilsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RudderUtilsTest.swift; sourceTree = ""; }; ED38D37C29CB01A0003A7544 /* ServerConfigManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServerConfigManagerTests.swift; sourceTree = ""; }; ED38D37D29CB01A0003A7544 /* TestUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUtils.swift; sourceTree = ""; }; + ED3CC19D2A14A78200F34082 /* NSData+GZIP.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+GZIP.h"; sourceTree = ""; }; + ED3CC19E2A14A78200F34082 /* NSData+GZIP.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSData+GZIP.m"; sourceTree = ""; }; ED7DFD85298C091800ED5A8E /* RSServerConfigSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSServerConfigSource.m; sourceTree = ""; }; ED7DFD86298C091800ED5A8E /* RSTraits.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSTraits.m; sourceTree = ""; }; ED7DFD87298C091800ED5A8E /* RSLibraryInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RSLibraryInfo.m; sourceTree = ""; }; @@ -556,6 +560,7 @@ children = ( ED7DFDD0298C091800ED5A8E /* Ecomm */, EDA2C5B129C0EB9500B7FF42 /* Headers */, + ED3CC19E2A14A78200F34082 /* NSData+GZIP.m */, ED7DFD8B298C091800ED5A8E /* RSApp.m */, F6B4B53729C8237D00344864 /* RSApplicationLifeCycleManager.m */, F6B4B53529C8237D00344864 /* RSBackGroundModeManager.m */, @@ -610,6 +615,7 @@ isa = PBXGroup; children = ( EDEC3CD829ADC9CF007DDE07 /* Ecomm */, + ED3CC19D2A14A78200F34082 /* NSData+GZIP.h */, ED7DFDB1298C091800ED5A8E /* RSApp.h */, F6B4B52529C8236100344864 /* RSApplicationLifeCycleManager.h */, F6B4B51E29C8236100344864 /* RSBackGroundModeManager.h */, @@ -946,6 +952,7 @@ F6B4B53029C8236100344864 /* RSDeviceModeTransformationManager.h in Headers */, ED7DFED7298C091800ED5A8E /* RSProductRemovedFromWishListEvent.h in Headers */, F6B4B52729C8236100344864 /* RSCloudModeManager.h in Headers */, + ED3CC19F2A14A78200F34082 /* NSData+GZIP.h in Headers */, F6B4B52D29C8236100344864 /* RSDataResidencyManager.h in Headers */, ED7DFE90298C091800ED5A8E /* RSECommerceCheckout.h in Headers */, F6B4B52A29C8236100344864 /* RSDeviceModeManager.h in Headers */, @@ -1158,6 +1165,7 @@ ED7DFE4C298C091800ED5A8E /* RSMessageType.m in Sources */, ED7DFEAA298C091800ED5A8E /* RSProductAddedToWishListEvent.m in Sources */, ED7DFED1298C091800ED5A8E /* RSProductViewedEvent.m in Sources */, + ED3CC1A02A14A78200F34082 /* NSData+GZIP.m in Sources */, ED7DFE41298C091800ED5A8E /* RSEventFilteringPlugin.m in Sources */, F6B4B54029C8237D00344864 /* RSApplicationLifeCycleManager.m in Sources */, ED7DFEAB298C091800ED5A8E /* RSProductSearchedEvent.m in Sources */, diff --git a/Sources/Classes/Headers/Public/NSData+GZIP.h b/Sources/Classes/Headers/Public/NSData+GZIP.h new file mode 100644 index 00000000..34cff4c5 --- /dev/null +++ b/Sources/Classes/Headers/Public/NSData+GZIP.h @@ -0,0 +1,18 @@ +// +// NSData+GZIP.h +// Rudder +// +// Created by Pallab Maiti on 17/05/23. +// + +#import + + +@interface NSData (GZIP) + +- (nullable NSData *)gzippedDataWithCompressionLevel:(float)level; +- (nullable NSData *)gzippedData; +- (nullable NSData *)gunzippedData; +- (BOOL)isGzippedData; + +@end diff --git a/Sources/Classes/Headers/Public/RSConfig.h b/Sources/Classes/Headers/Public/RSConfig.h index cc04e51a..2fc70b4c 100644 --- a/Sources/Classes/Headers/Public/RSConfig.h +++ b/Sources/Classes/Headers/Public/RSConfig.h @@ -31,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readwrite) NSMutableArray* factories; @property (nonatomic, readwrite) NSMutableArray* customFactories; @property (nonatomic, readwrite, nullable) id consentFilter; +@property (nonatomic) bool gzip; @end diff --git a/Sources/Classes/Headers/Public/RSConfigBuilder.h b/Sources/Classes/Headers/Public/RSConfigBuilder.h index e460958a..f883f077 100644 --- a/Sources/Classes/Headers/Public/RSConfigBuilder.h +++ b/Sources/Classes/Headers/Public/RSConfigBuilder.h @@ -41,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)withFactory:(id _Nonnull)factory; - (instancetype)withCustomFactory:(id _Nonnull)customFactory; - (instancetype)withConsentFilter:(id _Nonnull)consentFilter; +- (instancetype)withGzip:(BOOL)status; - (RSConfig*)build; @end diff --git a/Sources/Classes/Headers/Public/RSConstants.h b/Sources/Classes/Headers/Public/RSConstants.h index 6a26463a..d1da6a62 100644 --- a/Sources/Classes/Headers/Public/RSConstants.h +++ b/Sources/Classes/Headers/Public/RSConstants.h @@ -37,6 +37,8 @@ extern bool const RSRecordScreenViews; extern bool const RSEnableBackgroundMode; // default for automatic session tracking extern bool const RSAutomaticSessionTracking; +// default for gzip request payload +extern bool const RSGzipStatus; // SDK Version extern NSString *const RS_VERSION; // constant used to check if event filtering is disabled diff --git a/Sources/Classes/NSData+GZIP.m b/Sources/Classes/NSData+GZIP.m new file mode 100644 index 00000000..4ee77157 --- /dev/null +++ b/Sources/Classes/NSData+GZIP.m @@ -0,0 +1,94 @@ +// +// NSData+GZIP.m +// Rudder +// +// Created by Pallab Maiti on 17/05/23. +// + +#import "NSData+GZIP.h" +#import + + +#pragma clang diagnostic ignored "-Wcast-qual" + + +@implementation NSData (GZIP) + +- (NSData *)gzippedDataWithCompressionLevel:(float)level { + if (self.length == 0 || [self isGzippedData]) { + return self; + } + + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.avail_in = (uint)self.length; + stream.next_in = (Bytef *)(void *)self.bytes; + stream.total_out = 0; + stream.avail_out = 0; + + static const NSUInteger ChunkSize = 16384; + + NSMutableData *output = nil; + int compression = (level < 0.0f)? Z_DEFAULT_COMPRESSION: (int)(roundf(level * 9)); + if (deflateInit2(&stream, compression, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) == Z_OK) { + output = [NSMutableData dataWithLength:ChunkSize]; + while (stream.avail_out == 0) { + if (stream.total_out >= output.length) { + output.length += ChunkSize; + } + stream.next_out = (uint8_t *)output.mutableBytes + stream.total_out; + stream.avail_out = (uInt)(output.length - stream.total_out); + deflate(&stream, Z_FINISH); + } + deflateEnd(&stream); + output.length = stream.total_out; + } + + return output; +} + +- (NSData *)gzippedData { + return [self gzippedDataWithCompressionLevel:-1.0f]; +} + +- (NSData *)gunzippedData { + if (self.length == 0 || ![self isGzippedData]) { + return self; + } + + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.avail_in = (uint)self.length; + stream.next_in = (Bytef *)self.bytes; + stream.total_out = 0; + stream.avail_out = 0; + + NSMutableData *output = nil; + if (inflateInit2(&stream, 47) == Z_OK) { + int status = Z_OK; + output = [NSMutableData dataWithCapacity:self.length * 2]; + while (status == Z_OK) { + if (stream.total_out >= output.length) { + output.length += self.length / 2; + } + stream.next_out = (uint8_t *)output.mutableBytes + stream.total_out; + stream.avail_out = (uInt)(output.length - stream.total_out); + status = inflate (&stream, Z_SYNC_FLUSH); + } + if (inflateEnd(&stream) == Z_OK && status == Z_STREAM_END) { + output.length = stream.total_out; + } + } + + return output; +} + +- (BOOL)isGzippedData { + const UInt8 *bytes = (const UInt8 *)self.bytes; + return (self.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b); +} + +@end diff --git a/Sources/Classes/RSConfig.m b/Sources/Classes/RSConfig.m index ddae9f34..a991d137 100644 --- a/Sources/Classes/RSConfig.m +++ b/Sources/Classes/RSConfig.m @@ -30,6 +30,7 @@ - (instancetype)init { _controlPlaneUrl = RSControlPlaneUrl; _factories = [[NSMutableArray alloc] init]; _customFactories = [[NSMutableArray alloc] init]; + _gzip = RSGzipStatus; } return self; } diff --git a/Sources/Classes/RSConfigBuilder.m b/Sources/Classes/RSConfigBuilder.m index d8cc4ef9..28140f27 100644 --- a/Sources/Classes/RSConfigBuilder.m +++ b/Sources/Classes/RSConfigBuilder.m @@ -209,6 +209,14 @@ - (instancetype)withSessionTimeoutMillis:(long)sessionTimeout { return self; } +- (instancetype)withGzip:(BOOL)status { + if (config == nil) { + config = [[RSConfig alloc] init]; + } + config.gzip = status; + return self; +} + - (RSConfig*) build { if (config == nil) { config = [[RSConfig alloc] init]; diff --git a/Sources/Classes/RSConstants.m b/Sources/Classes/RSConstants.m index 0fc8ef3e..abcdea15 100644 --- a/Sources/Classes/RSConstants.m +++ b/Sources/Classes/RSConstants.m @@ -22,6 +22,7 @@ @implementation RSConstants bool const RSRecordScreenViews = NO; bool const RSEnableBackgroundMode = NO; bool const RSAutomaticSessionTracking = YES; +bool const RSGzipStatus = YES; NSString *const RS_VERSION = SDK_VERSION; NSString* const DISABLE = @"disable"; NSString* const WHITELISTED_EVENTS = @"whitelistedEvents"; diff --git a/Sources/Classes/RSNetworkManager.m b/Sources/Classes/RSNetworkManager.m index 484cc1e2..9f322ff4 100644 --- a/Sources/Classes/RSNetworkManager.m +++ b/Sources/Classes/RSNetworkManager.m @@ -7,6 +7,7 @@ // #import "RSNetworkManager.h" +#import "NSData+GZIP.h" @implementation RSNetworkManager @@ -58,6 +59,10 @@ -(RSNetworkResponse*) sendNetworkRequest: (NSString*) payload toEndpoint:(ENDPOI [urlRequest addValue:@"Application/json" forHTTPHeaderField:@"Content-Type"]; [urlRequest addValue:self->anonymousIdToken forHTTPHeaderField:@"AnonymousId"]; NSData *httpBody = [payload dataUsingEncoding:NSUTF8StringEncoding]; + if (self-> config.gzip) { + httpBody = [httpBody gzippedData]; + [urlRequest addValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"]; + } [urlRequest setHTTPBody:httpBody]; } NSURLSession *session = [NSURLSession sharedSession];