Browse Source

Fixes for OSX URL streams.

tags/2021-05-28
jules 13 years ago
parent
commit
95b94d6d10
1 changed files with 85 additions and 125 deletions
  1. +85
    -125
      modules/juce_core/native/juce_mac_Network.mm

+ 85
- 125
modules/juce_core/native/juce_mac_Network.mm View File

@@ -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<NSObject>
{
URLConnectionDelegateClass() : ObjCClass ("JUCEAppDelegate_")
//==============================================================================
struct DelegateClass : public ObjCClass<NSObject>
{
addIvar <URLConnectionState*> ("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 <URLConnectionState*> ("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<URLConnectionState*> (self, "state");
}
static void setState (id self, URLConnectionState* state) { object_setInstanceVariable (self, "state", state); }
static URLConnectionState* getState (id self) { return getIvar<URLConnectionState*> (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 <char*> (buffer), bytesToRead);
position += bytesRead;
const int bytesRead = connection->read (static_cast <char*> (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<URLConnectionState> 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);


Loading…
Cancel
Save