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:
parent
d5574ba9d7
commit
3d24a9b4c4
@ -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 */
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
|
@ -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[] = {
|
||||
|
@ -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*);
|
||||
|
Loading…
Reference in New Issue
Block a user