From f8516f2e191bd47cd46d47722070db40aacfaeef Mon Sep 17 00:00:00 2001 From: jules Date: Wed, 22 Jun 2016 16:12:09 +0100 Subject: [PATCH] Refactored the OSX/iOS HTTP streaming code to use the newer NSURLSession API, and not older now-deprecated functions. --- modules/juce_core/native/juce_mac_Network.mm | 133 +++++++++---------- 1 file changed, 63 insertions(+), 70 deletions(-) diff --git a/modules/juce_core/native/juce_mac_Network.mm b/modules/juce_core/native/juce_mac_Network.mm index f14adc744c..cd1fa5efa0 100644 --- a/modules/juce_core/native/juce_mac_Network.mm +++ b/modules/juce_core/native/juce_mac_Network.mm @@ -35,6 +35,7 @@ void MACAddress::findAllAddresses (Array& result) for (const ifaddrs* cursor = addrs; cursor != nullptr; cursor = cursor->ifa_next) { sockaddr_storage* sto = (sockaddr_storage*) cursor->ifa_addr; + if (sto->ss_family == AF_LINK) { const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr; @@ -45,7 +46,7 @@ void MACAddress::findAllAddresses (Array& result) if (sadd->sdl_type == IFT_ETHER) { - MACAddress ma (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen)); + MACAddress ma (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen); if (! ma.isNull()) result.addIfNotAlreadyThere (ma); @@ -109,7 +110,7 @@ bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailA } //============================================================================== -class URLConnectionState : public Thread +class URLConnectionState : private Thread { public: URLConnectionState (NSURLRequest* req, const int maxRedirects) @@ -117,7 +118,8 @@ public: contentLength (-1), delegate (nil), request ([req retain]), - connection (nil), + session (nil), + task (nil), data ([[NSMutableData data] retain]), headers (nil), statusCode (0), @@ -136,10 +138,10 @@ public: ~URLConnectionState() { stop(); - [connection release]; [data release]; [request release]; [headers release]; + [session release]; [delegate release]; } @@ -150,18 +152,20 @@ public: while (isThreadRunning() && ! initialised) { if (callback != nullptr) - callback (context, latestTotalBytes, (int) [[request HTTPBody] length]); + callback (context, (int) latestTotalBytes, (int) [[request HTTPBody] length]); Thread::sleep (1); } - return connection != nil && ! hasFailed; + return true; } void stop() { - [connection cancel]; + [task cancel]; stopThread (10000); + [task release]; + task = nil; } int read (char* dest, int numBytes) @@ -194,7 +198,7 @@ public: return numDone; } - void didReceiveResponse (NSURLResponse* response) + void didReceiveResponse (NSURLResponse* response, id completionHandler) { { const ScopedLock sl (dataLock); @@ -214,22 +218,17 @@ public: } initialised = true; - } - NSURLRequest* willSendRequest (NSURLRequest* newRequest, NSURLResponse* redirectResponse) - { - if (redirectResponse != nullptr) + if (completionHandler != nil) { - if (numRedirects >= numRedirectsToFollow) - return nil; // Cancel redirect and allow connection to continue - - ++numRedirects; + // Need to wrangle this parameter back into an obj-C block, + // and call it to allow the transfer to continue.. + void (^callbackBlock)(NSURLSessionResponseDisposition) = completionHandler; + callbackBlock (NSURLSessionResponseAllow); } - - return newRequest; } - void didFailWithError (NSError* error) + void didBecomeInvalidWithError (NSError* error) { DBG (nsStringToJuce ([error description])); ignoreUnused (error); hasFailed = true; @@ -244,60 +243,67 @@ public: initialised = true; } - void didSendBodyData (NSInteger totalBytesWritten, NSInteger /*totalBytesExpected*/) + void didSendBodyData (int64_t totalBytesWritten) { latestTotalBytes = static_cast (totalBytesWritten); } - void finishedLoading() - { - hasFinished = true; - initialised = true; - signalThreadShouldExit(); - } - void run() override { - connection = [[NSURLConnection alloc] initWithRequest: request - delegate: delegate]; + jassert (task == nil && session == nil); + + session = [[NSURLSession sessionWithConfiguration: [NSURLSessionConfiguration defaultSessionConfiguration] + delegate: delegate + delegateQueue: [NSOperationQueue currentQueue]] retain]; + + task = [session dataTaskWithRequest: request]; + + if (task == nil) + return; + + [task retain]; + [task resume]; + while (! threadShouldExit()) { - JUCE_AUTORELEASEPOOL - { - [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; - } + wait (5); + + if (task.state != NSURLSessionTaskStateRunning) + break; } + + hasFinished = true; + initialised = true; } int64 contentLength; CriticalSection dataLock; - NSObject* delegate; + id delegate; NSURLRequest* request; - NSURLConnection* connection; + NSURLSession* session; + NSURLSessionTask* task; NSMutableData* data; NSDictionary* headers; int statusCode; bool initialised, hasFailed, hasFinished; const int numRedirectsToFollow; int numRedirects; - int latestTotalBytes; + int64 latestTotalBytes; private: //============================================================================== struct DelegateClass : public ObjCClass { - DelegateClass() : ObjCClass ("JUCEAppDelegate_") + DelegateClass() : ObjCClass ("JUCE_URLDelegate_") { addIvar ("state"); - addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@"); - addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@"); - addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@"); - addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:), - connectionDidSendBodyData, "v@:@iii"); - addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@"); - addMethod (@selector (connection:willSendRequest:redirectResponse:), willSendRequest, "@@:@@@"); - + addMethod (@selector (URLSession:dataTask:didReceiveResponse:completionHandler:), + didReceiveResponse, "v@:@@@@"); + addMethod (@selector (URLSession:didBecomeInvalidWithError:), didBecomeInvalidWithError, "v@:@@"); + addMethod (@selector (URLSession:dataTask:didReceiveData:), didReceiveData, "v@:@@@"); + addMethod (@selector (URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:), + didSendBodyData, "v@:@@qqq"); registerClass(); } @@ -305,34 +311,24 @@ private: static URLConnectionState* getState (id self) { return getIvar (self, "state"); } private: - static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response) + static void didReceiveResponse (id self, SEL, NSURLSession*, NSURLSessionDataTask*, NSURLResponse* response, id completionHandler) { - getState (self)->didReceiveResponse (response); + getState (self)->didReceiveResponse (response, completionHandler); } - static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error) + static void didBecomeInvalidWithError (id self, SEL, NSURLSession*, NSError* error) { - getState (self)->didFailWithError (error); + getState (self)->didBecomeInvalidWithError (error); } - static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData) + static void didReceiveData (id self, SEL, NSURLSession*, NSURLSessionDataTask*, NSData* newData) { getState (self)->didReceiveData (newData); } - static NSURLRequest* willSendRequest (id self, SEL, NSURLConnection*, NSURLRequest* request, NSURLResponse* response) + static void didSendBodyData (id self, SEL, NSURLSession*, NSURLSessionTask*, int64_t, int64_t totalBytesWritten, int64_t) { - return getState (self)->willSendRequest (request, response); - } - - static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected) - { - getState (self)->didSendBodyData (totalBytesWritten, totalBytesExpected); - } - - static void connectionDidFinishLoading (id self, SEL, NSURLConnection*) - { - getState (self)->finishedLoading(); + getState (self)->didSendBodyData (totalBytesWritten); } }; @@ -433,14 +429,11 @@ private: { jassert (connection == nullptr); - NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: juceStringToNS (address)] - cachePolicy: NSURLRequestReloadIgnoringLocalCacheData - timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)]; - - if (req != nil) + if (NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: juceStringToNS (address)] + cachePolicy: NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)]) { [req setHTTPMethod: [NSString stringWithUTF8String: httpRequestCmd.toRawUTF8()]]; - //[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData]; StringArray headerLines; headerLines.addLines (headers); @@ -448,8 +441,8 @@ private: for (int i = 0; i < headerLines.size(); ++i) { - const String key (headerLines[i].upToFirstOccurrenceOf (":", false, false).trim()); - const String value (headerLines[i].fromFirstOccurrenceOf (":", false, false).trim()); + String key = headerLines[i].upToFirstOccurrenceOf (":", false, false).trim(); + String value = headerLines[i].fromFirstOccurrenceOf (":", false, false).trim(); if (key.isNotEmpty() && value.isNotEmpty()) [req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)];