diff --git a/v2/internal/frontend/desktop/darwin/Application.h b/v2/internal/frontend/desktop/darwin/Application.h index 7e53c36e..22304f4f 100644 --- a/v2/internal/frontend/desktop/darwin/Application.h +++ b/v2/internal/frontend/desktop/darwin/Application.h @@ -45,7 +45,7 @@ void Quit(void*); const char* GetSize(void *ctx); const char* GetPosition(void *ctx); -void ProcessURLResponse(void *inctx, const char *url, int statusCode, void *headersString, int headersStringLength, void* data, int datalength); +void ProcessURLResponse(void *inctx, unsigned long long requestId, int statusCode, void *headersString, int headersStringLength, void* data, int datalength); /* Dialogs */ diff --git a/v2/internal/frontend/desktop/darwin/Application.m b/v2/internal/frontend/desktop/darwin/Application.m index ddb39716..18db2b3d 100644 --- a/v2/internal/frontend/desktop/darwin/Application.m +++ b/v2/internal/frontend/desktop/darwin/Application.m @@ -51,16 +51,13 @@ WailsContext* Create(const char* title, int width, int height, int frameless, in return result; } -void ProcessURLResponse(void *inctx, const char *url, int statusCode, void *headersString, int headersStringLength, void* data, int datalength) { +void ProcessURLResponse(void *inctx, unsigned long long requestId, int statusCode, void *headersString, int headersStringLength, void* data, int datalength) { WailsContext *ctx = (__bridge WailsContext*) inctx; - NSString *nsurl = safeInit(url); - NSData *nsHeadersJSON = [NSData dataWithBytes:headersString length:headersStringLength]; - NSData *nsdata = [NSData dataWithBytes:data length:datalength]; - - [ctx processURLResponse:nsurl :statusCode :nsHeadersJSON :nsdata]; - - [nsdata release]; - [nsHeadersJSON release]; + @autoreleasepool { + NSData *nsHeadersJSON = [NSData dataWithBytes:headersString length:headersStringLength]; + NSData *nsdata = [NSData dataWithBytes:data length:datalength]; + [ctx processURLResponse:requestId :statusCode :nsHeadersJSON :nsdata]; + } } void ExecJS(void* inctx, const char *script) { diff --git a/v2/internal/frontend/desktop/darwin/WailsContext.h b/v2/internal/frontend/desktop/darwin/WailsContext.h index 4325e5fb..d0034d8b 100644 --- a/v2/internal/frontend/desktop/darwin/WailsContext.h +++ b/v2/internal/frontend/desktop/darwin/WailsContext.h @@ -47,6 +47,8 @@ @property bool debug; @property (retain) WKUserContentController* userContentController; +@property (retain) NSLock *urlRequestsLock; +@property unsigned long long urlRequestsId; @property (retain) NSMutableDictionary *urlRequests; @property (retain) NSMenu* applicationMenu; @@ -84,7 +86,7 @@ - (void) SaveFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(NSString*)filters; - (void) loadRequest:(NSString*)url; -- (void) processURLResponse:(NSString *)url :(int)statusCode :(NSData *)headersString :(NSData*)data; +- (void) processURLResponse:(unsigned long long)requestId :(int)statusCode :(NSData *)headersString :(NSData*)data; - (void) ExecJS:(NSString*)script; - (NSScreen*) getCurrentScreen; diff --git a/v2/internal/frontend/desktop/darwin/WailsContext.m b/v2/internal/frontend/desktop/darwin/WailsContext.m index f92fb314..a6599b81 100644 --- a/v2/internal/frontend/desktop/darwin/WailsContext.m +++ b/v2/internal/frontend/desktop/darwin/WailsContext.m @@ -106,6 +106,7 @@ [self.mouseEvent release]; [self.userContentController release]; [self.urlRequests release]; + [self.urlRequestsLock release]; [self.applicationMenu release]; [super dealloc]; } @@ -135,7 +136,8 @@ } - (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(NSString*)appearance :(bool)windowIsTranslucent :(int)minWidth :(int)minHeight :(int)maxWidth :(int)maxHeight { - + self.urlRequestsId = 0; + self.urlRequestsLock = [NSLock new]; self.urlRequests = [NSMutableDictionary new]; NSWindowStyleMask styleMask = 0; @@ -394,24 +396,41 @@ [self.webview evaluateJavaScript:script completionHandler:nil]; } -- (void) processURLResponse:(NSString *)url :(int)statusCode :(NSData *)headersJSON :(NSData *)data { - id urlSchemeTask = self.urlRequests[url]; - NSURL *nsurl = [NSURL URLWithString:url]; - NSDictionary *headerFields = [NSJSONSerialization JSONObjectWithData: headersJSON options: NSJSONReadingMutableContainers error: nil]; - NSHTTPURLResponse *response = [[NSHTTPURLResponse new] initWithURL:nsurl statusCode:statusCode HTTPVersion:@"HTTP/1.1" headerFields:headerFields]; - [urlSchemeTask didReceiveResponse:response]; - [urlSchemeTask didReceiveData:data]; - [urlSchemeTask didFinish]; - [self.urlRequests removeObjectForKey:url]; - [response release]; - if (headerFields != nil) { - [headerFields release]; +- (void) processURLResponse:(unsigned long long)requestId :(int)statusCode :(NSData *)headersJSON :(NSData *)data { + NSNumber *key = [NSNumber numberWithUnsignedLongLong:requestId]; + + [self.urlRequestsLock lock]; + id urlSchemeTask = self.urlRequests[key]; + [self.urlRequestsLock unlock]; + + @try { + if (urlSchemeTask == nil) { + return; + } + + NSDictionary *headerFields = [NSJSONSerialization JSONObjectWithData: headersJSON options: NSJSONReadingMutableContainers error: nil]; + NSHTTPURLResponse *response = [[[NSHTTPURLResponse alloc] initWithURL:urlSchemeTask.request.URL statusCode:statusCode HTTPVersion:@"HTTP/1.1" headerFields:headerFields] autorelease]; + + @try { + [urlSchemeTask didReceiveResponse:response]; + [urlSchemeTask didReceiveData:data]; + [urlSchemeTask didFinish]; + } @catch (NSException *exception) { + // This is very bad to detect a stopped schemeTask this should be implemented in a better way + // See todo in stopURLSchemeTask... + if (![exception.reason isEqualToString: @"This task has already been stopped"]) { + @throw exception; + } + } + } @finally { + [self.urlRequestsLock lock]; + [self.urlRequests removeObjectForKey:key]; // This will release the urlSchemeTask which was retained from the dictionary + [self.urlRequestsLock unlock]; } } - (void)webView:(nonnull WKWebView *)webView startURLSchemeTask:(nonnull id)urlSchemeTask { // This callback is run with an autorelease pool - self.urlRequests[urlSchemeTask.request.URL.absoluteString] = urlSchemeTask; const char *url = [urlSchemeTask.request.URL.absoluteString UTF8String]; const char *method = [urlSchemeTask.request.HTTPMethod UTF8String]; const char *headerJSON = ""; @@ -431,11 +450,19 @@ // TODO handle HTTPBodyStream } - processURLRequest(self, url, method, headerJSON, body, bodyLen); + [self.urlRequestsLock lock]; + self.urlRequestsId++; + unsigned long long requestId = self.urlRequestsId; + NSNumber *key = [NSNumber numberWithUnsignedLongLong:requestId]; + self.urlRequests[key] = urlSchemeTask; + [self.urlRequestsLock unlock]; + + processURLRequest(self, requestId, url, method, headerJSON, body, bodyLen); } - (void)webView:(nonnull WKWebView *)webView stopURLSchemeTask:(nonnull id)urlSchemeTask { - + // TODO implement the stopping process here in a better way... + // As soon as we introduce response body streaming we need to rewrite this nevertheless. } - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { diff --git a/v2/internal/frontend/desktop/darwin/frontend.go b/v2/internal/frontend/desktop/darwin/frontend.go index 75df093b..842301a9 100644 --- a/v2/internal/frontend/desktop/darwin/frontend.go +++ b/v2/internal/frontend/desktop/darwin/frontend.go @@ -350,9 +350,7 @@ func (f *Frontend) processRequest(r *request) { headersLen = len(headerData) } - url := C.CString(r.url) - defer C.free(unsafe.Pointer(url)) - C.ProcessURLResponse(r.ctx, url, C.int(rw.Code), headers, C.int(headersLen), content, C.int(contentLen)) + C.ProcessURLResponse(r.ctx, r.id, C.int(rw.Code), headers, C.int(headersLen), content, C.int(contentLen)) } //func (f *Frontend) processSystemEvent(message string) { @@ -372,6 +370,7 @@ func (f *Frontend) processRequest(r *request) { //} type request struct { + id C.ulonglong url string method string headers string @@ -412,13 +411,14 @@ func processMessage(message *C.char) { } //export processURLRequest -func processURLRequest(ctx unsafe.Pointer, url *C.char, method *C.char, headers *C.char, body unsafe.Pointer, bodyLen C.int) { +func processURLRequest(ctx unsafe.Pointer, requestId C.ulonglong, url *C.char, method *C.char, headers *C.char, body unsafe.Pointer, bodyLen C.int) { var goBody []byte if body != nil && bodyLen != 0 { goBody = C.GoBytes(body, bodyLen) } requestBuffer <- &request{ + id: requestId, url: C.GoString(url), method: C.GoString(method), headers: C.GoString(headers), diff --git a/v2/internal/frontend/desktop/darwin/main.m b/v2/internal/frontend/desktop/darwin/main.m index 154c3306..5f4618d1 100644 --- a/v2/internal/frontend/desktop/darwin/main.m +++ b/v2/internal/frontend/desktop/darwin/main.m @@ -29,11 +29,11 @@ void processCallback(int callbackID) { NSLog(@"Process callback %d", callbackID); } -void processURLRequest(void *ctx, const char* url const char *method, const char *headers, const void *body, int bodyLen) { +void processURLRequest(void *ctx, unsigned long long requestId, const char* url, const char *method, const char *headers, const void *body, int bodyLen) { NSLog(@"processURLRequest called"); const char myByteArray[] = { 0x3c,0x68,0x31,0x3e,0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64,0x21,0x3c,0x2f,0x68,0x31,0x3e }; // void *inctx, const char *url, int statusCode, const char *headers, void* data, int datalength - ProcessURLResponse(ctx, url, 200, "{\"Content-Type\": \"text/html\"}", (void*)myByteArray, 21); + ProcessURLResponse(ctx, requestId, 200, "{\"Content-Type\": \"text/html\"}", (void*)myByteArray, 21); } unsigned char _Users_username_Pictures_SaltBae_png[] = { diff --git a/v2/internal/frontend/desktop/darwin/message.h b/v2/internal/frontend/desktop/darwin/message.h index f0a5f482..b3405f4a 100644 --- a/v2/internal/frontend/desktop/darwin/message.h +++ b/v2/internal/frontend/desktop/darwin/message.h @@ -15,7 +15,7 @@ extern "C" #endif void processMessage(const char *); -void processURLRequest(void*, const char *, const char *, const char *, const void *, int); +void processURLRequest(void*, unsigned long long, const char *, const char *, const char *, const void *, int); void processMessageDialogResponse(int); void processOpenFileDialogResponse(const char*); void processSaveFileDialogResponse(const char*);