Skip to content

Commit 911e6d1

Browse files
authored
fix: crash when a string is passed for the topics parameter of the mercure_publish() function (#2021)
1 parent c6cadf3 commit 911e6d1

5 files changed

Lines changed: 50 additions & 7 deletions

File tree

frankenphp_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type testOptions struct {
4747
realServer bool
4848
logger *slog.Logger
4949
initOpts []frankenphp.Option
50+
requestOpts []frankenphp.RequestOption
5051
phpIni map[string]string
5152
}
5253

@@ -82,8 +83,10 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), *
8283
require.NoError(t, err)
8384
defer frankenphp.Shutdown()
8485

86+
opts.requestOpts = append(opts.requestOpts, frankenphp.WithRequestDocumentRoot(testDataDir, false))
87+
8588
handler := func(w http.ResponseWriter, r *http.Request) {
86-
req, err := frankenphp.NewRequestWithContext(r, frankenphp.WithRequestDocumentRoot(testDataDir, false))
89+
req, err := frankenphp.NewRequestWithContext(r, opts.requestOpts...)
8790
assert.NoError(t, err)
8891

8992
err = frankenphp.ServeHTTP(w, req)
@@ -1003,6 +1006,7 @@ func FuzzRequest(f *testing.F) {
10031006
if strings.Contains(req.URL.Path, "\x00") {
10041007
assert.Equal(t, 400, resp.StatusCode)
10051008
assert.Contains(t, body, "invalid request path")
1009+
10061010
return
10071011
}
10081012

mercure.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type mercureContext struct {
1717
}
1818

1919
//export go_mercure_publish
20-
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) {
20+
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) {
2121
thread := phpThreads[threadIndex]
2222
ctx := thread.context()
2323
fc := thread.frankenPHPContext()
@@ -32,18 +32,18 @@ func go_mercure_publish(threadIndex C.uintptr_t, topics *C.struct__zval_struct,
3232

3333
u := &mercure.Update{
3434
Event: mercure.Event{
35-
Data: GoString(data),
36-
ID: GoString(id),
35+
Data: GoString(unsafe.Pointer(data)),
36+
ID: GoString(unsafe.Pointer(id)),
3737
Retry: retry,
38-
Type: GoString(typ),
38+
Type: GoString(unsafe.Pointer(typ)),
3939
},
4040
Private: private,
4141
}
4242

4343
zvalType := C.zval_get_type(topics)
4444
switch zvalType {
4545
case C.IS_STRING:
46-
u.Topics = []string{GoString(unsafe.Pointer(topics))}
46+
u.Topics = []string{GoString(unsafe.Pointer(*(**C.zend_string)(unsafe.Pointer(&topics.value[0]))))}
4747
case C.IS_ARRAY:
4848
ts, err := GoPackedArray[string](unsafe.Pointer(topics))
4949
if err != nil {

mercure_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//go:build !nomercure
2+
3+
package frankenphp_test
4+
5+
import (
6+
"fmt"
7+
"net/http"
8+
"net/http/httptest"
9+
"testing"
10+
11+
"github.com/dunglas/frankenphp"
12+
"github.com/dunglas/mercure"
13+
"github.com/stretchr/testify/assert"
14+
"github.com/stretchr/testify/require"
15+
)
16+
17+
func TestMercurePublish_module(t *testing.T) { testMercurePublish(t, &testOptions{}) }
18+
func TestMercurePublish_worker(t *testing.T) {
19+
testMercurePublish(t, &testOptions{workerScript: "index.php"})
20+
}
21+
func testMercurePublish(t *testing.T, opts *testOptions) {
22+
h, err := mercure.NewHub(t.Context(), mercure.WithTransport(mercure.NewLocalTransport(mercure.NewSubscriberList(0))))
23+
require.NoError(t, err)
24+
25+
opts.requestOpts = []frankenphp.RequestOption{frankenphp.WithMercureHub(h)}
26+
27+
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
28+
body, _ := testGet(fmt.Sprintf("https://example.com/mercure-publish.php?i=%d", i), handler, t)
29+
assert.Contains(t, body, "update 1: ")
30+
assert.Contains(t, body, "update 2: ")
31+
}, opts)
32+
}

testdata/flush.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?php
22

3-
43
require_once __DIR__.'/_executor.php';
54

65
return function () {

testdata/mercure-publish.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
require_once __DIR__.'/_executor.php';
4+
5+
return function () {
6+
echo "update 1: " . mercure_publish('foo', 'bar', true, 'myid', 'mytype', 10) . PHP_EOL;
7+
echo "update 2: " . mercure_publish(['baz', 'bar']) . PHP_EOL;
8+
};

0 commit comments

Comments
 (0)