Skip to content

Commit

Permalink
[assetserver, linux] Add support for WebKit2GTK 2.40+ features (#2592)
Browse files Browse the repository at this point in the history
  • Loading branch information
stffabi committed Apr 14, 2023
1 parent ec3da8b commit 39a7ab5
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 60 deletions.
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

0 comments on commit 39a7ab5

Please sign in to comment.