Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/actions/setup-php/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ runs:
with:
php-version: ${{ inputs.php-version }}
ini-file: development
ini-values: disable_functions=
coverage: none
tools: none
env:
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ jobs:
platform: linux/arm/v6
- variant: php-${{ needs.prepare.outputs.php85_version }}-bookworm
platform: linux/arm/v6
# PHP 8.5 Debian images are not published for 386.
- variant: php-${{ needs.prepare.outputs.php85_version }}-trixie
platform: linux/386
- variant: php-${{ needs.prepare.outputs.php85_version }}-bookworm
platform: linux/386
steps:
- name: Prepare
id: prepare
Expand Down Expand Up @@ -213,11 +218,12 @@ jobs:
- name: Run tests
if: ${{ !fromJson(needs.prepare.outputs.push) }}
run: |
# PHP's PIE flags require the external linker for pure Go race tests too.
# TODO: remove "containerimage.config.digest" fallback once all runners use buildx v0.18+
# which replaced it with "containerimage.digest" and "containerimage.descriptor"
docker run --platform="${PLATFORM}" --rm \
"$(jq -r ".\"builder-${VARIANT}\" | .\"containerimage.config.digest\" // .\"containerimage.digest\"" <<< "${METADATA}")" \
sh -c "./go.sh test ${RACE} -v $(./go.sh list ./... | grep -v github.com/dunglas/frankenphp/internal/testext | grep -v github.com/dunglas/frankenphp/internal/extgen | tr '\n' ' ') && cd caddy && ../go.sh test ${RACE} -v ./..."
sh -c "./go.sh test ${RACE} -ldflags=-linkmode=external -v $(./go.sh list ./... | grep -v github.com/dunglas/frankenphp/internal/testext | grep -v github.com/dunglas/frankenphp/internal/extgen | tr '\n' ' ') && cd caddy && ../go.sh test ${RACE} -ldflags=-linkmode=external -v ./..."
env:
METADATA: ${{ steps.build.outputs.metadata }}
PLATFORM: ${{ matrix.platform }}
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
GOMAXPROCS: 10
LIBRARY_PATH: ${{ github.workspace }}/watcher/target/lib
GOFLAGS: "-tags=nobadger,nomysql,nopgx"
FRANKENPHP_NATIVE_TEST_BINARY: ${{ github.workspace }}/caddy/internal/nativetest/nativetest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -47,6 +48,8 @@ jobs:
php-version: ${{ matrix.php-versions }}
- name: Install e-dant/watcher
uses: ./.github/actions/watcher
- name: Install PHP development libraries
run: sudo apt-get update && sudo apt-get install -y libkrb5-dev libsodium-dev libargon2-dev
- name: Reinstall libbrotli-dev
# TODO: remove this workaround when fixed upstream
run: sudo apt-get install --reinstall -y libbrotli-dev
Expand All @@ -57,6 +60,9 @@ jobs:
- name: Build testcli binary
working-directory: internal/testcli/
run: go build
- name: Build native CLI with a Go extension
working-directory: caddy/internal/nativetest/
run: ../../../build-native.sh -o nativetest
- name: Install gotestsum
run: go install gotest.tools/gotestsum@latest
- name: Run library tests
Expand All @@ -69,7 +75,7 @@ jobs:
run: go test -fuzz FuzzRequest -fuzztime 20s
- name: Build the server
working-directory: caddy/frankenphp/
run: go build
run: ../../build-native.sh
- name: Start the server
working-directory: testdata/
run: sudo ../caddy/frankenphp/frankenphp start
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
/profiles/worker.pgo
/caddy/frankenphp/frankenphp.exe
/caddy/frankenphp/public
/caddy/internal/nativetest/nativetest
/dist
/github_conf
/internal/testserver/testserver
Expand Down
12 changes: 11 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,20 @@ Build Caddy with the FrankenPHP Caddy module:

```console
cd caddy/frankenphp/
go build -tags nobadger,nomysql,nopgx
../../build-native.sh
cd ../../
```

Use `go build -tags nobadger,nomysql,nopgx` instead on macOS and FreeBSD.
To exercise native CLI signal handling and Go extension callbacks on Linux:

```console
cd caddy
../build-native.sh -o internal/nativetest/nativetest ./internal/nativetest
FRANKENPHP_NATIVE_TEST_BINARY="$PWD/internal/nativetest/nativetest" ../go.sh test -race -run '^TestNative' .
cd ..
```

