mirror of
https://github.com/dunglas/frankenphp.git
synced 2025-12-24 13:38:11 +08:00
fix: crash when a string is passed for the topics parameter of the mercure_publish() function (#2021)
This commit is contained in:
@@ -47,6 +47,7 @@ type testOptions struct {
|
|||||||
realServer bool
|
realServer bool
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
initOpts []frankenphp.Option
|
initOpts []frankenphp.Option
|
||||||
|
requestOpts []frankenphp.RequestOption
|
||||||
phpIni map[string]string
|
phpIni map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,8 +83,10 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), *
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer frankenphp.Shutdown()
|
defer frankenphp.Shutdown()
|
||||||
|
|
||||||
|
opts.requestOpts = append(opts.requestOpts, frankenphp.WithRequestDocumentRoot(testDataDir, false))
|
||||||
|
|
||||||
handler := func(w http.ResponseWriter, r *http.Request) {
|
handler := func(w http.ResponseWriter, r *http.Request) {
|
||||||
req, err := frankenphp.NewRequestWithContext(r, frankenphp.WithRequestDocumentRoot(testDataDir, false))
|
req, err := frankenphp.NewRequestWithContext(r, opts.requestOpts...)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = frankenphp.ServeHTTP(w, req)
|
err = frankenphp.ServeHTTP(w, req)
|
||||||
@@ -1003,6 +1006,7 @@ func FuzzRequest(f *testing.F) {
|
|||||||
if strings.Contains(req.URL.Path, "\x00") {
|
if strings.Contains(req.URL.Path, "\x00") {
|
||||||
assert.Equal(t, 400, resp.StatusCode)
|
assert.Equal(t, 400, resp.StatusCode)
|
||||||
assert.Contains(t, body, "invalid request path")
|
assert.Contains(t, body, "invalid request path")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
mercure.go
10
mercure.go
@@ -17,7 +17,7 @@ type mercureContext struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//export go_mercure_publish
|
//export go_mercure_publish
|
||||||
func go_mercure_publish(threadIndex C.uintptr_t, topics *C.struct__zval_struct, data unsafe.Pointer, private bool, id, typ unsafe.Pointer, retry uint64) (generatedID *C.zend_string, error C.short) {
|
func go_mercure_publish(threadIndex C.uintptr_t, topics *C.struct__zval_struct, data *C.zend_string, private bool, id, typ *C.zend_string, retry uint64) (generatedID *C.zend_string, error C.short) {
|
||||||
thread := phpThreads[threadIndex]
|
thread := phpThreads[threadIndex]
|
||||||
ctx := thread.context()
|
ctx := thread.context()
|
||||||
fc := thread.frankenPHPContext()
|
fc := thread.frankenPHPContext()
|
||||||
@@ -32,10 +32,10 @@ func go_mercure_publish(threadIndex C.uintptr_t, topics *C.struct__zval_struct,
|
|||||||
|
|
||||||
u := &mercure.Update{
|
u := &mercure.Update{
|
||||||
Event: mercure.Event{
|
Event: mercure.Event{
|
||||||
Data: GoString(data),
|
Data: GoString(unsafe.Pointer(data)),
|
||||||
ID: GoString(id),
|
ID: GoString(unsafe.Pointer(id)),
|
||||||
Retry: retry,
|
Retry: retry,
|
||||||
Type: GoString(typ),
|
Type: GoString(unsafe.Pointer(typ)),
|
||||||
},
|
},
|
||||||
Private: private,
|
Private: private,
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ func go_mercure_publish(threadIndex C.uintptr_t, topics *C.struct__zval_struct,
|
|||||||
zvalType := C.zval_get_type(topics)
|
zvalType := C.zval_get_type(topics)
|
||||||
switch zvalType {
|
switch zvalType {
|
||||||
case C.IS_STRING:
|
case C.IS_STRING:
|
||||||
u.Topics = []string{GoString(unsafe.Pointer(topics))}
|
u.Topics = []string{GoString(unsafe.Pointer(*(**C.zend_string)(unsafe.Pointer(&topics.value[0]))))}
|
||||||
case C.IS_ARRAY:
|
case C.IS_ARRAY:
|
||||||
ts, err := GoPackedArray[string](unsafe.Pointer(topics))
|
ts, err := GoPackedArray[string](unsafe.Pointer(topics))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
32
mercure_test.go
Normal file
32
mercure_test.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
//go:build !nomercure
|
||||||
|
|
||||||
|
package frankenphp_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/dunglas/frankenphp"
|
||||||
|
"github.com/dunglas/mercure"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMercurePublish_module(t *testing.T) { testMercurePublish(t, &testOptions{}) }
|
||||||
|
func TestMercurePublish_worker(t *testing.T) {
|
||||||
|
testMercurePublish(t, &testOptions{workerScript: "index.php"})
|
||||||
|
}
|
||||||
|
func testMercurePublish(t *testing.T, opts *testOptions) {
|
||||||
|
h, err := mercure.NewHub(t.Context(), mercure.WithTransport(mercure.NewLocalTransport(mercure.NewSubscriberList(0))))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
opts.requestOpts = []frankenphp.RequestOption{frankenphp.WithMercureHub(h)}
|
||||||
|
|
||||||
|
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
|
||||||
|
body, _ := testGet(fmt.Sprintf("https://example.com/mercure-publish.php?i=%d", i), handler, t)
|
||||||
|
assert.Contains(t, body, "update 1: ")
|
||||||
|
assert.Contains(t, body, "update 2: ")
|
||||||
|
}, opts)
|
||||||
|
}
|
||||||
1
testdata/flush.php
vendored
1
testdata/flush.php
vendored
@@ -1,6 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
require_once __DIR__.'/_executor.php';
|
require_once __DIR__.'/_executor.php';
|
||||||
|
|
||||||
return function () {
|
return function () {
|
||||||
|
|||||||
8
testdata/mercure-publish.php
vendored
Normal file
8
testdata/mercure-publish.php
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__.'/_executor.php';
|
||||||
|
|
||||||
|
return function () {
|
||||||
|
echo "update 1: " . mercure_publish('foo', 'bar', true, 'myid', 'mytype', 10) . PHP_EOL;
|
||||||
|
echo "update 2: " . mercure_publish(['baz', 'bar']) . PHP_EOL;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user