Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[assetserver, linux] Add support for WebKit2GTK 2.40+ features #2592

Merged
merged 1 commit into from
Apr 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions v2/pkg/assetserver/webview/request_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ func (r *request) Body() (io.ReadCloser, error) {
return r.body, nil
}

// WebKit2GTK has currently no support for request bodies.
r.body = http.NoBody
r.body = webkit_uri_scheme_request_get_http_body(r.req)

return r.body, nil
}
Expand Down
69 changes: 69 additions & 0 deletions v2/pkg/assetserver/webview/webkit2_36+.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//go:build linux && (webkit2_36 || webkit2_40)

package webview

/*
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 libsoup-2.4

#include "gtk/gtk.h"
#include "webkit2/webkit2.h"
#include "libsoup/soup.h"
*/
import "C"

import (
"net/http"
"strings"
"unsafe"
)

func webkit_uri_scheme_request_get_http_method(req *C.WebKitURISchemeRequest) string {
method := C.GoString(C.webkit_uri_scheme_request_get_http_method(req))
return strings.ToUpper(method)
}

func webkit_uri_scheme_request_get_http_headers(req *C.WebKitURISchemeRequest) http.Header {
hdrs := C.webkit_uri_scheme_request_get_http_headers(req)

var iter C.SoupMessageHeadersIter
C.soup_message_headers_iter_init(&iter, hdrs)

var name *C.char
var value *C.char

h := http.Header{}
for C.soup_message_headers_iter_next(&iter, &name, &value) != 0 {
h.Add(C.GoString(name), C.GoString(value))
}

return h
}

func webkit_uri_scheme_request_finish(req *C.WebKitURISchemeRequest, code int, header http.Header, stream *C.GInputStream, streamLength int64) error {
resp := C.webkit_uri_scheme_response_new(stream, C.gint64(streamLength))
defer C.g_object_unref(C.gpointer(resp))

cReason := C.CString(http.StatusText(code))
C.webkit_uri_scheme_response_set_status(resp, C.guint(code), cReason)
C.free(unsafe.Pointer(cReason))

cMimeType := C.CString(header.Get(HeaderContentType))
C.webkit_uri_scheme_response_set_content_type(resp, cMimeType)
C.free(unsafe.Pointer(cMimeType))

hdrs := C.soup_message_headers_new(C.SOUP_MESSAGE_HEADERS_RESPONSE)
for name, values := range header {
cName := C.CString(name)
for _, value := range values {
cValue := C.CString(value)
C.soup_message_headers_append(hdrs, cName, cValue)
C.free(unsafe.Pointer(cValue))
}
C.free(unsafe.Pointer(cName))
}

C.webkit_uri_scheme_response_set_http_headers(resp, hdrs)

C.webkit_uri_scheme_request_finish_with_response(req, resp)
return nil
}
58 changes: 4 additions & 54 deletions v2/pkg/assetserver/webview/webkit2_36.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,69 +3,19 @@
package webview

/*
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 libsoup-2.4
#cgo linux pkg-config: webkit2gtk-4.0

#include "gtk/gtk.h"
#include "webkit2/webkit2.h"
#include "libsoup/soup.h"
*/
import "C"

import (
"io"
"net/http"
"strings"
"unsafe"
)

const Webkit2MinMinorVersion = 36

func webkit_uri_scheme_request_get_http_method(req *C.WebKitURISchemeRequest) string {
method := C.GoString(C.webkit_uri_scheme_request_get_http_method(req))
return strings.ToUpper(method)
}

func webkit_uri_scheme_request_get_http_headers(req *C.WebKitURISchemeRequest) http.Header {
hdrs := C.webkit_uri_scheme_request_get_http_headers(req)

var iter C.SoupMessageHeadersIter
C.soup_message_headers_iter_init(&iter, hdrs)

var name *C.char
var value *C.char

h := http.Header{}
for C.soup_message_headers_iter_next(&iter, &name, &value) != 0 {
h.Add(C.GoString(name), C.GoString(value))
}

return h
}

