github.com/AlpineAIO/wails/v2@v2.0.0-beta.32.0.20240505041856-1047a8fa5fef/pkg/assetserver/webview/webkit2_40+.go (about)

     1  //go:build linux && webkit2_40
     2  
     3  package webview
     4  
     5  /*
     6  #cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 gio-unix-2.0
     7  
     8  #include "gtk/gtk.h"
     9  #include "webkit2/webkit2.h"
    10  #include "gio/gunixinputstream.h"
    11  */
    12  import "C"
    13  
    14  import (
    15  	"fmt"
    16  	"io"
    17  	"net/http"
    18  	"unsafe"
    19  )
    20  
    21  func webkit_uri_scheme_request_get_http_body(req *C.WebKitURISchemeRequest) io.ReadCloser {
    22  	stream := C.webkit_uri_scheme_request_get_http_body(req)
    23  	if stream == nil {
    24  		return http.NoBody
    25  	}
    26  	return &webkitRequestBody{stream: stream}
    27  }
    28  
    29  type webkitRequestBody struct {
    30  	stream *C.GInputStream
    31  	closed bool
    32  }
    33  
    34  // Read implements io.Reader
    35  func (r *webkitRequestBody) Read(p []byte) (int, error) {
    36  	if r.closed {
    37  		return 0, io.ErrClosedPipe
    38  	}
    39  
    40  	var content unsafe.Pointer
    41  	var contentLen int
    42  	if p != nil {
    43  		content = unsafe.Pointer(&p[0])
    44  		contentLen = len(p)
    45  	}
    46  
    47  	var n C.gsize
    48  	var gErr *C.GError
    49  	res := C.g_input_stream_read_all(r.stream, content, C.gsize(contentLen), &n, nil, &gErr)
    50  	if res == 0 {
    51  		return 0, formatGError("stream read failed", gErr)
    52  	} else if n == 0 {
    53  		return 0, io.EOF
    54  	}
    55  	return int(n), nil
    56  }
    57  
    58  func (r *webkitRequestBody) Close() error {
    59  	if r.closed {
    60  		return nil
    61  	}
    62  	r.closed = true
    63  
    64  	// https://docs.gtk.org/gio/method.InputStream.close.html
    65  	// Streams will be automatically closed when the last reference is dropped, but you might want to call this function
    66  	// to make sure resources are released as early as possible.
    67  	var err error
    68  	var gErr *C.GError
    69  	if C.g_input_stream_close(r.stream, nil, &gErr) == 0 {
    70  		err = formatGError("stream close failed", gErr)
    71  	}
    72  	C.g_object_unref(C.gpointer(r.stream))
    73  	r.stream = nil
    74  	return err
    75  }
    76  
    77  func formatGError(msg string, gErr *C.GError, args ...any) error {
    78  	if gErr != nil && gErr.message != nil {
    79  		msg += ": " + C.GoString(gErr.message)
    80  		C.g_error_free(gErr)
    81  	}
    82  	return fmt.Errorf(msg, args...)
    83  }