Browse Source

Refactored the OSX/iOS HTTP streaming code to use the newer NSURLSession API, and not older now-deprecated functions.

tags/2021-05-28
jules 9 years ago
parent
commit
f8516f2e19
1 changed files with 63 additions and 70 deletions
  1. +63
    -70
      modules/juce_core/native/juce_mac_Network.mm

+ 63
- 70
modules/juce_core/native/juce_mac_Network.mm View File

@@ -35,6 +35,7 @@ void MACAddress::findAllAddresses (Array<MACAddress>& result)
for (const ifaddrs* cursor = addrs; cursor != nullptr; cursor = cursor->ifa_next) for (const ifaddrs* cursor = addrs; cursor != nullptr; cursor = cursor->ifa_next)
{ {
sockaddr_storage* sto = (sockaddr_storage*) cursor->ifa_addr; sockaddr_storage* sto = (sockaddr_storage*) cursor->ifa_addr;
if (sto->ss_family == AF_LINK) if (sto->ss_family == AF_LINK)
{ {
const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr; const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
@@ -45,7 +46,7 @@ void MACAddress::findAllAddresses (Array<MACAddress>& result)
if (sadd->sdl_type == IFT_ETHER) 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()) if (! ma.isNull())
result.addIfNotAlreadyThere (ma); result.addIfNotAlreadyThere (ma);
@@ -109,7 +110,7 @@ bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailA
} }
//============================================================================== //==============================================================================
class URLConnectionState : public Thread
class URLConnectionState : private Thread
{ {
public: public:
URLConnectionState (NSURLRequest* req, const int maxRedirects) URLConnectionState (NSURLRequest* req, const int maxRedirects)
@@ -117,7 +118,8 @@ public:
contentLength (-1), contentLength (-1),
delegate (nil), delegate (nil),
request ([req retain]), request ([req retain]),
connection (nil),
session (nil),
task (nil),
data ([[NSMutableData data] retain]), data ([[NSMutableData data] retain]),
headers (nil), headers (nil),
statusCode (0), statusCode (0),
@@ -136,10 +138,10 @@ public:
~URLConnectionState() ~URLConnectionState()
{ {
stop(); stop();
[connection release];
[data release]; [data release];
[request release]; [request release];
[headers release]; [headers release];
[session release];
[delegate release]; [delegate release];
} }
@@ -150,18 +152,20 @@ public:
while (isThreadRunning() && ! initialised) while (isThreadRunning() && ! initialised)
{ {
if (callback != nullptr) if (callback != nullptr)
callback (context, latestTotalBytes, (int) [[request HTTPBody] length]);
callback (context, (int) latestTotalBytes, (int) [[request HTTPBody] length]);
Thread::sleep (1); Thread::sleep (1);
} }
return connection != nil && ! hasFailed;
return true;
} }
void stop() void stop()
{ {
[connection cancel];
[task cancel];
stopThread (10000); stopThread (10000);
[task release];
task = nil;
} }
int read (char* dest, int numBytes) int read (char* dest, int numBytes)
@@ -194,7 +198,7 @@ public:
return numDone; return numDone;
} }
void didReceiveResponse (NSURLResponse* response)
void didReceiveResponse (NSURLResponse* response, id completionHandler)
{ {
{ {
const ScopedLock sl (dataLock); const ScopedLock sl (dataLock);
@@ -214,22 +218,17 @@ public:
} }
initialised = true; 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); DBG (nsStringToJuce ([error description])); ignoreUnused (error);
hasFailed = true; hasFailed = true;
@@ -244,60 +243,67 @@ public:
initialised = true; initialised = true;
} }
void didSendBodyData (NSInteger totalBytesWritten, NSInteger /*totalBytesExpected*/)
void didSendBodyData (int64_t totalBytesWritten)
{ {
latestTotalBytes = static_cast<int> (totalBytesWritten); latestTotalBytes = static_cast<int> (totalBytesWritten);
} }
void finishedLoading()
{
hasFinished = true;
initialised = true;
signalThreadShouldExit();
}
void run() override 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()) while (! threadShouldExit())
{ {
JUCE_AUTORELEASEPOOL
{
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
}
wait (5);
if (task.state != NSURLSessionTaskStateRunning)
break;
} }
hasFinished = true;
initialised = true;
} }
int64 contentLength; int64 contentLength;
CriticalSection dataLock; CriticalSection dataLock;
NSObject* delegate;
id delegate;
NSURLRequest* request; NSURLRequest* request;
NSURLConnection* connection;
NSURLSession* session;
NSURLSessionTask* task;
NSMutableData* data; NSMutableData* data;
NSDictionary* headers; NSDictionary* headers;
int statusCode; int statusCode;
bool initialised, hasFailed, hasFinished; bool initialised, hasFailed, hasFinished;
const int numRedirectsToFollow; const int numRedirectsToFollow;
int numRedirects; int numRedirects;
int latestTotalBytes;
int64 latestTotalBytes;
private: private:
//============================================================================== //==============================================================================
struct DelegateClass : public ObjCClass<NSObject> struct DelegateClass : public ObjCClass<NSObject>
{ {
DelegateClass() : ObjCClass<NSObject> ("JUCEAppDelegate_")
DelegateClass() : ObjCClass<NSObject> ("JUCE_URLDelegate_")
{ {
addIvar<URLConnectionState*> ("state"); addIvar<URLConnectionState*> ("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(); registerClass();
} }
@@ -305,34 +311,24 @@ private:
static URLConnectionState* getState (id self) { return getIvar<URLConnectionState*> (self, "state"); } static URLConnectionState* getState (id self) { return getIvar<URLConnectionState*> (self, "state"); }
private: 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); 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); 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 setHTTPMethod: [NSString stringWithUTF8String: httpRequestCmd.toRawUTF8()]];
//[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
StringArray headerLines; StringArray headerLines;
headerLines.addLines (headers); headerLines.addLines (headers);
@@ -448,8 +441,8 @@ private:
for (int i = 0; i < headerLines.size(); ++i) 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()) if (key.isNotEmpty() && value.isNotEmpty())
[req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)]; [req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)];


Loading…
Cancel
Save