Run the Caddy with the FrankenPHP Caddy module:

```console
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ COPY --from=golang-base /usr/local/go /usr/local/go

ENV PATH=/usr/local/go/bin:$PATH
ENV GOTOOLCHAIN=local
ENV XCADDY_WHICH_GO=/go/src/app/native-go.sh

# This is required to link the FrankenPHP binary to the PHP binary
RUN apt-get update && \
Expand Down Expand Up @@ -121,8 +122,7 @@ ENV CGO_CPPFLAGS=$PHP_CPPFLAGS
ENV CGO_LDFLAGS="-L/usr/local/lib -lssl -lcrypto -lreadline -largon2 -lcurl -lonig -lz $PHP_LDFLAGS"

WORKDIR /go/src/app/caddy/frankenphp
RUN GOBIN=/usr/local/bin \
../../go.sh install -ldflags "-w -s -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy' -X 'github.com/caddyserver/caddy/v2.CustomBinaryName=frankenphp' -X 'github.com/caddyserver/caddy/v2/modules/caddyhttp.ServerHeader=FrankenPHP Caddy'" -buildvcs=true && \
RUN ../../build-native.sh -o /usr/local/bin/frankenphp -ldflags "-w -s -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy' -X 'github.com/caddyserver/caddy/v2.CustomBinaryName=frankenphp' -X 'github.com/caddyserver/caddy/v2/modules/caddyhttp.ServerHeader=FrankenPHP Caddy'" -buildvcs=true && \
setcap cap_net_bind_service=+ep /usr/local/bin/frankenphp && \
cp Caddyfile /etc/frankenphp/Caddyfile && \
frankenphp version && \
Expand Down
4 changes: 2 additions & 2 deletions alpine.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ COPY --link --from=golang-base /usr/local/go /usr/local/go

ENV PATH=/usr/local/go/bin:$PATH
ENV GOTOOLCHAIN=local
ENV XCADDY_WHICH_GO=/go/src/app/native-go.sh

# hadolint ignore=SC2086
RUN apk add --no-cache --virtual .build-deps \
Expand Down Expand Up @@ -125,8 +126,7 @@ ENV CGO_CPPFLAGS=$PHP_CPPFLAGS
ENV CGO_LDFLAGS="-lssl -lcrypto -lreadline -largon2 -lcurl -lonig -lz $PHP_LDFLAGS"

WORKDIR /go/src/app/caddy/frankenphp
RUN GOBIN=/usr/local/bin \
../../go.sh install -ldflags "-w -s -extldflags '-Wl,-z,stack-size=0x80000' -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy' -X 'github.com/caddyserver/caddy/v2.CustomBinaryName=frankenphp' -X 'github.com/caddyserver/caddy/v2/modules/caddyhttp.ServerHeader=FrankenPHP Caddy'" -buildvcs=true && \
RUN ../../build-native.sh -o /usr/local/bin/frankenphp -ldflags "-w -s -extldflags '-Wl,-z,stack-size=0x80000' -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy' -X 'github.com/caddyserver/caddy/v2.CustomBinaryName=frankenphp' -X 'github.com/caddyserver/caddy/v2/modules/caddyhttp.ServerHeader=FrankenPHP Caddy'" -buildvcs=true && \
setcap cap_net_bind_service=+ep /usr/local/bin/frankenphp && \
([ -n "${COMPRESS}" ] && upx --best /usr/local/bin/frankenphp || true) && \
frankenphp version && \
Expand Down
5 changes: 5 additions & 0 deletions build-native.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh
set -eu

script_dir=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
exec "$script_dir/go.sh" run "$script_dir/internal/nativebuild/main.go" "$@"
3 changes: 3 additions & 0 deletions build-static.sh
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ done
# shellcheck disable=SC2086
${spcCommand} download --with-php="${PHP_VERSION}" --for-extensions="${PHP_EXTENSIONS}" --for-libs="${PHP_EXTENSION_LIBS}" ${SPC_OPT_DOWNLOAD_ARGS}
export FRANKENPHP_SOURCE_PATH="${CURRENT_DIR}"
if [ "${os}" = "linux" ]; then
export XCADDY_WHICH_GO="${CURRENT_DIR}/native-go.sh"
fi
# shellcheck disable=SC2086,SC2090
${spcCommand} build --enable-zts --build-embed --build-frankenphp ${SPC_OPT_BUILD_ARGS} "${PHP_EXTENSIONS}" --with-libs="${PHP_EXTENSION_LIBS}"

Expand Down
22 changes: 17 additions & 5 deletions caddy/hotreload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,14 @@ func TestHotReload(t *testing.T) {
}
`, "caddyfile")

