From 95b94d6d10c03f23cf179ebffbc78dde5d618e25 Mon Sep 17 00:00:00 2001 From: jules Date: Tue, 29 May 2012 13:18:03 +0100 Subject: [PATCH] Fixes for OSX URL streams. --- modules/juce_core/native/juce_mac_Network.mm | 210 ++++++++----------- 1 file changed, 85 insertions(+), 125 deletions(-) diff --git a/modules/juce_core/native/juce_mac_Network.mm b/modules/juce_core/native/juce_mac_Network.mm index 79e576b5c4..9aeadef3d9 100644 --- a/modules/juce_core/native/juce_mac_Network.mm +++ b/modules/juce_core/native/juce_mac_Network.mm @@ -101,10 +101,10 @@ bool Process::openEmailWithAttachments (const String& targetEmailAddress, class URLConnectionState : public Thread { public: - URLConnectionState (NSObject* owner_, NSURLRequest* req) + URLConnectionState (NSURLRequest* req) : Thread ("http connection"), contentLength (-1), - owner (owner_), + delegate (nil), request ([req retain]), connection (nil), data ([[NSMutableData data] retain]), @@ -113,15 +113,19 @@ public: hasFailed (false), hasFinished (false) { + static DelegateClass cls; + delegate = [cls.createInstance() init]; + DelegateClass::setState (delegate, this); } ~URLConnectionState() { - stopThread (10000); + stop(); [connection release]; [data release]; [request release]; [headers release]; + [delegate release]; } bool start (URL::OpenStreamProgressCallback* callback, void* context) @@ -216,12 +220,12 @@ public: void run() { - NSUInteger oldRetainCount = [owner retainCount]; + NSUInteger oldRetainCount = [delegate retainCount]; connection = [[NSURLConnection alloc] initWithRequest: request - delegate: owner]; + delegate: delegate]; - if (oldRetainCount == [owner retainCount]) - [owner retain]; // newer SDK should already retain this, but there were problems in older versions.. + if (oldRetainCount == [delegate retainCount]) + [delegate retain]; // newer SDK should already retain this, but there were problems in older versions.. if (connection != nil) { @@ -235,7 +239,7 @@ public: int64 contentLength; CriticalSection dataLock; - NSObject* owner; + NSObject* delegate; NSURLRequest* request; NSURLConnection* connection; NSMutableData* data; @@ -243,64 +247,50 @@ public: bool initialised, hasFailed, hasFinished; private: - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState); -}; - -//============================================================================== -struct URLConnectionDelegateClass : public ObjCClass -{ - URLConnectionDelegateClass() : ObjCClass ("JUCEAppDelegate_") + //============================================================================== + struct DelegateClass : public ObjCClass { - addIvar ("state"); - - addMethod (@selector (dealloc), dealloc, "v@:"); - addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@"); - addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@"); - addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@"); - addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@"); + DelegateClass() : ObjCClass ("JUCEAppDelegate_") + { + addIvar ("state"); - registerClass(); - } + addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@"); + addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@"); + addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@"); + addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@"); - static void setState (id self, URLConnectionState* state) - { - object_setInstanceVariable (self, "state", state); - } + registerClass(); + } - static URLConnectionState* getState (id self) - { - return getIvar (self, "state"); - } + static void setState (id self, URLConnectionState* state) { object_setInstanceVariable (self, "state", state); } + static URLConnectionState* getState (id self) { return getIvar (self, "state"); } -private: - static void dealloc (id self, SEL sel) - { - getState (self)->stop(); - delete getState (self); - sendSuperclassMessage (self, @selector (dealloc)); - } + private: + static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response) + { + getState (self)->didReceiveResponse (response); + } - static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response) - { - getState (self)->didReceiveResponse (response); - } + static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error) + { + getState (self)->didFailWithError (error); + } - static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error) - { - getState (self)->didFailWithError (error); - } + static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData) + { + getState (self)->didReceiveData (newData); + } - static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData) - { - getState (self)->didReceiveData (newData); - } + static void connectionDidFinishLoading (id self, SEL, NSURLConnection*) + { + getState (self)->finishedLoading(); + } + }; - static void connectionDidFinishLoading (id self, SEL, NSURLConnection*) - { - getState (self)->finishedLoading(); - } + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState); }; + //============================================================================== class WebInputStream : public InputStream { @@ -308,37 +298,29 @@ public: WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_, URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, const String& headers_, int timeOutMs_, StringPairArray* responseHeaders) - : connection (nil), - address (address_), headers (headers_), postData (postData_), position (0), + : address (address_), headers (headers_), postData (postData_), position (0), finished (false), isPost (isPost_), timeOutMs (timeOutMs_) { JUCE_AUTORELEASEPOOL - connection = createConnection (progressCallback, progressCallbackContext); + createConnection (progressCallback, progressCallbackContext); - if (responseHeaders != nullptr && connection != nil) + if (responseHeaders != nullptr && connection != nullptr) { - URLConnectionState* const state = URLConnectionDelegateClass::getState (connection); - - if (state->headers != nil) + if (connection->headers != nil) { - NSEnumerator* enumerator = [state->headers keyEnumerator]; + NSEnumerator* enumerator = [connection->headers keyEnumerator]; NSString* key; while ((key = [enumerator nextObject]) != nil) responseHeaders->set (nsStringToJuce (key), - nsStringToJuce ((NSString*) [state->headers objectForKey: key])); + nsStringToJuce ((NSString*) [connection->headers objectForKey: key])); } } } - ~WebInputStream() - { - close(); - } - //============================================================================== - bool isError() const { return connection == nil; } - int64 getTotalLength() { return connection == nil ? -1 : URLConnectionDelegateClass::getState (connection)->contentLength; } + bool isError() const { return connection == nullptr; } + int64 getTotalLength() { return connection == nullptr ? -1 : connection->contentLength; } bool isExhausted() { return finished; } int64 getPosition() { return position; } @@ -347,23 +329,17 @@ public: jassert (buffer != nullptr && bytesToRead >= 0); if (finished || isError()) - { return 0; - } - else - { - JUCE_AUTORELEASEPOOL - URLConnectionState* const state = URLConnectionDelegateClass::getState (connection); + JUCE_AUTORELEASEPOOL - const int bytesRead = state->read (static_cast (buffer), bytesToRead); - position += bytesRead; + const int bytesRead = connection->read (static_cast (buffer), bytesToRead); + position += bytesRead; - if (bytesRead == 0) - finished = true; + if (bytesRead == 0) + finished = true; - return bytesRead; - } + return bytesRead; } bool setPosition (int64 wantedPos) @@ -374,9 +350,9 @@ public: if (wantedPos < position) { - close(); + connection = nullptr; position = 0; - connection = createConnection (0, 0); + createConnection (0, 0); } skipNextBytes (wantedPos - position); @@ -385,9 +361,8 @@ public: return true; } - //============================================================================== private: - NSObject* connection; + ScopedPointer connection; String address, headers; MemoryBlock postData; int64 position; @@ -395,57 +370,42 @@ private: const bool isPost; const int timeOutMs; - void close() + void createConnection (URL::OpenStreamProgressCallback* progressCallback, + void* progressCallbackContext) { - if (connection != nil) - { - URLConnectionDelegateClass::getState (connection)->stop(); - [connection release]; - connection = nil; - } - } + jassert (connection == nullptr); - NSObject* createConnection (URL::OpenStreamProgressCallback* progressCallback, - void* progressCallbackContext) - { NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: juceStringToNS (address)] cachePolicy: NSURLRequestReloadIgnoringLocalCacheData timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)]; - if (req == nil) - return nil; - - [req setHTTPMethod: nsStringLiteral (isPost ? "POST" : "GET")]; - //[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData]; - - StringArray headerLines; - headerLines.addLines (headers); - headerLines.removeEmptyStrings (true); - - for (int i = 0; i < headerLines.size(); ++i) + if (req != nil) { - const String key (headerLines[i].upToFirstOccurrenceOf (":", false, false).trim()); - const String value (headerLines[i].fromFirstOccurrenceOf (":", false, false).trim()); + [req setHTTPMethod: nsStringLiteral (isPost ? "POST" : "GET")]; + //[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData]; - if (key.isNotEmpty() && value.isNotEmpty()) - [req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)]; - } + StringArray headerLines; + headerLines.addLines (headers); + headerLines.removeEmptyStrings (true); - if (isPost && postData.getSize() > 0) - [req setHTTPBody: [NSData dataWithBytes: postData.getData() - length: postData.getSize()]]; + 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()); - static URLConnectionDelegateClass cls; - NSObject* const s = [cls.createInstance() init]; + if (key.isNotEmpty() && value.isNotEmpty()) + [req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)]; + } - URLConnectionState* state = new URLConnectionState (s, req); - URLConnectionDelegateClass::setState (s, state); + if (isPost && postData.getSize() > 0) + [req setHTTPBody: [NSData dataWithBytes: postData.getData() + length: postData.getSize()]]; - if (state->start (progressCallback, progressCallbackContext)) - return s; + connection = new URLConnectionState (req); - [s release]; - return nil; + if (! connection->start (progressCallback, progressCallbackContext)) + connection = nullptr; + } } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream);