[v2] Consolidate processRequest, improve logging and error handling (#1158)

This commit is contained in:
stffabi 2022-02-28 09:14:03 +01:00 committed by GitHub
commit c63b1f1981
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 114 additions and 103 deletions

View file

@ -0,0 +1,55 @@
package common
import (
"fmt"
"net/http"
"os"
"strings"
"github.com/wailsapp/wails/v2/internal/frontend/assetserver"
)
type RequestRespone struct {
Body []byte
MimeType string
StatusCode int
}
func (r RequestRespone) StatusText() string {
return http.StatusText(r.StatusCode)
}
func (r RequestRespone) String() string {
return fmt.Sprintf("Body: '%s', StatusCode: %d", string(r.Body), r.StatusCode)
}
func ProcessRequest(uri string, assets *assetserver.DesktopAssetServer, expectedScheme string, expectedHosts ...string) (RequestRespone, error) {
// Translate URI to file
file, err := translateUriToFile(uri, expectedScheme, expectedHosts...)
if err != nil {
if err == ErrUnexpectedHost {
body := fmt.Sprintf("expected host one of \"%s\"", strings.Join(expectedHosts, ","))
return textResponse(body, http.StatusInternalServerError), err
}
return RequestRespone{StatusCode: http.StatusInternalServerError}, err
}
content, mimeType, err := assets.Load(file)
if err != nil {
statusCode := http.StatusInternalServerError
if os.IsNotExist(err) {
statusCode = http.StatusNotFound
}
return RequestRespone{StatusCode: statusCode}, err
}
return RequestRespone{Body: content, MimeType: mimeType, StatusCode: http.StatusOK}, nil
}
func textResponse(body string, statusCode int) RequestRespone {
if body == "" {
return RequestRespone{StatusCode: statusCode}
}
return RequestRespone{Body: []byte(body), MimeType: "text/plain;charset=UTF-8", StatusCode: statusCode}
}

View file

@ -1,20 +1,34 @@
package common
import "net/url"
import (
"fmt"
"net/url"
)
func TranslateUriToFile(uri string, expectedScheme string, expectedHost string) (file string, match bool, err error) {
var ErrUnexpectedScheme = fmt.Errorf("unexpected scheme")
var ErrUnexpectedHost = fmt.Errorf("unexpected host")
func translateUriToFile(uri string, expectedScheme string, expectedHosts ...string) (file string, err error) {
url, err := url.Parse(uri)
if err != nil {
return "", false, err
return "", err
}
if url.Scheme != expectedScheme || url.Host != expectedHost {
return "", false, nil
if url.Scheme != expectedScheme {
return "", ErrUnexpectedScheme
}
filePath := url.Path
if filePath == "" {
filePath = "/"
for _, expectedHost := range expectedHosts {
if url.Host != expectedHost {
continue
}
filePath := url.Path
if filePath == "" {
filePath = "/"
}
return filePath, nil
}
return filePath, true, nil
return "", ErrUnexpectedHost
}

View file

@ -16,10 +16,8 @@ import "C"
import (
"context"
"encoding/json"
"fmt"
"html/template"
"log"
"os"
"strconv"
"unsafe"
@ -280,40 +278,21 @@ 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 {
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)
}
statusCode := 200
res, err := common.ProcessRequest(uri, f.assets, "wails", "wails")
if err != nil {
if os.IsNotExist(err) {
statusCode = 404
} else {
err = fmt.Errorf("Error processing request %s: %w", uri, err)
f.logger.Error(err.Error())
statusCode = 500
}
f.logger.Error("Error processing request '%s': %s (HttpResponse=%s)", uri, err, res)
}
var data unsafe.Pointer
if _contents != nil {
data = unsafe.Pointer(&_contents[0])
var content unsafe.Pointer
var contentLen int
if _contents := res.Body; _contents != nil {
content = unsafe.Pointer(&_contents[0])
contentLen = len(_contents)
}
mimetype := C.CString(_mimetype)
mimetype := C.CString(res.MimeType)
defer C.free(unsafe.Pointer(mimetype))
C.ProcessURLResponse(r.ctx, r.url, C.int(statusCode), mimetype, data, C.int(len(_contents)))
C.ProcessURLResponse(r.ctx, r.url, C.int(res.StatusCode), mimetype, content, C.int(contentLen))
}
//func (f *Frontend) processSystemEvent(message string) {

View file

@ -14,8 +14,8 @@ import "C"
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strconv"
"text/template"
@ -292,46 +292,23 @@ func (f *Frontend) processRequest(request unsafe.Pointer) {
uri := C.webkit_uri_scheme_request_get_uri(req)
goURI := C.GoString(uri)
file, match, err := common.TranslateUriToFile(goURI, "wails", "")
res, err := common.ProcessRequest(goURI, f.assets, "wails", "", "null")
if err != nil {
// TODO Handle errors
return
} else if !match {
file, match, err = common.TranslateUriToFile(goURI, "wails", "null")
if err != nil {
// TODO Handle errors
return
} else if !match {
// This should never happen on linux, because we get only called for wails://
panic("Unexpected host for request on wails:// scheme")
}
f.logger.Error("Error processing request '%s': %s (HttpResponse=%s)", goURI, err, res)
}
// Load file from asset store
content, mimeType, err := f.assets.Load(file)
// TODO How to return 404/500 errors to webkit?
if err != nil {
if os.IsNotExist(err) {
message := C.CString("File not found")
gerr := C.g_error_new_literal(C.g_quark_from_string(message), C.int(404), message)
C.webkit_uri_scheme_request_finish_error(req, gerr)
C.g_error_free(gerr)
C.free(unsafe.Pointer(message))
} else {
err = fmt.Errorf("Error processing request %s: %v", uri, err)
message := C.CString("Internal Error")
gerr := C.g_error_new_literal(C.g_quark_from_string(message), C.int(500), message)
C.webkit_uri_scheme_request_finish_error(req, gerr)
C.g_error_free(gerr)
C.free(unsafe.Pointer(message))
}
if code := res.StatusCode; code != http.StatusOK {
message := C.CString(res.StatusText())
gerr := C.g_error_new_literal(C.g_quark_from_string(message), C.int(code), message)
C.webkit_uri_scheme_request_finish_error(req, gerr)
C.g_error_free(gerr)
C.free(unsafe.Pointer(message))
return
}
cContent := C.CString(string(content))
cContent := C.CString(string(res.Body))
defer C.free(unsafe.Pointer(cContent))
cMimeType := C.CString(mimeType)
cMimeType := C.CString(res.MimeType)
defer C.free(unsafe.Pointer(cMimeType))
cLen := C.long(C.strlen(cContent))
stream := C.g_memory_input_stream_new_from_data(

View file

@ -8,7 +8,6 @@ import (
"encoding/json"
"fmt"
"log"
"os"
"runtime"
"strconv"
"strings"
@ -353,46 +352,32 @@ 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 {
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)
}
statusCode := 200
reasonPhrase := "OK"
if err != nil {
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"
}
res, err := common.ProcessRequest(uri, f.assets, "file", "wails")
if err == common.ErrUnexpectedScheme {
// In this case we should let the WebView2 handle the request with its default handler
return
} else if err == common.ErrUnexpectedHost {
// This means file:// to something other than wails, should we prevent this?
// Maybe we should introduce an AllowList for explicitly allowing schemes and hosts, this could also be interesting
// for all other platforms to improve security.
return // Let WebView2 handle the request with its default handler
} else if err != nil {
f.logger.Error("Error processing request '%s': %s (HttpResponse=%s)", uri, err, res)
}
headers := []string{}
if mimeType != "" {
if mimeType := res.MimeType; mimeType != "" {
headers = append(headers, "Content-Type: "+mimeType)
}
content := res.Body
if content != nil && f.servingFromDisk {
headers = append(headers, "Pragma: no-cache")
}
env := f.chromium.Environment()
response, err := env.CreateWebResourceResponse(content, statusCode, reasonPhrase, strings.Join(headers, "\n"))
response, err := env.CreateWebResourceResponse(content, res.StatusCode, res.StatusText(), strings.Join(headers, "\n"))
if err != nil {
f.logger.Error("CreateWebResourceResponse Error: %s", err)
return
}
defer response.Release()
@ -400,6 +385,7 @@ func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, arg
// Send response back
err = args.PutResponse(response)
if err != nil {
f.logger.Error("PutResponse Error: %s", err)
return
}
}