Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
ca19712
Cleanup.
AlliBalliBaba Nov 1, 2025
5b7fbab
Formatting.
AlliBalliBaba Nov 1, 2025
0cebb74
Moves state to own module.
AlliBalliBaba Nov 1, 2025
6dc3432
Refactoring.
AlliBalliBaba Nov 1, 2025
7c8813e
Also moves php_headers test.
AlliBalliBaba Nov 1, 2025
1436802
tests with -vet=off
AlliBalliBaba Nov 6, 2025
7c79d7a
tests with ./go.sh vet before.
AlliBalliBaba Nov 6, 2025
f5bb4e0
Moves env logic to the C side.
AlliBalliBaba Nov 8, 2025
06a329b
Cleanup.
AlliBalliBaba Nov 8, 2025
87123bd
import C test.
AlliBalliBaba Nov 10, 2025
4161623
adds turns state into string
AlliBalliBaba Nov 11, 2025
a36547b
suggestion: simplify exponential backoff (#1970)
AlliBalliBaba Nov 13, 2025
b05964f
Merge branch 'main' into refator/cleanup-c
AlliBalliBaba Nov 13, 2025
42b2ffa
changes log to the documented version.
AlliBalliBaba Nov 13, 2025
26e1408
go linting.
AlliBalliBaba Nov 14, 2025
99e3b99
Merge branch 'main' into refactor/cleanup-env
AlliBalliBaba Nov 21, 2025
a116591
Merge branch 'main' into refator/cleanup-c
AlliBalliBaba Nov 21, 2025
bcd482a
Resolve merge conflicts.
AlliBalliBaba Nov 21, 2025
69f3d8d
Merge branch 'main' into refactor/cleanup-env
AlliBalliBaba Nov 30, 2025
c4e6605
better success checks.
AlliBalliBaba Nov 30, 2025
b8288b9
Merge branch 'main' into refator/cleanup-c
AlliBalliBaba Dec 2, 2025
2e1811c
Merge conflict fix.
AlliBalliBaba Dec 2, 2025
0199038
Merge branch 'refator/cleanup-c' into refactor/cleanup-env
AlliBalliBaba Dec 2, 2025
0e5964d
go fmt
AlliBalliBaba Dec 2, 2025
c116953
Merge branch 'main' into refactor/cleanup-env
AlliBalliBaba Dec 2, 2025
1d52c10
go fmt
AlliBalliBaba Dec 2, 2025
dde7906
Fixes tests.
AlliBalliBaba Dec 2, 2025
45a86af
clang-format
AlliBalliBaba Dec 4, 2025
c55dc34
makes wrong format even wronger.
AlliBalliBaba Dec 4, 2025
016b63d
Adds clarification.
AlliBalliBaba Dec 4, 2025
981b801
Removes test again as asan/msan will make insertions succeed.
AlliBalliBaba Dec 4, 2025
d3c5501
Adds test.
AlliBalliBaba Dec 11, 2025
3aa35f9
Adds custom env to start of tests.
AlliBalliBaba Dec 11, 2025
c803d7c
Never clears main thread env.
AlliBalliBaba Dec 11, 2025
3fc0d92
Adds putenv syntax check.
AlliBalliBaba Dec 11, 2025
e00a70e
Adds more tests.
AlliBalliBaba Dec 11, 2025
c578745
Fixes os env tests.
AlliBalliBaba Dec 12, 2025
75a07f8
cleanup.
AlliBalliBaba Dec 12, 2025
ec9e53b
Merge branch 'main' into refactor/cleanup-env
AlliBalliBaba Dec 19, 2025
8da70be
Merge branch 'main' into refactor/cleanup-env
AlliBalliBaba Feb 8, 2026
697e91d
Merge branch 'main' into refactor/cleanup-env
AlliBalliBaba Feb 9, 2026
8be2859
Cleanup.
AlliBalliBaba Feb 9, 2026
5cd7fb9
Also test $_ENV is unaffected.
AlliBalliBaba Feb 16, 2026
51a9fe4
Keeps PHP consistency on null bytes.
AlliBalliBaba Feb 17, 2026
de08ca6
Adds ZVAL_STRING wrapper.
AlliBalliBaba Feb 17, 2026
aa970b7
Merge branch 'main' into refactor/cleanup-env
AlliBalliBaba Feb 17, 2026
205e5ab
Uses pemalloc
AlliBalliBaba Feb 17, 2026
6dcc63d
Uses pemalloc
AlliBalliBaba Feb 17, 2026
80e82b7
Test and linter fixes.
AlliBalliBaba Feb 17, 2026
f854902
Fixes tests with no env.
AlliBalliBaba Feb 17, 2026
a2e7671
Merge branch 'main' into refactor/cleanup-env
AlliBalliBaba Feb 23, 2026
70a9d94
Merge fix.
AlliBalliBaba Feb 23, 2026
3ba22f4
clang-format.
AlliBalliBaba Feb 23, 2026
4deeed9
Merge branch 'main' into refactor/cleanup-env
AlliBalliBaba Feb 26, 2026
88a794b
go fmt.
AlliBalliBaba Feb 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions caddy/caddy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ func escapeMetricLabel(s string) string {
return strings.ReplaceAll(s, "\\", "\\\\")
}

func TestMain(m *testing.M) {
// setup custom environment vars for TestOsEnv
if os.Setenv("ENV1", "value1") != nil || os.Setenv("ENV2", "value2") != nil {
fmt.Println("Failed to set environment variables for tests")
os.Exit(1)
}

os.Exit(m.Run())
}

func TestPHP(t *testing.T) {
var wg sync.WaitGroup
tester := caddytest.NewTester(t)
Expand Down Expand Up @@ -957,9 +967,6 @@ func testSingleIniConfiguration(tester *caddytest.Tester, key string, value stri
}

func TestOsEnv(t *testing.T) {
require.NoError(t, os.Setenv("ENV1", "value1"))
require.NoError(t, os.Setenv("ENV2", "value2"))

tester := caddytest.NewTester(t)
tester.InitServer(`
{
Expand Down
4 changes: 2 additions & 2 deletions caddy/mercure.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ package caddy
import (
"encoding/json"
"errors"
"os"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
"github.com/dunglas/frankenphp"
"github.com/dunglas/mercure"
mercureCaddy "github.com/dunglas/mercure/caddy"
"os"
)

func init() {
Expand Down Expand Up @@ -67,5 +67,5 @@ func createMercureRoute() (caddyhttp.Route, error) {
},
}

return mercureRoute, nil;
return mercureRoute, nil
}
4 changes: 2 additions & 2 deletions caddy/php-server.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,8 @@ func cmdPHPServer(fs caddycmd.Flags) (int, error) {
if mercure {
mercureRoute, err := createMercureRoute()
if err != nil {
return caddy.ExitCodeFailedStartup, err
}
return caddy.ExitCodeFailedStartup, err
}

subroute.Routes = append(caddyhttp.RouteList{mercureRoute}, subroute.Routes...)
}
Expand Down
110 changes: 14 additions & 96 deletions env.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,114 +3,32 @@ package frankenphp
// #cgo nocallback frankenphp_init_persistent_string
// #cgo noescape frankenphp_init_persistent_string
// #include "frankenphp.h"
// #include <Zend/zend_API.h>
// #include "types.h"
import "C"
import (
"os"
"strings"
"unsafe"
)

func initializeEnv() map[string]*C.zend_string {
env := os.Environ()
envMap := make(map[string]*C.zend_string, len(env))

for _, envVar := range env {
//export go_init_os_env
func go_init_os_env(mainThreadEnv *C.zend_array) {
for _, envVar := range os.Environ() {
key, val, _ := strings.Cut(envVar, "=")
envMap[key] = C.frankenphp_init_persistent_string(toUnsafeChar(val), C.size_t(len(val)))
}

return envMap
}

// get the main thread env or the thread specific env
func getSandboxedEnv(thread *phpThread) map[string]*C.zend_string {
if thread.sandboxedEnv != nil {
return thread.sandboxedEnv
}

return mainThread.sandboxedEnv
}

func clearSandboxedEnv(thread *phpThread) {
if thread.sandboxedEnv == nil {
return
}

for key, val := range thread.sandboxedEnv {
valInMainThread, ok := mainThread.sandboxedEnv[key]
if !ok || val != valInMainThread {
C.free(unsafe.Pointer(val))
}
}

thread.sandboxedEnv = nil
}

// if an env var already exists, it needs to be freed
func removeEnvFromThread(thread *phpThread, key string) {
valueInThread, existsInThread := thread.sandboxedEnv[key]
if !existsInThread {
return
}

valueInMainThread, ok := mainThread.sandboxedEnv[key]
if !ok || valueInThread != valueInMainThread {
C.free(unsafe.Pointer(valueInThread))
}

delete(thread.sandboxedEnv, key)
}

// copy the main thread env to the thread specific env
func cloneSandboxedEnv(thread *phpThread) {
if thread.sandboxedEnv != nil {
return
}
thread.sandboxedEnv = make(map[string]*C.zend_string, len(mainThread.sandboxedEnv))
for key, value := range mainThread.sandboxedEnv {
thread.sandboxedEnv[key] = value
zkey := C.frankenphp_init_persistent_string(toUnsafeChar(key), C.size_t(len(key)))
zStr := C.frankenphp_init_persistent_string(toUnsafeChar(val), C.size_t(len(val)))
C.__hash_update_string__(mainThreadEnv, zkey, zStr)
}
}

//export go_putenv
func go_putenv(threadIndex C.uintptr_t, str *C.char, length C.int) C.bool {
thread := phpThreads[threadIndex]
envString := C.GoStringN(str, length)
cloneSandboxedEnv(thread)

// Check if '=' is present in the string
if key, val, found := strings.Cut(envString, "="); found {
removeEnvFromThread(thread, key)
thread.sandboxedEnv[key] = C.frankenphp_init_persistent_string(toUnsafeChar(val), C.size_t(len(val)))
return os.Setenv(key, val) == nil
}

// No '=', unset the environment variable
removeEnvFromThread(thread, envString)
return os.Unsetenv(envString) == nil
}

//export go_getfullenv
func go_getfullenv(threadIndex C.uintptr_t, trackVarsArray *C.zval) {
thread := phpThreads[threadIndex]
env := getSandboxedEnv(thread)

for key, val := range env {
C.add_assoc_str_ex(trackVarsArray, toUnsafeChar(key), C.size_t(len(key)), val)
}
}

//export go_getenv
func go_getenv(threadIndex C.uintptr_t, name *C.char) (C.bool, *C.zend_string) {
thread := phpThreads[threadIndex]
func go_putenv(name *C.char, nameLen C.int, val *C.char, valLen C.int) C.bool {
goName := C.GoStringN(name, nameLen)

// Get the environment variable value
envValue, exists := getSandboxedEnv(thread)[C.GoString(name)]
if !exists {
// Environment variable does not exist
return false, nil // Return 0 to indicate failure
if val == nil {
// If no "=" is present, unset the environment variable
return C.bool(os.Unsetenv(goName) == nil)
}

return true, envValue // Return 1 to indicate success
goVal := C.GoStringN(val, valLen)
return C.bool(os.Setenv(goName, goVal) == nil)
}
Loading
Loading