diff --git a/android/arm64-v8a/libjs_static.a b/android/arm64-v8a/libjs_static.a index 78a87db0..5f2dbbb7 100644 Binary files a/android/arm64-v8a/libjs_static.a and b/android/arm64-v8a/libjs_static.a differ diff --git a/android/arm64-v8a/libmozglue.a b/android/arm64-v8a/libmozglue.a index 669dbf8f..cdbcecd5 100644 Binary files a/android/arm64-v8a/libmozglue.a and b/android/arm64-v8a/libmozglue.a differ diff --git a/ios/include/spidermonkey/js/Utility.h b/ios/include/spidermonkey/js/Utility.h index 75214c32..e95e8ecc 100644 --- a/ios/include/spidermonkey/js/Utility.h +++ b/ios/include/spidermonkey/js/Utility.h @@ -77,11 +77,11 @@ enum ThreadType { # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) extern bool InitThreadType(void); extern void SetThreadType(ThreadType); -extern uint32_t GetThreadType(void); +extern JS_PUBLIC_API(uint32_t) GetThreadType(void); # else inline bool InitThreadType(void) { return true; } inline void SetThreadType(ThreadType t) {}; -inline uint32_t GetThreadType(void) { return 0; } +inline JS_PUBLIC_API(uint32_t) GetThreadType(void) { return 0; } # endif } /* namespace oom */ diff --git a/ios/include/spidermonkey/jsalloc.h b/ios/include/spidermonkey/jsalloc.h index b9ae5190..6660b71d 100644 --- a/ios/include/spidermonkey/jsalloc.h +++ b/ios/include/spidermonkey/jsalloc.h @@ -49,7 +49,7 @@ class SystemAllocPolicy }; class ExclusiveContext; -void ReportOutOfMemory(ExclusiveContext* cxArg); +JS_PUBLIC_API(void) ReportOutOfMemory(ExclusiveContext* cxArg); /* * Allocation policy that calls the system memory functions and reports errors diff --git a/ios/libs/libjs_static.a b/ios/libs/libjs_static.a index d559f909..ad4eca10 100644 Binary files a/ios/libs/libjs_static.a and b/ios/libs/libjs_static.a differ diff --git a/ios/libs/libmozglue.a b/ios/libs/libmozglue.a index a40cf9e0..68a4fa13 100644 Binary files a/ios/libs/libmozglue.a and b/ios/libs/libmozglue.a differ diff --git a/sources/SocketRocket/Internal/Delegate/SRDelegateController.h b/sources/SocketRocket/Internal/Delegate/SRDelegateController.h index 7b230022..e1497cd0 100644 --- a/sources/SocketRocket/Internal/Delegate/SRDelegateController.h +++ b/sources/SocketRocket/Internal/Delegate/SRDelegateController.h @@ -33,11 +33,7 @@ typedef void(^SRDelegateBlock)(id _Nullable delegate, SRDel @property (nonatomic, weak) id delegate; @property (atomic, readonly) SRDelegateAvailableMethods availableDelegateMethods; -#if OS_OBJECT_USE_OBJC @property (nullable, nonatomic, strong) dispatch_queue_t dispatchQueue; -#else -@property (nullable, nonatomic, assign) dispatch_queue_t dispatchQueue; -#endif @property (nullable, nonatomic, strong) NSOperationQueue *operationQueue; ///-------------------------------------- diff --git a/sources/SocketRocket/Internal/IOConsumer/SRIOConsumerPool.h b/sources/SocketRocket/Internal/IOConsumer/SRIOConsumerPool.h index 1e7ad320..c11a1c4d 100644 --- a/sources/SocketRocket/Internal/IOConsumer/SRIOConsumerPool.h +++ b/sources/SocketRocket/Internal/IOConsumer/SRIOConsumerPool.h @@ -25,4 +25,6 @@ unmaskBytes:(BOOL)unmaskBytes; - (void)returnConsumer:(SRIOConsumer *)consumer; +- (void)clear; + @end diff --git a/sources/SocketRocket/Internal/IOConsumer/SRIOConsumerPool.m b/sources/SocketRocket/Internal/IOConsumer/SRIOConsumerPool.m index 2c527dae..1459e63b 100644 --- a/sources/SocketRocket/Internal/IOConsumer/SRIOConsumerPool.m +++ b/sources/SocketRocket/Internal/IOConsumer/SRIOConsumerPool.m @@ -61,4 +61,10 @@ } } +-(void)clear +{ + _poolSize = 0; + _bufferedConsumers = nil; +} + @end diff --git a/sources/SocketRocket/Internal/Proxy/SRProxyConnect.m b/sources/SocketRocket/Internal/Proxy/SRProxyConnect.m index 43cdfef4..cbf2eef9 100644 --- a/sources/SocketRocket/Internal/Proxy/SRProxyConnect.m +++ b/sources/SocketRocket/Internal/Proxy/SRProxyConnect.m @@ -234,11 +234,11 @@ [self _openConnection]; return; } - __weak __typeof__(self) wself = self; + __weak __typeof(self) wself = self; NSURLRequest *request = [NSURLRequest requestWithURL:PACurl]; NSURLSession *session = [NSURLSession sharedSession]; [[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { - __strong __typeof__(wself) sself = wself; + __strong __typeof(wself) sself = wself; if (!error) { NSString *script = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; [sself _runPACScript:script withProxySettings:proxySettings]; @@ -454,9 +454,9 @@ static NSTimeInterval const SRProxyConnectWriteTimeout = 5.0; { const uint8_t * bytes = data.bytes; __block NSInteger timeout = (NSInteger)(SRProxyConnectWriteTimeout * 1000000); // wait timeout before giving up - __weak __typeof__(self) wself = self; + __weak __typeof(self) wself = self; dispatch_async(_writeQueue, ^{ - __strong __typeof__(wself) sself = self; + __strong __typeof(wself) sself = self; if (!sself) { return; } diff --git a/sources/SocketRocket/SRWebSocket.m b/sources/SocketRocket/SRWebSocket.m index 8d226bf3..2f9f6660 100644 --- a/sources/SocketRocket/SRWebSocket.m +++ b/sources/SocketRocket/SRWebSocket.m @@ -295,6 +295,14 @@ NSString *const SRHTTPResponseErrorKey = @"HTTPResponseStatusCode"; return NO; } +-(void)_onTimeout +{ + if (self.readyState == SR_CONNECTING) { + NSError *error = SRErrorWithDomainCodeDescription(NSURLErrorDomain, NSURLErrorTimedOut, @"Timed out connecting to server."); + [self _failWithError:error]; + } +} + ///-------------------------------------- #pragma mark - Open / Close ///-------------------------------------- @@ -307,18 +315,12 @@ NSString *const SRHTTPResponseErrorKey = @"HTTPResponseStatusCode"; _selfRetain = self; if (_urlRequest.timeoutInterval > 0) { - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_urlRequest.timeoutInterval * NSEC_PER_SEC)); - dispatch_after(popTime, dispatch_get_main_queue(), ^{ - if (self.readyState == SR_CONNECTING) { - NSError *error = SRErrorWithDomainCodeDescription(NSURLErrorDomain, NSURLErrorTimedOut, @"Timed out connecting to server."); - [self _failWithError:error]; - } - }); + [self performSelector:@selector(_onTimeout) withObject:nil afterDelay:_urlRequest.timeoutInterval]; } _proxyConnect = [[SRProxyConnect alloc] initWithURL:_url]; - __weak __typeof__(self) wself = self; + __weak __typeof(self) wself = self; [_proxyConnect openNetworkStreamWithCompletion:^(NSError *error, NSInputStream *readStream, NSOutputStream *writeStream) { [wself _connectionDoneWithError:error readStream:readStream writeStream:writeStream]; }]; @@ -419,14 +421,23 @@ NSString *const SRHTTPResponseErrorKey = @"HTTPResponseStatusCode"; _receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO); } - [self _readUntilHeaderCompleteWithCallback:^(SRWebSocket *socket, NSData *data) { - CFHTTPMessageAppendBytes(_receivedHTTPHeaders, (const UInt8 *)data.bytes, data.length); + // Uses weak self object in the block, otherwise Consumers will retain SRWebSocket instance, + // and SRWebSocket instance also hold consumers, cycle reference will occur. + __weak __typeof(self) wself = self; - if (CFHTTPMessageIsHeaderComplete(_receivedHTTPHeaders)) { - SRDebugLog(@"Finished reading headers %@", CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_receivedHTTPHeaders))); - [self _HTTPHeadersDidFinish]; + [self _readUntilHeaderCompleteWithCallback:^(SRWebSocket *socket, NSData *data) { + + __strong __typeof(wself) sself = wself; + if (sself == nil) + return; + + CFHTTPMessageAppendBytes(sself.receivedHTTPHeaders, (const UInt8 *)data.bytes, data.length); + + if (CFHTTPMessageIsHeaderComplete(sself.receivedHTTPHeaders)) { + SRDebugLog(@"Finished reading headers %@", CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(sself.receivedHTTPHeaders))); + [sself _HTTPHeadersDidFinish]; } else { - [self _readHTTPHeader]; + [sself _readHTTPHeader]; } }]; } @@ -1127,6 +1138,16 @@ static const uint8_t SRPayloadLenMask = 0x7F; _cleanupScheduled = YES; + // _consumers retain SRWebSocket instance by block copy, if there are consumers here, clear them. + [_consumers removeAllObjects]; + [_consumerPool clear]; + + // Cancel the timer which retains SRWebSocket instance. + // If we don't cancel the timer, the 'dealloc' method will be invoked only after the time (default: 60s) have come, which may cause memory increase. + dispatch_async(dispatch_get_main_queue(), ^(){ + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_onTimeout) object:nil]; + }); + // Cleanup NSStream delegate's in the same RunLoop used by the streams themselves: // This way we'll prevent race conditions between handleEvent and SRWebsocket's dealloc NSTimer *timer = [NSTimer timerWithTimeInterval:(0.0f) target:self selector:@selector(_cleanupSelfReference:) userInfo:nil repeats:NO]; @@ -1392,7 +1413,7 @@ static const size_t SRFrameHeaderOverhead = 32; - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { - __weak __typeof__(self) wself = self; + __weak __typeof(self) wself = self; if (_requestRequiresSSL && !_streamSecurityValidated && (eventCode == NSStreamEventHasBytesAvailable || eventCode == NSStreamEventHasSpaceAvailable)) {