From d827aafe8907b4612f1cb532b59f0ec3f78eaf6c Mon Sep 17 00:00:00 2001 From: stffabi Date: Fri, 3 Dec 2021 16:40:42 +0100 Subject: [PATCH] [v2] Improve processRequest: Handle errors and behave more like a webserver This also fixes that requests remain in "pending" state on darwin if e.g. a file is not found or an error occurs during loading of the file. --- .../frontend/desktop/darwin/Application.h | 2 +- .../frontend/desktop/darwin/Application.m | 4 +- .../frontend/desktop/darwin/WailsContext.h | 2 +- .../frontend/desktop/darwin/WailsContext.m | 8 ++-- .../frontend/desktop/darwin/frontend.go | 33 +++++++++---- .../frontend/desktop/linux/frontend.go | 5 +- .../frontend/desktop/windows/frontend.go | 47 +++++++++++++------ 7 files changed, 69 insertions(+), 32 deletions(-) diff --git a/v2/internal/frontend/desktop/darwin/Application.h b/v2/internal/frontend/desktop/darwin/Application.h index 38e4cebc5..1c96abe57 100644 --- a/v2/internal/frontend/desktop/darwin/Application.h +++ b/v2/internal/frontend/desktop/darwin/Application.h @@ -41,7 +41,7 @@ void Quit(void*); const char* GetSize(void *ctx); const char* GetPos(void *ctx); -void ProcessURLResponse(void *inctx, const char *url, const char *contentType, void* data, int datalength); +void ProcessURLResponse(void *inctx, const char *url, int statusCode, const char *contentType, void* data, int datalength); /* Dialogs */ diff --git a/v2/internal/frontend/desktop/darwin/Application.m b/v2/internal/frontend/desktop/darwin/Application.m index 8c5d93d15..14932c319 100644 --- a/v2/internal/frontend/desktop/darwin/Application.m +++ b/v2/internal/frontend/desktop/darwin/Application.m @@ -51,13 +51,13 @@ WailsContext* Create(const char* title, int width, int height, int frameless, in return result; } -void ProcessURLResponse(void *inctx, const char *url, const char *contentType, void* data, int datalength) { +void ProcessURLResponse(void *inctx, const char *url, int statusCode, const char *contentType, void* data, int datalength) { WailsContext *ctx = (__bridge WailsContext*) inctx; NSString *nsurl = safeInit(url); NSString *nsContentType = safeInit(contentType); NSData *nsdata = [NSData dataWithBytes:data length:datalength]; - [ctx processURLResponse:nsurl :nsContentType :nsdata]; + [ctx processURLResponse:nsurl :statusCode :nsContentType :nsdata]; [nsdata release]; } diff --git a/v2/internal/frontend/desktop/darwin/WailsContext.h b/v2/internal/frontend/desktop/darwin/WailsContext.h index f7ae2b72e..5a47a8ef2 100644 --- a/v2/internal/frontend/desktop/darwin/WailsContext.h +++ b/v2/internal/frontend/desktop/darwin/WailsContext.h @@ -79,7 +79,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 :(NSString *)contentType :(NSData*)data; +- (void) processURLResponse:(NSString *)url :(int)statusCode :(NSString *)contentType :(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 2d4e07b5c..3124c59a1 100644 --- a/v2/internal/frontend/desktop/darwin/WailsContext.m +++ b/v2/internal/frontend/desktop/darwin/WailsContext.m @@ -376,12 +376,14 @@ [self.webview evaluateJavaScript:script completionHandler:nil]; } -- (void) processURLResponse:(NSString *)url :(NSString *)contentType :(NSData *)data { +- (void) processURLResponse:(NSString *)url :(int)statusCode :(NSString *)contentType :(NSData *)data { id urlSchemeTask = self.urlRequests[url]; NSURL *nsurl = [NSURL URLWithString:url]; NSMutableDictionary *headerFields = [NSMutableDictionary new]; - headerFields[@"content-type"] = contentType; - NSHTTPURLResponse *response = [[NSHTTPURLResponse new] initWithURL:nsurl statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:headerFields]; + if ( ![contentType isEqualToString:@""] ) { + headerFields[@"content-type"] = contentType; + } + NSHTTPURLResponse *response = [[NSHTTPURLResponse new] initWithURL:nsurl statusCode:statusCode HTTPVersion:@"HTTP/1.1" headerFields:headerFields]; [urlSchemeTask didReceiveResponse:response]; [urlSchemeTask didReceiveData:data]; [urlSchemeTask didFinish]; diff --git a/v2/internal/frontend/desktop/darwin/frontend.go b/v2/internal/frontend/desktop/darwin/frontend.go index 8922cd228..2d169da1f 100644 --- a/v2/internal/frontend/desktop/darwin/frontend.go +++ b/v2/internal/frontend/desktop/darwin/frontend.go @@ -16,8 +16,10 @@ import "C" import ( "context" "encoding/json" + "fmt" "html/template" "log" + "os" "strconv" "unsafe" @@ -272,21 +274,32 @@ func (f *Frontend) ExecJS(js string) { func (f *Frontend) processRequest(r *request) { uri := C.GoString(r.url) + var _contents []byte + var _mimetype string + // Translate URI to file file, match, err := common.TranslateUriToFile(uri, "wails", "wails") - if err != nil { - // TODO Handle errors - return - } else if !match { - return + if err == nil { + if !match { + // This should never happen on darwin, because we get only called for wails:// + panic("Unexpected host for request on wails:// scheme") + } + + // Load file from asset store + _contents, _mimetype, err = f.assets.Load(file) } - _contents, _mimetype, err := f.assets.Load(file) + statusCode := 200 if err != nil { - f.logger.Error(err.Error()) - //TODO: Handle errors - return + if os.IsNotExist(err) { + statusCode = 404 + } else { + err = fmt.Errorf("Error processing request %s: %w", uri, err) + f.logger.Error(err.Error()) + statusCode = 500 + } } + var data unsafe.Pointer if _contents != nil { data = unsafe.Pointer(&_contents[0]) @@ -294,7 +307,7 @@ func (f *Frontend) processRequest(r *request) { mimetype := C.CString(_mimetype) defer C.free(unsafe.Pointer(mimetype)) - C.ProcessURLResponse(r.ctx, r.url, mimetype, data, C.int(len(_contents))) + C.ProcessURLResponse(r.ctx, r.url, C.int(statusCode), mimetype, data, C.int(len(_contents))) } //func (f *Frontend) processSystemEvent(message string) { diff --git a/v2/internal/frontend/desktop/linux/frontend.go b/v2/internal/frontend/desktop/linux/frontend.go index 7523396f7..c4ab13f4a 100644 --- a/v2/internal/frontend/desktop/linux/frontend.go +++ b/v2/internal/frontend/desktop/linux/frontend.go @@ -333,7 +333,8 @@ func (f *Frontend) processRequest(request unsafe.Pointer) { // TODO Handle errors return } else if !match { - return + // This should never happen on linux, because we get only called for wails:// + panic("Unexpected host for request on wails:// scheme") } // Load file from asset store @@ -342,6 +343,8 @@ func (f *Frontend) processRequest(request unsafe.Pointer) { return } + // TODO How to return 404/500 errors to webkit? + cContent := C.CString(string(content)) defer C.free(unsafe.Pointer(cContent)) cMimeType := C.CString(mimeType) diff --git a/v2/internal/frontend/desktop/windows/frontend.go b/v2/internal/frontend/desktop/windows/frontend.go index 940af105f..32245c129 100644 --- a/v2/internal/frontend/desktop/windows/frontend.go +++ b/v2/internal/frontend/desktop/windows/frontend.go @@ -8,6 +8,7 @@ import ( "encoding/json" "fmt" "log" + "os" "runtime" "strconv" "strings" @@ -336,26 +337,45 @@ func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, arg //Get the request uri, _ := req.GetUri() + var content []byte + var mimeType string + + // Translate URI to file file, match, err := common.TranslateUriToFile(uri, "file", "wails") - if err != nil { - // TODO Handle errors - return - } else if !match { - return + if err == nil { + if !match { + // In this case we should let the WebView2 handle the request with it's default handler + return + } + + // Load file from asset store + content, mimeType, err = f.assets.Load(file) } - // Load file from asset store - content, mimeType, err := f.assets.Load(file) + statusCode := 200 + reasonPhrase := "OK" if err != nil { - return + if os.IsNotExist(err) { + statusCode = 404 + reasonPhrase = "Not Found" + } else { + err = fmt.Errorf("Error processing request %s: %w", uri, err) + f.logger.Error(err.Error()) + statusCode = 500 + reasonPhrase = "Internal Server Error" + } + } + + headers := []string{} + if mimeType != "" { + headers = append(headers, "Content-Type: "+mimeType) + } + if content != nil && f.servingFromDisk { + headers = append(headers, "Pragma: no-cache") } env := f.chromium.Environment() - headers := "Content-Type: " + mimeType - if f.servingFromDisk { - headers += "\nPragma: no-cache" - } - response, err := env.CreateWebResourceResponse(content, 200, "OK", headers) + response, err := env.CreateWebResourceResponse(content, statusCode, reasonPhrase, strings.Join(headers, "\n")) if err != nil { return } @@ -366,7 +386,6 @@ func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, arg if err != nil { return } - return } var edgeMap = map[string]uintptr{