diff --git a/frankenphp.c b/frankenphp.c index 18f5c10..ce74406 100644 --- a/frankenphp.c +++ b/frankenphp.c @@ -262,6 +262,7 @@ PHP_FUNCTION(frankenphp_request_headers) { } free(headers.r0); + go_apache_request_cleanup(headers.r2); } /* }}} */ diff --git a/frankenphp.go b/frankenphp.go index e449f4d..f8f721e 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -582,24 +582,41 @@ func go_register_variables(rh C.uintptr_t, trackVarsArray *C.zval) { } //export go_apache_request_headers -func go_apache_request_headers(rh C.uintptr_t) (*C.go_string, C.size_t) { +func go_apache_request_headers(rh C.uintptr_t) (*C.go_string, C.size_t, C.uintptr_t) { r := cgo.Handle(rh).Value().(*http.Request) + pinner := runtime.Pinner{} + pinnerHandle := C.uintptr_t(cgo.NewHandle(pinner)) + rl := len(r.Header) scs := unsafe.Sizeof(C.go_string{}) headers := (*C.go_string)(unsafe.Pointer(C.malloc(C.size_t(rl*2) * (C.size_t)(scs)))) header := headers for field, val := range r.Header { - *header = C.go_string{C.size_t(len(field)), (*C.char)(unsafe.Pointer(unsafe.StringData(field)))} + fd := unsafe.StringData(field) + pinner.Pin(fd) + + *header = C.go_string{C.size_t(len(field)), (*C.char)(unsafe.Pointer(fd))} header = (*C.go_string)(unsafe.Add(unsafe.Pointer(header), scs)) cv := strings.Join(val, ", ") - *header = C.go_string{C.size_t(len(cv)), (*C.char)(unsafe.Pointer(unsafe.StringData(cv)))} + vd := unsafe.StringData(cv) + pinner.Pin(vd) + + *header = C.go_string{C.size_t(len(cv)), (*C.char)(unsafe.Pointer(vd))} header = (*C.go_string)(unsafe.Add(unsafe.Pointer(header), scs)) } - return headers, C.size_t(rl) + return headers, C.size_t(rl), pinnerHandle +} + +//export go_apache_request_cleanup +func go_apache_request_cleanup(rh C.uintptr_t) { + h := cgo.Handle(rh) + p := h.Value().(runtime.Pinner) + p.Unpin() + h.Delete() } func addHeader(fc *FrankenPHPContext, cString *C.char, length C.int) { diff --git a/frankenphp_test.go b/frankenphp_test.go index cbc8700..0857ca7 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -581,8 +581,8 @@ func TestRequestHeaders_worker(t *testing.T) { func testRequestHeaders(t *testing.T, opts *testOptions) { runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) { req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/request-headers.php?i=%d", i), nil) - req.Header.Add("Content-Type", "text/plain") - req.Header.Add("Frankenphp-I", strconv.Itoa(i)) + req.Header.Add(strings.Clone("Content-Type"), strings.Clone("text/plain")) + req.Header.Add(strings.Clone("Frankenphp-I"), strings.Clone(strconv.Itoa(i))) w := httptest.NewRecorder() handler(w, req)