5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-03 01:30:32 +08:00

[v2, darwin] Assign a unique requestId to every WKWebView request (#1681)

This makes sure we always use the correct WKURLSchemeTask during
processURLResponse. Only using the URL is not unique enough and
might result in pending requests if two requests with the same URL
are getting processed.
This commit is contained in:
stffabi 2022-08-01 10:55:25 +02:00 committed by GitHub
parent d5574ba9d7
commit 3d24a9b4c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 60 additions and 34 deletions

View File

@ -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 */

View File

@ -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) {

View File

@ -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;

View File

@ -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<WKURLSchemeTask> 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<WKURLSchemeTask> 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<WKURLSchemeTask>)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<WKURLSchemeTask>)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 {

View File

@ -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),

View File

@ -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[] = {

View File

@ -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*);