var connected, received sync.WaitGroup
var connected sync.WaitGroup
received := make(chan struct{})

connected.Add(1)
received.Go(func() {
go func() {
defer close(received)
cx, cancel := context.WithCancel(t.Context())
defer cancel()
req, _ := http.NewRequest(http.MethodGet, "http://localhost:"+testPort+u, nil)
req = req.WithContext(cx)
resp := tester.AssertResponseCode(req, http.StatusOK)
Expand Down Expand Up @@ -89,13 +92,22 @@ func TestHotReload(t *testing.T) {
}

require.NoError(t, resp.Body.Close())
})
}()

connected.Wait()

require.NoError(t, os.WriteFile(indexFile, []byte("<?=$_SERVER['FRANKENPHP_HOT_RELOAD'];"), 0644))
// The file watcher starts asynchronously. Retry the write until it sees a
// change, leaving enough time between writes for its debounce timer to fire.
require.Eventually(t, func() bool {
select {
case <-received:
return true
default:
require.NoError(t, os.WriteFile(indexFile, []byte("<?=$_SERVER['FRANKENPHP_HOT_RELOAD'];"), 0644))

received.Wait()
return false
}
}, tester.Client.Timeout, 500*time.Millisecond)

tester.AssertGetResponse("http://localhost:"+testPort+"/index.php", http.StatusOK, u)
}
25 changes: 25 additions & 0 deletions caddy/internal/nativetest/extension.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "extension.h"
#include "_cgo_export.h"

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_native_cli_test, 0, 0, IS_LONG,
0)
ZEND_END_ARG_INFO()

PHP_FUNCTION(frankenphp_native_test) {
ZEND_PARSE_PARAMETERS_NONE();
RETURN_LONG(go_frankenphp_native_test());
}

static const zend_function_entry native_cli_test_functions[] = {
PHP_FE(frankenphp_native_test, arginfo_native_cli_test) PHP_FE_END};

zend_module_entry native_cli_test_module = {STANDARD_MODULE_HEADER,
"native_cli_test",
native_cli_test_functions,
NULL,
NULL,
NULL,
NULL,
NULL,
"1.0.0",
STANDARD_MODULE_PROPERTIES};
3 changes: 3 additions & 0 deletions caddy/internal/nativetest/extension.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include <php.h>

extern zend_module_entry native_cli_test_module;
52 changes: 52 additions & 0 deletions caddy/internal/nativetest/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//go:build linux

package main

// #cgo linux CFLAGS: -D_GNU_SOURCE
// #include "extension.h"
import "C"
import (
"os"
"runtime"
"sync"
"unsafe"

caddycmd "github.com/caddyserver/caddy/v2/cmd"
_ "github.com/caddyserver/caddy/v2/modules/standard"
"github.com/dunglas/frankenphp"
_ "github.com/dunglas/frankenphp/caddy"
)

func init() {
frankenphp.RegisterExtension(unsafe.Pointer(&C.native_cli_test_module))
if path := os.Getenv("FRANKENPHP_TEST_EMBEDDED_PATH"); path != "" {
frankenphp.EmbeddedAppPath = path
}
}

//export go_frankenphp_native_test
func go_frankenphp_native_test() C.int {
// Exercise Go initialization, callbacks, and creation of additional OS
// threads, which must inherit the CLI signal mask too.
var ready, done sync.WaitGroup
ready.Add(8)
done.Add(8)
release := make(chan struct{})
for range 8 {
go func() {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
defer done.Done()
ready.Done()
<-release
}()
}
ready.Wait()
close(release)
done.Wait()
return 42
}

func main() {
caddycmd.Main()
}
11 changes: 11 additions & 0 deletions caddy/native.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//go:build linux

package caddy

import "C"
import caddycmd "github.com/caddyserver/caddy/v2/cmd"

//export go_frankenphp_caddy_main
func go_frankenphp_caddy_main() {
caddycmd.Main()
}
Loading
Loading