func webkit_uri_scheme_request_finish(req *C.WebKitURISchemeRequest, code int, header http.Header, stream *C.GInputStream, streamLength int64) error {
resp := C.webkit_uri_scheme_response_new(stream, C.gint64(streamLength))
defer C.g_object_unref(C.gpointer(resp))

cReason := C.CString(http.StatusText(code))
C.webkit_uri_scheme_response_set_status(resp, C.guint(code), cReason)
C.free(unsafe.Pointer(cReason))

cMimeType := C.CString(header.Get(HeaderContentType))
C.webkit_uri_scheme_response_set_content_type(resp, cMimeType)
C.free(unsafe.Pointer(cMimeType))

hdrs := C.soup_message_headers_new(C.SOUP_MESSAGE_HEADERS_RESPONSE)
for name, values := range header {
cName := C.CString(name)
for _, value := range values {
cValue := C.CString(value)
C.soup_message_headers_append(hdrs, cName, cValue)
C.free(unsafe.Pointer(cValue))
}
C.free(unsafe.Pointer(cName))
}

C.webkit_uri_scheme_response_set_http_headers(resp, hdrs)

C.webkit_uri_scheme_request_finish_with_response(req, resp)
return nil
func webkit_uri_scheme_request_get_http_body(_ *C.WebKitURISchemeRequest) io.ReadCloser {
return http.NoBody
}
83 changes: 83 additions & 0 deletions v2/pkg/assetserver/webview/webkit2_40+.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//go:build linux && webkit2_40

package webview

/*
#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 gio-unix-2.0

#include "gtk/gtk.h"
#include "webkit2/webkit2.h"
#include "gio/gunixinputstream.h"
*/
import "C"

import (
"fmt"
"io"
"net/http"
"unsafe"
)

func webkit_uri_scheme_request_get_http_body(req *C.WebKitURISchemeRequest) io.ReadCloser {
stream := C.webkit_uri_scheme_request_get_http_body(req)
if stream == nil {
return http.NoBody
}
return &webkitRequestBody{stream: stream}
}

type webkitRequestBody struct {
stream *C.GInputStream
closed bool
}

// Read implements io.Reader
func (r *webkitRequestBody) Read(p []byte) (int, error) {
if r.closed {
return 0, io.ErrClosedPipe
}

var content unsafe.Pointer
var contentLen int
if p != nil {
content = unsafe.Pointer(&p[0])
contentLen = len(p)
}

var n C.gsize
var gErr *C.GError
res := C.g_input_stream_read_all(r.stream, content, C.gsize(contentLen), &n, nil, &gErr)
if res == 0 {
return 0, formatGError("stream read failed", gErr)
} else if n == 0 {
return 0, io.EOF
}
return int(n), nil
}

func (r *webkitRequestBody) Close() error {
if r.closed {
return nil
}
r.closed = true

// https://docs.gtk.org/gio/method.InputStream.close.html
// Streams will be automatically closed when the last reference is dropped, but you might want to call this function
// to make sure resources are released as early as possible.
var err error
var gErr *C.GError
if C.g_input_stream_close(r.stream, nil, &gErr) == 0 {
err = formatGError("stream close failed", gErr)
}
C.g_object_unref(C.gpointer(r.stream))
r.stream = nil
return err
}

func formatGError(msg string, gErr *C.GError, args ...any) error {
if gErr != nil && gErr.message != nil {
msg += ": " + C.GoString(gErr.message)
C.g_error_free(gErr)
}
return fmt.Errorf(msg, args...)
}
5 changes: 5 additions & 0 deletions v2/pkg/assetserver/webview/webkit2_40.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//go:build linux && webkit2_40

package webview

const Webkit2MinMinorVersion = 40
7 changes: 6 additions & 1 deletion v2/pkg/assetserver/webview/webkit2_legacy.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build linux && !webkit2_36
//go:build linux && !(webkit2_36 || webkit2_40)

package webview

Expand All @@ -12,6 +12,7 @@ import "C"

import (
"fmt"
"io"
"net/http"
"unsafe"
)
Expand All @@ -26,6 +27,10 @@ func webkit_uri_scheme_request_get_http_headers(_ *C.WebKitURISchemeRequest) htt
return http.Header{}
}

func webkit_uri_scheme_request_get_http_body(_ *C.WebKitURISchemeRequest) io.ReadCloser {
return http.NoBody
}

func webkit_uri_scheme_request_finish(req *C.WebKitURISchemeRequest, code int, header http.Header, stream *C.GInputStream, streamLength int64) error {
if code != http.StatusOK {
return fmt.Errorf("StatusCodes not supported: %d - %s", code, http.StatusText(code))
Expand Down
7 changes: 4 additions & 3 deletions website/docs/reference/options.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -260,16 +260,17 @@ Not all features of an `http.Request` are currently supported, please see the fo
| PATCH | ✅ | ✅ | ✅ [^1] |
| DELETE | ✅ | ✅ | ✅ [^1] |
| Request Headers | ✅ | ✅ | ✅ [^1] |
| Request Body | ✅ | ✅ | |
| Request Body Streaming | ✅ | ✅ | |
| Request Body | ✅ | ✅ | ✅ [^2] |
| Request Body Streaming | ✅ | ✅ | ✅ [^2] |
| Response StatusCodes | ✅ | ✅ | ✅ [^1] |
| Response Headers | ✅ | ✅ | ✅ [^1] |
| Response Body | ✅ | ✅ | ✅ |
| Response Body Streaming | ❌ | ✅ | ✅ |
| WebSockets | ❌ | ❌ | ❌ |
| HTTP Redirects 30x | ✅ | ❌ | ❌ |

[^1]: This requires WebKit2GTK 2.36+ support and your app needs to be build with the build tag `webkit2_36` to activate support for this feature. This also bumps the minimum requirement of WebKit2GTK to 2.36 for your app.
[^1]: This requires WebKit2GTK 2.36+ support and your app needs to be build with the build tag `webkit2_36` to activate support for this feature. This also bumps the minimum requirement of WebKit2GTK to 2.36 for your app.
[^2]: This requires WebKit2GTK 2.40+ support and your app needs to be build with the build tag `webkit2_40` to activate support for this feature. This also bumps the minimum requirement of WebKit2GTK to 2.40 for your app.

Name: AssetServer<br/>
Type: `*assetserver.Options`
Expand Down
1 change: 1 addition & 0 deletions website/src/pages/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Added Nodejs version in `wails doctor`. Added by @misitebao in [PR](https://github.com/wailsapp/wails/pull/2546)
- Added support for WebKit2GTK 2.40+ on Linux. This brings additional features for the [AssetServer](/docs/reference/options#assetserver), like support for HTTP Request Bodies. The app must be compiled with the Go build tag `webkit2_40` to activate support for this features. This also bumps the minimum requirement of WebKit2GTK to 2.40 for your app. Added by @stffabi in this [PR](https://github.com/wailsapp/wails/pull/2592)

### Changed

Expand Down