Compare commits

...

98 Commits

Author SHA1 Message Date
Kévin Dunglas
204977145b ci: downgrade PHP version for static builds 2024-09-03 21:31:58 +02:00
Kévin Dunglas
dcf190ebcb chore: prepare release 1.2.5 2024-08-27 12:03:36 +02:00
Kévin Dunglas
d968334371 chore: bump deps 2024-08-27 12:02:39 +02:00
Kévin Dunglas
47257ec919 docs: add performance docs (#1004)
* docs: add performance docs

* docs: add PHP performance section

* Update docs/performance.md

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>

* Update docs/performance.md

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>

* Update docs/performance.md

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>

* Update docs/performance.md

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>

* Update docs/performance.md

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>

* Update docs/performance.md

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>

* Update docs/performance.md

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>

* typo

* musl

* musl fixes

* add log section

* french translation

* typo

---------

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>
2024-08-27 11:45:56 +02:00
Kévin Dunglas
a16076e082 perf: prevent useless logger allocs 2024-08-27 11:03:01 +02:00
Alexander Stecher
f5bec5c13c fix(caddy): resolve_root_symlink not taken into account (#1001)
* Prevents parsing from always throwing an error.

* Removes empty line.

* Accepts suggestions.

* Accepts suggestions.

* Fixes syntax.

* Fixes formatting.

* chore: use a guard close

---------

Co-authored-by: a.stecher <a.stecher@sportradar.com>
Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
2024-08-26 20:30:42 +02:00
Kévin Dunglas
db12b4e113 perf: cache document root resolution when possible 2024-08-26 20:26:27 +02:00
Kévin Dunglas
4a8555571c docs: fix build/curl instructions in more languages 2024-08-24 08:30:00 +02:00
David Legrand
d12551762f docs: fix build/curl instructions (#998)
The `z` was missing and there was an error after download:

```
tar: Archive is compressed. Use -z option
tar: Error is not recoverable: exiting now
```
2024-08-23 16:07:42 +02:00
Kévin Dunglas
27ca1ae4f7 feat(static): add HTTP/2 support for ext-curl 2024-08-20 16:38:53 +02:00
Kévin Dunglas
60e3aba981 docs: fix and improve compilation docs 2024-08-20 09:55:33 +02:00
Kévin Dunglas
7a524ddbd5 ci: add back -Wall -Werror 2024-08-20 01:36:26 +02:00
Kévin Dunglas
ac37760e37 docs: create SECURITY.md 2024-08-13 16:08:59 +02:00
Kévin Dunglas
496831329f ci: run tests with PHP 8.4 2024-08-13 09:46:54 +02:00
Kévin Dunglas
ba58e3d829 chore: prepare release 1.2.4 2024-08-12 10:05:10 +02:00
Rob Landers
d532772355 fix: reset sapi response code (#964)
* fix: reset sapi response code
It turns out that the sapi response code is NOT reset between requests by the zend engine. This resets the code for cgi-based requests.
fixes: #960

* update response header test

* fix assertion

* appears to affect workers too
2024-08-11 22:34:50 +02:00
Kévin Dunglas
3ca52f5934 ci: generate SLSA attestations for static binaries 2024-08-09 22:47:50 +02:00
Kévin Dunglas
968176a948 ci: run tests with ASAN and MSAN (#955) 2024-08-09 18:18:15 +02:00
Kévin Dunglas
2af8fd2e31 chore: remove useless cgo directive 2024-08-06 22:57:04 +02:00
Kévin Dunglas
26cfcc145a chore: prepare release 1.2.3 2024-08-05 23:27:19 +02:00
Kévin Dunglas
fd97c977c1 chore: bump deps (#954) 2024-08-05 15:48:25 +02:00
Kévin Dunglas
6c708be99d ci: upgrade to super-linter 6 (#952) 2024-08-04 14:05:54 +02:00
Kévin Dunglas
bcc825a121 ci: switch to super-linter slim variant 2024-08-02 17:33:18 +02:00
Kévin Dunglas
4de9abb49d chore: bump deps 2024-08-02 12:19:03 +02:00
Alexander Makarov
93859e3149 docs: fix assorted typos (#942) 2024-07-27 00:07:52 +02:00
Rob Landers
fb23c64632 perf: cgi-mode 1700% improvement (#933)
* major perf

* clean up before thread returns

* fix lint

* clean up and refactor server-context initialization

* removing the request-startup memset
I'm electing to remove the memset at startup and keeping it in shutdown. Why? Security! Keeping around the request data after a request may result in a leak of important information in a core dump or something. By setting it to zero when we shutdown the request, we can ensure no information is left laying around
2024-07-26 09:22:08 +02:00
Jerry Ma
323edefc4b chore: add prefer-pre-built option for spc download (#921) 2024-07-14 18:13:22 +02:00
Fabien Papet
a6572225f6 docs: fix port number in French version (#919) 2024-07-12 10:55:21 +02:00
Kévin Dunglas
6d5cb37647 chore: prepare release 1.2.2 2024-07-11 14:09:52 +02:00
Kévin Dunglas
0751f453b9 fix: create a custom Go build when using musl to prevent a crash (#913) 2024-07-11 10:26:28 +02:00
Kévin Dunglas
4fab5a3169 docs: fix php.ini path for static binaries 2024-07-10 14:08:11 +02:00
Kévin Dunglas
e743f6ab87 docs: customizing the configuration (#911)
* docs: customizing the configuration

* Update docs/config.md

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>

* Update docs/fr/config.md

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>

* Update embed.md

---------

Co-authored-by: Jacob Dreesen <jacob@hdreesen.de>
2024-07-09 16:13:55 +02:00
Kévin Dunglas
0500ebc191 perf: improve PHP thread management (#898) 2024-07-09 09:39:03 +02:00
Kévin Dunglas
b87cf4e8b9 chore: bump deps 2024-07-08 16:21:06 +02:00
Kévin Dunglas
ebdb2656b6 fix: deprecated Dockerfile ENV syntax 2024-07-05 11:34:47 +02:00
Kévin Dunglas
29d47f42c8 chore: switch back to upstream Static PHP CLI 2024-07-05 11:12:34 +02:00
Kévin Dunglas
ae4ebd11f6 fix: downgrade to Go 1.22.4 for Alpine builds 2024-07-03 17:02:37 +02:00
Kévin Dunglas
8ff6cfdda8 refactor: prevent a useless allocation (#895)
* refactor: prevent a useless allocation

* cs
2024-06-28 16:46:34 +02:00
Kevin Detournay
952dd7a79b docs: use octane:frankenphp instead of octane:start (#893)
to be more consistent with OFFICIAL laravel documentation

(basically octane:start comment , will
check your env octane server and call octane:frankenphp )

Co-authored-by: kevin <kevin@popsell.com>
2024-06-28 12:11:43 +02:00
Kévin Dunglas
213be22967 docs: fix linter 2024-06-27 14:10:51 +02:00
Simon
11e3745b8b docs: explain how to fix SSL/TLS-related issues (#888)
* mail tls issues documentation

* fix linting

* Update known-issues.md

* Update known-issues.md

* Update known-issues.md

---------

Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
2024-06-27 13:49:16 +02:00
Kévin Dunglas
153e7d6686 chore: simplify log config (#887)
* chore: simplify log config

* review
2024-06-25 23:13:57 +02:00
Kévin Dunglas
a313f3a809 chore: prepare release 1.2.1 2024-06-24 17:37:19 +02:00
Kévin Dunglas
e45a788824 fix(caddy): incorrectly prepared environment variables when not using Caddyfile 2024-06-24 17:36:06 +02:00
Kévin Dunglas
549239d16f chore: bump deps 2024-06-24 13:57:41 +02:00
Kévin Dunglas
b47f4d3aa0 fix(static): unbundle parallel extension 2024-06-24 13:53:32 +02:00
Kévin Dunglas
d6d1b2731c feat: add support for max_input_time in worker mode (#874) 2024-06-18 12:00:01 +02:00
dependabot[bot]
e0ccd816e6 ci: bump docker/bake-action from 4 to 5
Bumps [docker/bake-action](https://github.com/docker/bake-action) from 4 to 5.
- [Release notes](https://github.com/docker/bake-action/releases)
- [Commits](https://github.com/docker/bake-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: docker/bake-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 14:42:51 +02:00
dependabot[bot]
039d021f51 chore(caddy): bump github.com/spf13/cobra from 1.8.0 to 1.8.1 in /caddy
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.8.0 to 1.8.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.8.0...v1.8.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 14:42:21 +02:00
Benedikt Franke
6b44b532f5 docs: improve Docker tags documentation (#866) 2024-06-12 15:17:59 +02:00
Tim Düsterhus
c0c56a8cf8 Fix typo in code sample in worker.md 2024-06-11 11:02:06 +02:00
dependabot[bot]
d99ce659f6 chore: bump golang.org/x/net from 0.25.0 to 0.26.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.25.0 to 0.26.0.
- [Commits](https://github.com/golang/net/compare/v0.25.0...v0.26.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-10 13:30:22 +02:00
Kévin Dunglas
c4aba6be02 chore: uniformize C comment style 2024-06-09 12:13:15 +02:00
Kévin Dunglas
4537f27f67 fix: prevent crash when worker terminates after a file upload 2024-06-08 13:36:32 +02:00
DubbleClick
acf6d0ffc4 ci: add -lstdc++ to CGO_LDFLAGS if a C++ extension is enabled (#855) 2024-06-08 13:35:44 +02:00
DubbleClick
ce4732aa43 docs: fix worker example (#856)
* Update worker.md documentation if MAX_REQUESTS is not set

* Update worker.md
2024-06-08 13:06:40 +02:00
Kévin Dunglas
68c0a4c246 chore: prepare release 1.2.0 2024-06-05 15:27:02 +02:00
Kévin Dunglas
74e9a3c9e5 chore: upgrade to Caddy 2.8.4 2024-06-05 15:24:36 +02:00
Kévin Dunglas
3714fdf3a1 fix: superglobals-realated crash with custom extensions in worker mode (#796)
* test: failing test reproducing #767

* fix

* Update frankenphp.c

Co-authored-by: Tim Düsterhus <timwolla@googlemail.com>

* Update frankenphp.c

Co-authored-by: Tim Düsterhus <timwolla@googlemail.com>

* review

* ZVAL_COPY

* fix

* add back current $_SERVER behavior

* add docs

* bad fix for the leak

* clean test

* improve tests

* fix test

* fix

* cleanup

* clarify destroy super globals name

* micro-optim: use zval_ptr_dtor_nogc to destroy super globals

* style

* fix

* better name for frankenphp_free_server_context

* more cleanup

* remove useless memset

* more cleanup

* continue refactoring

* fix and update docs

* docs

---------

Co-authored-by: Tim Düsterhus <timwolla@googlemail.com>
2024-06-05 15:24:16 +02:00
Kévin Dunglas
0b4a427cac feat: use the new RegisterDirectiveOrder to simplify config 2024-05-31 17:47:24 +02:00
Rob Landers
b96db939b7 feat: option to enable full duplex for HTTP/1 connections (#692)
* found another spot that was preventing http1 writes

* remove full-duplex from caddyfile

* update documentation

* fix: update http name

Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>

* fix: update http name

Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>

* fix: names

Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>

* fix: update caddyfile name

Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>

* Add caution to docs

Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>

* Update config.md

Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>

* fix lint

---------

Co-authored-by: Kévin Dunglas <kevin@dunglas.fr>
2024-05-31 14:38:31 +02:00
jeremyj11
ad2c18a6b7 docs: add missing -z to tar (#828) 2024-05-30 16:47:15 +02:00
Kévin Dunglas
2183f29b18 feat: Caddy 2.8 support 2024-05-30 13:59:44 +02:00
Kévin Dunglas
90a7b98b10 feat: log the number of threads and workers during startup 2024-05-30 11:15:30 +02:00
Jerry Ma
322e45c186 fix: support libxml with latest static-php-cli 2024-05-30 11:15:12 +02:00
Stephen Miracle
da342b6f2f docs: recommend FrankenWP for WordPress (#785)
* updating reference location to provide WordPress implementation supprt.

* correcting autoformat issue from previous commit. Should now only be updating wordpress references.
2024-05-27 13:29:16 +02:00
Kévin Dunglas
3d065eda35 $_SERVER['FRANKENPHP_WORKER'] must not be NULL-terminated 2024-05-21 18:50:02 +02:00
Kévin Dunglas
c894a92135 ci: load setup-php debug symbols 2024-05-21 11:12:30 +02:00
Kévin Dunglas
835ad8acb2 ci: cleanup static build workflows 2024-05-17 16:14:22 +02:00
Kévin Dunglas
73e9b640d6 fix: skip installing Buildx when possible 2024-05-16 15:59:41 +02:00
Kévin Dunglas
d01733dd3e docs: better Mercure hub schema 2024-05-16 14:42:30 +02:00
Kévin Dunglas
f773c1f529 ci: clean Docker tags 2024-05-15 14:23:36 +02:00
Kévin Dunglas
469070ce85 chore: prepare release 1.1.5 2024-05-13 15:37:01 +02:00
Kévin Dunglas
ea83ea6dbd chore: bump deps 2024-05-13 15:35:26 +02:00
Kévin Dunglas
a2f0eb9140 ci: remove SHA tag for non-dev Docker images (#781)
* ci: remove SHA tag for non-dev Docker images

* docs: Docker variants
2024-05-13 14:52:13 +02:00
dependabot[bot]
e5fcea0690 ci: bump golangci/golangci-lint-action from 5 to 6
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 5 to 6.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-13 13:52:15 +02:00
Kévin Dunglas
cd2049f611 docs: rootless Docker images with no capabilities 2024-05-13 11:11:52 +02:00
Kévin Dunglas
3dbb3fd48d feat(static): add ftp, gettext, gmp, imagick, mbregex, parallel, protobuf, shmop, soap, ssh2, sysmsg, sysvshm, tidy, xlswriter, yaml and zstd extensions (#773) 2024-05-11 15:43:00 +02:00
dependabot[bot]
627f817b59 ci: bump golangci/golangci-lint-action from 4 to 5
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 4 to 5.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-09 21:46:45 +02:00
Kévin Dunglas
ea5e19ff4b fix: getallheaders() must return request headers (#772)
* fix: getallheaders() must return request headers

* cs
2024-05-08 11:43:39 +02:00
Kévin Dunglas
12fb11eead docs: embedding Laravel apps (#753)
* docs: embedding Laravel apps

* fix

* docs: embedding Octane apps

* fix

* fix

* cs

* cs

* fix md

* path explaination

* changing the storage path
2024-04-29 17:42:18 +02:00
Kévin Dunglas
25a858954c fix: temporary directory name for embed apps 2024-04-28 10:45:38 +02:00
Kévin Dunglas
593233db17 fix: DOMdocument not found when building embedded apps 2024-04-27 03:17:28 +02:00
Kévin Dunglas
fc76447cad chore: prepare release 1.1.4 2024-04-25 11:35:32 +02:00
Kévin Dunglas
ac2dd4ab56 ci: fix linux/amd64 static pipeline 2024-04-24 17:18:58 +02:00
Benjamin Eberlei
5d68a3c5e5 docs: Tideways now supports FrankenPHP in normal and worker mode (#745)
* Tideways now supports FrankenPHP worker mode

See https://support.tideways.com/documentation/setup/installation/frankenphp.html

* Update fr/known-issues.md

* Update tr/known-issues.md
2024-04-24 17:07:14 +02:00
Kévin Dunglas
6597b71f52 ci: fix static pipeline 2024-04-24 11:42:25 +02:00
Kévin Dunglas
fe7d69d01b ci: fix mimalloc pipeline 2024-04-24 00:40:31 +02:00
Kévin Dunglas
977cad0314 ci: fix debug and mimalloc pipeline 2024-04-23 21:34:09 +02:00
Kévin Dunglas
60b5a11e5a ci: fix mimalloc pipeline 2024-04-23 19:29:28 +02:00
Kévin Dunglas
a9ebc3aeea chore: prepare release 1.1.3 2024-04-23 14:50:00 +02:00
dependabot[bot]
4a97a40f4a chore: bump golang.org/x/net from 0.22.0 to 0.24.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to 0.24.0.
- [Commits](https://github.com/golang/net/compare/v0.22.0...v0.24.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-23 14:35:38 +02:00
Kévin Dunglas
404086d4d5 feat: autodetect extensions to build for embedded apps (#717)
* feat: autodetect extensions to build for embeded apps

* fix: ext-libxml support
2024-04-23 14:04:47 +02:00
Kévin Dunglas
498294a561 feat: option to use mimalloc for static builds (#666)
* feat: use mimalloc for static builds

* fix: use Tweag's approach

* fix: debug build

* chore: mark USE_MIMALLOC as experimental

* ci: build a static binary using mimalloc
2024-04-23 14:04:25 +02:00
Kévin Dunglas
06f7c9448f chore: bump deps 2024-04-23 12:08:48 +02:00
Kévin Dunglas
85b8a8c805 fix(static): ensure that FRANKENPHP_VERSION is defined in child Docker images 2024-04-22 11:35:51 +02:00
Pierre
03c0247ae5 docs: translate the contribution guide in Chinese (#739)
Co-authored-by: Pierre Clavequin <pierre.clavequin@valueapex.com>
2024-04-22 10:49:21 +02:00
Kévin Dunglas
238a6ebe9f docs: remove Xdebug from the list of buggy extensions 2024-04-17 17:35:01 +02:00
87 changed files with 2242 additions and 1865 deletions

View File

@@ -16,15 +16,17 @@ on:
- v*.*.*
workflow_dispatch:
inputs:
#checkov:skip=CKV_GHA_7
version:
description: 'FrankenPHP version'
required: false
type: string
schedule:
- cron: '0 4 * * *'
permissions:
contents: read
env:
IMAGE_NAME: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/')) && 'dunglas/frankenphp' || 'dunglas/frankenphp-dev' }}
LATEST: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/')) && '0' || '1' }}
jobs:
prepare:
runs-on: ubuntu-latest
@@ -79,9 +81,8 @@ jobs:
ref: ${{ steps.check.outputs.ref }}
-
name: Set up Docker Buildx
if: ${{ !fromJson(steps.check.outputs.skip) }}
uses: docker/setup-buildx-action@v3
with:
version: latest
-
name: Create variants matrix
if: ${{ !fromJson(steps.check.outputs.skip) }}
@@ -95,7 +96,7 @@ jobs:
} >> "${GITHUB_OUTPUT}"
env:
SHA: ${{ github.sha }}
VERSION: ${{ (github.ref_type == 'tag' && github.ref_name) || steps.check.outputs.ref || github.sha }}
VERSION: ${{ (github.ref_type == 'tag' && github.ref_name) || steps.check.outputs.ref || 'dev' }}
PHP_VERSION: ${{ steps.check.outputs.php_version }}
build:
runs-on: ubuntu-latest
@@ -142,7 +143,6 @@ jobs:
uses: docker/setup-buildx-action@v3
with:
platforms: ${{ matrix.platform }}
version: latest
-
name: Login to DockerHub
if: fromJson(needs.prepare.outputs.push)
@@ -153,7 +153,7 @@ jobs:
-
name: Build
id: build
uses: docker/bake-action@v4
uses: docker/bake-action@v5
with:
pull: true
load: ${{ !fromJson(needs.prepare.outputs.push) }}
@@ -170,7 +170,7 @@ jobs:
${{ fromJson(needs.prepare.outputs.push) && format('*.output=type=image,name={0},push-by-digest=true,name-canonical=true,push=true', env.IMAGE_NAME) || '' }}
env:
SHA: ${{ github.sha }}
VERSION: ${{ github.ref_type == 'tag' && github.ref_name || needs.prepare.outputs.ref || github.sha }}
VERSION: ${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref || 'dev' }}
PHP_VERSION: ${{ needs.prepare.outputs.php_version }}
-
# Workaround for https://github.com/actions/runner/pull/2477#issuecomment-1501003600
@@ -235,9 +235,6 @@ jobs:
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
# Temporary fix for https://github.com/docker/buildx/issues/2229
version: "https://github.com/docker/buildx.git#master"
-
name: Login to DockerHub
uses: docker/login-action@v3

View File

@@ -7,17 +7,14 @@ on:
push:
branches:
- main
permissions:
contents: read
packages: read
statuses: write
jobs:
build:
name: Lint Code Base
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
statuses: write
steps:
-
name: Checkout Code
@@ -26,18 +23,21 @@ jobs:
fetch-depth: 0
-
name: Lint Code Base
uses: super-linter/super-linter@v5
uses: super-linter/super-linter/slim@v6.8.0
env:
VALIDATE_ALL_CODEBASE: true
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
LINTER_RULES_PATH: /
FILTER_REGEX_EXCLUDE: '.*C-Thread-Pool/.*'
MARKDOWN_CONFIG_FILE: .markdown-lint.yaml
VALIDATE_CPP: false
VALIDATE_JSCPD: false
VALIDATE_GO: false
VALIDATE_GO_MODULES: false
VALIDATE_PHP_PHPCS: false
VALIDATE_PHP_PHPSTAN: false
VALIDATE_PHP_PSALM: false
VALIDATE_TERRAGRUNT: false
# Prettier and StandardJS are incompatible
VALIDATE_JAVASCRIPT_PRETTIER: false
VALIDATE_TYPESCRIPT_PRETTIER: false

110
.github/workflows/sanitizers.yaml vendored Normal file
View File

@@ -0,0 +1,110 @@
---
name: Sanitizers
on:
pull_request:
branches:
- main
paths-ignore:
- 'docs/**'
push:
branches:
- main
paths-ignore:
- 'docs/**'
permissions:
contents: read
jobs:
# Adapted from https://github.com/beberlei/hdrhistogram-php
sanitizers:
name: ${{ matrix.sanitizer }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
sanitizer: ['asan', 'msan']
env:
CFLAGS: -g -O0 -fsanitize=${{ matrix.sanitizer == 'asan' && 'address' || 'memory' }} -DZEND_TRACK_ARENA_ALLOC
LDFLAGS: -fsanitize=${{ matrix.sanitizer == 'asan' && 'address' || 'memory' }}
CC: clang
CXX: clang++
USE_ZEND_ALLOC: 0
LIBRARY_PATH: ${{ github.workspace }}/php/target/lib
LD_LIBRARY_PATH: ${{ github.workspace }}/php/target/lib
steps:
-
name: Remove local PHP
run: sudo apt-get remove --purge --autoremove 'php*' 'libmemcached*'
-
uses: actions/checkout@v4
-
uses: actions/setup-go@v5
with:
go-version: '1.22'
cache-dependency-path: |
go.sum
caddy/go.sum
-
name: Determine PHP version
id: determine-php-version
run: |
curl -fsSL 'https://www.php.net/releases/index.php?json&max=1&version=8.3' -o version.json
echo version="$(jq -r 'keys[0]' version.json)" >> "$GITHUB_OUTPUT"
echo archive="$(jq -r '.[] .source[] | select(.filename |endswith(".xz")) | "https://www.php.net/distributions/" + .filename' version.json)" >> "$GITHUB_OUTPUT"
-
name: Cache PHP
id: cache-php
uses: actions/cache@v4
with:
path: php/target
key: php-sanitizers-${{ matrix.sanitizer }}-${{ runner.arch }}-${{ steps.determine-php-version.outputs.version }}
-
if: steps.cache-php.outputs.cache-hit != 'true'
name: Compile PHP
run: |
mkdir php/
curl -fsSL "${{ steps.determine-php-version.outputs.archive }}" | tar -Jx -C php --strip-components=1
cd php/
./configure \
CFLAGS="$CFLAGS" \
LDFLAGS="$LDFLAGS" \
--enable-debug \
--enable-embed \
--enable-zts \
--enable-option-checking=fatal \
--disable-zend-signals \
--without-sqlite3 \
--without-pdo-sqlite \
--without-libxml \
--disable-dom \
--disable-simplexml \
--disable-xml \
--disable-xmlreader \
--disable-xmlwriter \
--without-pcre-jit \
--disable-opcache-jit \
--disable-cli \
--disable-cgi \
--disable-phpdbg \
--without-pear \
--disable-mbregex \
--enable-werror \
${{ matrix.sanitizer == 'msan' && '--enable-memory-sanitizer' || '' }} \
--prefix="$(pwd)/target/"
make -j"$(getconf _NPROCESSORS_ONLN)"
make install
-
name: Add PHP to the PATH
run: echo "$(pwd)/php/target/bin" >> "$GITHUB_PATH"
-
name: Set Set CGO flags
run: |
{
echo "CGO_CFLAGS=$CFLAGS $(php-config --includes)"
echo "CGO_LDFLAGS=$LDFLAGS $(php-config --ldflags) $(php-config --libs)"
} >> "$GITHUB_ENV"
-
name: Compile tests
run: go test -${{ matrix.sanitizer }} -v -x -c
-
name: Run tests
run: ./frankenphp.test -test.v

View File

@@ -16,15 +16,20 @@ on:
- v*.*.*
workflow_dispatch:
inputs:
#checkov:skip=CKV_GHA_7
version:
description: 'FrankenPHP version'
required: false
type: string
schedule:
- cron: '0 0 * * *'
permissions:
contents: write
id-token: write
attestations: write
env:
IMAGE_NAME: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/')) && 'dunglas/frankenphp' || 'dunglas/frankenphp-dev' }}
LATEST: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/')) && '0' || '1' }}
IMAGE_NAME: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/')) && 'dunglas/frankenphp' || 'dunglas/frankenphp-dev' }}
PHP_VERSION: 8.3.10 # Temporary workaround for https://github.com/dunglas/frankenphp/issues/1011
jobs:
prepare:
runs-on: ubuntu-latest
@@ -54,8 +59,6 @@ jobs:
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
version: latest
-
name: Create platforms matrix
id: matrix
@@ -67,13 +70,14 @@ jobs:
} >> "${GITHUB_OUTPUT}"
env:
SHA: ${{ github.sha }}
VERSION: ${{ steps.check.outputs.ref || github.sha }}
VERSION: ${{ steps.check.outputs.ref || 'dev' }}
build-linux:
strategy:
fail-fast: false
matrix:
platform: ${{ fromJson(needs.prepare.outputs.platforms) }}
debug: [false]
mimalloc: [false]
include:
-
qemu: true
@@ -84,7 +88,11 @@ jobs:
platform: linux/amd64
qemu: false
debug: true
name: Build ${{ matrix.platform }} static binary${{ matrix.debug && ' (debug)' || '' }}
-
platform: linux/amd64
qemu: false
mimalloc: true
name: Build ${{ matrix.platform }} static binary${{ matrix.debug && ' (debug)' || '' }}${{ matrix.mimalloc && ' (mimalloc)' || '' }}
runs-on: ubuntu-latest
needs: [ prepare ]
steps:
@@ -103,10 +111,9 @@ jobs:
uses: docker/setup-buildx-action@v3
with:
platforms: ${{ matrix.platform }}
version: latest
-
name: Login to DockerHub
if: ${{ fromJson(needs.prepare.outputs.push) && !matrix.debug }}
if: ${{ fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc }}
uses: docker/login-action@v3
with:
username: ${{ secrets.REGISTRY_USERNAME }}
@@ -114,27 +121,29 @@ jobs:
-
name: Build
id: build
uses: docker/bake-action@v4
uses: docker/bake-action@v5
with:
pull: true
load: ${{ !fromJson(needs.prepare.outputs.push) || matrix.debug }}
load: ${{ !fromJson(needs.prepare.outputs.push) || matrix.debug || matrix.mimalloc }}
targets: static-builder
set: |
${{ matrix.debug && 'static-builder.args.DEBUG_SYMBOLS=1' || '' }}
${{ matrix.mimalloc && 'static-builder.args.MIMALLOC=1' || '' }}
${{ matrix.platform == 'linux/arm64' && 'static-builder.args.NO_COMPRESS=1' || '' }}
*.tags=
*.platform=${{ matrix.platform }}
*.cache-from=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder${{ matrix.debug && '-debug' && '' }}
*.cache-from=type=gha,scope=refs/heads/main-static-builder${{ matrix.debug && '-debug' && '' }}
*.cache-to=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder${{ matrix.debug && '-debug' && '' }},ignore-error=true
${{ (fromJson(needs.prepare.outputs.push) && !matrix.debug) && format('*.output=type=image,name={0},push-by-digest=true,name-canonical=true,push=true', env.IMAGE_NAME) || '' }}
*.cache-from=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
*.cache-from=type=gha,scope=refs/heads/main-static-builder${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
*.cache-to=type=gha,scope=${{ needs.prepare.outputs.ref || github.ref }}-static-builder${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }},ignore-error=true
${{ (fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc) && format('*.output=type=image,name={0},push-by-digest=true,name-canonical=true,push=true', env.IMAGE_NAME) || '' }}
env:
SHA: ${{ github.sha }}
VERSION: ${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref || github.sha }}
VERSION: ${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref || 'dev' }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
# Workaround for https://github.com/actions/runner/pull/2477#issuecomment-1501003600
name: Export metadata
if: fromJson(needs.prepare.outputs.push) && !matrix.debug
if: fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc
run: |
mkdir -p /tmp/metadata
@@ -145,7 +154,7 @@ jobs:
METADATA: ${{ steps.build.outputs.metadata }}
-
name: Upload metadata
if: fromJson(needs.prepare.outputs.push) && !matrix.debug
if: fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc
uses: actions/upload-artifact@v3
with:
name: metadata-static-builder
@@ -154,11 +163,11 @@ jobs:
retention-days: 1
-
name: Copy binary
if: ${{ !fromJson(needs.prepare.outputs.push) || matrix.debug }}
if: ${{ !fromJson(needs.prepare.outputs.push) || matrix.debug || matrix.mimalloc }}
run: |
digest=$(jq -r '."static-builder"."containerimage.config.digest"' <<< "${METADATA}")
docker create --platform=${{ matrix.platform }} --name static-builder "${digest}"
docker cp "static-builder:/go/src/app/dist/${BINARY}" "${BINARY}${{ matrix.debug && '-debug' || '' }}"
docker cp "static-builder:/go/src/app/dist/${BINARY}" "${BINARY}${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}"
env:
METADATA: ${{ steps.build.outputs.metadata }}
BINARY: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}
@@ -167,14 +176,19 @@ jobs:
if: ${{ !fromJson(needs.prepare.outputs.push) }}
uses: actions/upload-artifact@v3
with:
name: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}${{ matrix.debug && '-debug' || '' }}
path: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}${{ matrix.debug && '-debug' || '' }}
name: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
path: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
-
name: Upload debug asset
if: fromJson(needs.prepare.outputs.push) && matrix.debug && (needs.prepare.outputs.ref || github.ref_type == 'tag')
run: gh release upload "${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref }}" frankenphp-linux-x86_64-debug --repo dunglas/frankenphp --clobber
name: Upload special assets
if: fromJson(needs.prepare.outputs.push) && (matrix.debug || matrix.mimalloc) && (needs.prepare.outputs.ref || github.ref_type == 'tag')
run: gh release upload "${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref }}" frankenphp-linux-x86_64${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }} --repo dunglas/frankenphp --clobber
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
if: fromJson(needs.prepare.outputs.push) && (matrix.debug || matrix.mimalloc) && (needs.prepare.outputs.ref || github.ref_type == 'tag')
uses: actions/attest-build-provenance@v1
with:
subject-path: ${{ github.workspace }}/frankenphp-linux-x86_64${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }}
# Adapted from https://docs.docker.com/build/ci/github-actions/multi-platform/
push:
@@ -183,7 +197,6 @@ jobs:
- prepare
- build-linux
if: fromJson(needs.prepare.outputs.push)
#if: fromJson(needs.prepare.outputs.push) && (needs.prepare.outputs.ref || github.ref_type == 'tag')
steps:
-
name: Download metadata
@@ -194,8 +207,6 @@ jobs:
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
version: latest
-
name: Login to DockerHub
uses: docker/login-action@v3
@@ -232,6 +243,12 @@ jobs:
run: gh release upload "${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref }}" frankenphp-linux-x86_64 frankenphp-linux-aarch64 --repo dunglas/frankenphp --clobber
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
if: needs.prepare.outputs.ref || github.ref_type == 'tag'
uses: actions/attest-build-provenance@v1
with:
subject-path: ${{ github.workspace }}/frankenphp-linux-*
build-mac:
strategy:
fail-fast: false
@@ -272,6 +289,11 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE: ${{ (needs.prepare.outputs.ref || github.ref_type == 'tag') && '1' || '' }}
-
if: needs.prepare.outputs.ref || github.ref_type == 'tag'
uses: actions/attest-build-provenance@v1
with:
subject-path: ${{ github.workspace }}/dist/frankenphp-mac-*
-
name: Upload artifact
if: github.ref_type == 'branch'

View File

@@ -11,15 +11,18 @@ on:
- main
paths-ignore:
- 'docs/**'
permissions:
contents: read
jobs:
tests:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-versions: ['8.2', '8.3']
php-versions: ['8.2', '8.3', '8.4']
env:
GOEXPERIMENT: cgocheck2
GOMAXPROCS: 10
steps:
-
uses: actions/checkout@v4
@@ -39,6 +42,7 @@ jobs:
tools: none
env:
phpts: ts
debug: true
-
name: Set CGO flags
run: |
@@ -70,6 +74,7 @@ jobs:
run: ./reload_test.sh
-
name: Lint Go code
uses: golangci/golangci-lint-action@v4
uses: golangci/golangci-lint-action@v6
if: matrix.php-versions == '8.3'
with:
version: latest

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2016 Johan Hanssen Seferidis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,70 +0,0 @@
[![GitHub Actions](https://github.com/Pithikos/C-Thread-Pool/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/Pithikos/C-Thread-Pool/actions?query=workflow%3Atests+branch%3Amaster)
# C Thread Pool
This is a minimal but advanced threadpool implementation.
* ANCI C and POSIX compliant
* Pause/resume/wait as you like
* Simple easy-to-digest API
* Well tested
The threadpool is under MIT license. Notice that this project took a considerable amount of work and sacrifice of my free time and the reason I give it for free (even for commercial use) is so when you become rich and wealthy you don't forget about us open-source creatures of the night. Cheers!
If this project reduced your development time feel free to buy me a coffee.
[![Donate](https://www.paypal.com/en_US/i/btn/x-click-but21.gif)](https://www.paypal.me/seferidis)
## Run an example
The library is not precompiled so you have to compile it with your project. The thread pool
uses POSIX threads so if you compile with gcc on Linux you have to use the flag `-pthread` like this:
gcc example.c thpool.c -D THPOOL_DEBUG -pthread -o example
Then run the executable like this:
./example
## Basic usage
1. Include the header in your source file: `#include "thpool.h"`
2. Create a thread pool with number of threads you want: `threadpool thpool = thpool_init(4);`
3. Add work to the pool: `thpool_add_work(thpool, (void*)function_p, (void*)arg_p);`
The workers(threads) will start their work automatically as fast as there is new work
in the pool. If you want to wait for all added work to be finished before continuing
you can use `thpool_wait(thpool);`. If you want to destroy the pool you can use
`thpool_destroy(thpool);`.
## API
For a deeper look into the documentation check in the [thpool.h](https://github.com/Pithikos/C-Thread-Pool/blob/master/thpool.h) file. Below is a fast practical overview.
| Function example | Description |
|---------------------------------|---------------------------------------------------------------------|
| ***thpool_init(4)*** | Will return a new threadpool with `4` threads. |
| ***thpool_add_work(thpool, (void&#42;)function_p, (void&#42;)arg_p)*** | Will add new work to the pool. Work is simply a function. You can pass a single argument to the function if you wish. If not, `NULL` should be passed. |
| ***thpool_wait(thpool)*** | Will wait for all jobs (both in queue and currently running) to finish. |
| ***thpool_destroy(thpool)*** | This will destroy the threadpool. If jobs are currently being executed, then it will wait for them to finish. |
| ***thpool_pause(thpool)*** | All threads in the threadpool will pause no matter if they are idle or executing work. |
| ***thpool_resume(thpool)*** | If the threadpool is paused, then all threads will resume from where they were. |
| ***thpool_num_threads_working(thpool)*** | Will return the number of currently working threads. |
## Contribution
You are very welcome to contribute. If you have a new feature in mind, you can always open an issue on github describing it so you don't end up doing a lot of work that might not be eventually merged. Generally we are very open to contributions as long as they follow the below keypoints.
* Try to keep the API as minimal as possible. That means if a feature or fix can be implemented without affecting the existing API but requires more development time, then we will opt to sacrifice development time.
* Solutions need to be POSIX compliant. The thread-pool is advertised as such so it makes sense that it actually is.
* For coding style simply try to stick to the conventions you find in the existing codebase.
* Tests: A new fix or feature should be covered by tests. If the existing tests are not sufficient, we expect an according test to follow with the pull request.
* Documentation: for a new feature please add documentation. For an API change the documentation has to be thorough and super easy to understand.
If you wish to **get access as a collaborator** feel free to mention it in the issue https://github.com/Pithikos/C-Thread-Pool/issues/78

View File

@@ -1,571 +0,0 @@
/* ********************************
* Author: Johan Hanssen Seferidis
* License: MIT
* Description: Library providing a threading pool where you can add
* work. For usage, check the thpool.h file or README.md
*
*//** @file thpool.h *//*
*
********************************/
#if defined(__APPLE__)
#include <AvailabilityMacros.h>
#else
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 500
#endif
#endif
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <time.h>
#if defined(__linux__)
#include <sys/prctl.h>
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__)
#include <pthread_np.h>
#endif
#include "thpool.h"
#ifdef THPOOL_DEBUG
#define THPOOL_DEBUG 1
#else
#define THPOOL_DEBUG 0
#endif
#if !defined(DISABLE_PRINT) || defined(THPOOL_DEBUG)
#define err(str) fprintf(stderr, str)
#else
#define err(str)
#endif
#ifndef THPOOL_THREAD_NAME
#define THPOOL_THREAD_NAME thpool
#endif
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
static volatile int threads_keepalive;
static volatile int threads_on_hold;
/* ========================== STRUCTURES ============================ */
/* Binary semaphore */
typedef struct bsem {
pthread_mutex_t mutex;
pthread_cond_t cond;
int v;
} bsem;
/* Job */
typedef struct job{
struct job* prev; /* pointer to previous job */
void (*function)(void* arg); /* function pointer */
void* arg; /* function's argument */
} job;
/* Job queue */
typedef struct jobqueue{
pthread_mutex_t rwmutex; /* used for queue r/w access */
job *front; /* pointer to front of queue */
job *rear; /* pointer to rear of queue */
bsem *has_jobs; /* flag as binary semaphore */
int len; /* number of jobs in queue */
} jobqueue;
/* Thread */
typedef struct thread{
int id; /* friendly id */
pthread_t pthread; /* pointer to actual thread */
struct thpool_* thpool_p; /* access to thpool */
} thread;
/* Threadpool */
typedef struct thpool_{
thread** threads; /* pointer to threads */
volatile int num_threads_alive; /* threads currently alive */
volatile int num_threads_working; /* threads currently working */
pthread_mutex_t thcount_lock; /* used for thread count etc */
pthread_cond_t threads_all_idle; /* signal to thpool_wait */
jobqueue jobqueue; /* job queue */
} thpool_;
/* ========================== PROTOTYPES ============================ */
static int thread_init(thpool_* thpool_p, struct thread** thread_p, int id);
static void* thread_do(struct thread* thread_p);
static void thread_hold(int sig_id);
static void thread_destroy(struct thread* thread_p);
static int jobqueue_init(jobqueue* jobqueue_p);
static void jobqueue_clear(jobqueue* jobqueue_p);
static void jobqueue_push(jobqueue* jobqueue_p, struct job* newjob_p);
static struct job* jobqueue_pull(jobqueue* jobqueue_p);
static void jobqueue_destroy(jobqueue* jobqueue_p);
static void bsem_init(struct bsem *bsem_p, int value);
static void bsem_reset(struct bsem *bsem_p);
static void bsem_post(struct bsem *bsem_p);
static void bsem_post_all(struct bsem *bsem_p);
static void bsem_wait(struct bsem *bsem_p);
/* ========================== THREADPOOL ============================ */
/* Initialise thread pool */
struct thpool_* thpool_init(int num_threads){
threads_on_hold = 0;
threads_keepalive = 1;
if (num_threads < 0){
num_threads = 0;
}
/* Make new thread pool */
thpool_* thpool_p;
thpool_p = (struct thpool_*)malloc(sizeof(struct thpool_));
if (thpool_p == NULL){
err("thpool_init(): Could not allocate memory for thread pool\n");
return NULL;
}
thpool_p->num_threads_alive = 0;
thpool_p->num_threads_working = 0;
/* Initialise the job queue */
if (jobqueue_init(&thpool_p->jobqueue) == -1){
err("thpool_init(): Could not allocate memory for job queue\n");
free(thpool_p);
return NULL;
}
/* Make threads in pool */
thpool_p->threads = (struct thread**)malloc(num_threads * sizeof(struct thread *));
if (thpool_p->threads == NULL){
err("thpool_init(): Could not allocate memory for threads\n");
jobqueue_destroy(&thpool_p->jobqueue);
free(thpool_p);
return NULL;
}
pthread_mutex_init(&(thpool_p->thcount_lock), NULL);
pthread_cond_init(&thpool_p->threads_all_idle, NULL);
/* Thread init */
int n;
for (n=0; n<num_threads; n++){
thread_init(thpool_p, &thpool_p->threads[n], n);
#if THPOOL_DEBUG
printf("THPOOL_DEBUG: Created thread %d in pool \n", n);
#endif
}
/* Wait for threads to initialize */
while (thpool_p->num_threads_alive != num_threads) {}
return thpool_p;
}
/* Add work to the thread pool */
int thpool_add_work(thpool_* thpool_p, void (*function_p)(void*), void* arg_p){
job* newjob;
newjob=(struct job*)malloc(sizeof(struct job));
if (newjob==NULL){
err("thpool_add_work(): Could not allocate memory for new job\n");
return -1;
}
/* add function and argument */
newjob->function=function_p;
newjob->arg=arg_p;
/* add job to queue */
jobqueue_push(&thpool_p->jobqueue, newjob);
return 0;
}
/* Wait until all jobs have finished */
void thpool_wait(thpool_* thpool_p){
pthread_mutex_lock(&thpool_p->thcount_lock);
while (thpool_p->jobqueue.len || thpool_p->num_threads_working) {
pthread_cond_wait(&thpool_p->threads_all_idle, &thpool_p->thcount_lock);
}
pthread_mutex_unlock(&thpool_p->thcount_lock);
}
/* Destroy the threadpool */
void thpool_destroy(thpool_* thpool_p){
/* No need to destroy if it's NULL */
if (thpool_p == NULL) return ;
volatile int threads_total = thpool_p->num_threads_alive;
/* End each thread 's infinite loop */
threads_keepalive = 0;
/* Give one second to kill idle threads */
double TIMEOUT = 1.0;
time_t start, end;
double tpassed = 0.0;
time (&start);
while (tpassed < TIMEOUT && thpool_p->num_threads_alive){
bsem_post_all(thpool_p->jobqueue.has_jobs);
time (&end);
tpassed = difftime(end,start);
}
/* Poll remaining threads */
while (thpool_p->num_threads_alive){
bsem_post_all(thpool_p->jobqueue.has_jobs);
sleep(1);
}
/* Job queue cleanup */
jobqueue_destroy(&thpool_p->jobqueue);
/* Deallocs */
int n;
for (n=0; n < threads_total; n++){
thread_destroy(thpool_p->threads[n]);
}
free(thpool_p->threads);
free(thpool_p);
}
/* Pause all threads in threadpool */
void thpool_pause(thpool_* thpool_p) {
int n;
for (n=0; n < thpool_p->num_threads_alive; n++){
pthread_kill(thpool_p->threads[n]->pthread, SIGUSR1);
}
}
/* Resume all threads in threadpool */
void thpool_resume(thpool_* thpool_p) {
// resuming a single threadpool hasn't been
// implemented yet, meanwhile this suppresses
// the warnings
(void)thpool_p;
threads_on_hold = 0;
}
int thpool_num_threads_working(thpool_* thpool_p){
return thpool_p->num_threads_working;
}
/* ============================ THREAD ============================== */
/* Initialize a thread in the thread pool
*
* @param thread address to the pointer of the thread to be created
* @param id id to be given to the thread
* @return 0 on success, -1 otherwise.
*/
static int thread_init (thpool_* thpool_p, struct thread** thread_p, int id){
*thread_p = (struct thread*)malloc(sizeof(struct thread));
if (*thread_p == NULL){
err("thread_init(): Could not allocate memory for thread\n");
return -1;
}
(*thread_p)->thpool_p = thpool_p;
(*thread_p)->id = id;
pthread_create(&(*thread_p)->pthread, NULL, (void * (*)(void *)) thread_do, (*thread_p));
pthread_detach((*thread_p)->pthread);
return 0;
}
/* Sets the calling thread on hold */
static void thread_hold(int sig_id) {
(void)sig_id;
threads_on_hold = 1;
while (threads_on_hold){
sleep(1);
}
}
/* What each thread is doing
*
* In principle this is an endless loop. The only time this loop gets interrupted is once
* thpool_destroy() is invoked or the program exits.
*
* @param thread thread that will run this function
* @return nothing
*/
static void* thread_do(struct thread* thread_p){
/* Set thread name for profiling and debugging */
char thread_name[16] = {0};
snprintf(thread_name, 16, TOSTRING(THPOOL_THREAD_NAME) "-%d", thread_p->id);
#if defined(__linux__)
/* Use prctl instead to prevent using _GNU_SOURCE flag and implicit declaration */
prctl(PR_SET_NAME, thread_name);
#elif defined(__APPLE__) && defined(__MACH__)
pthread_setname_np(thread_name);
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
pthread_set_name_np(thread_p->pthread, thread_name);
#else
err("thread_do(): pthread_setname_np is not supported on this system");
#endif
/* Assure all threads have been created before starting serving */
thpool_* thpool_p = thread_p->thpool_p;
/* Register signal handler */
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_ONSTACK;
act.sa_handler = thread_hold;
if (sigaction(SIGUSR1, &act, NULL) == -1) {
err("thread_do(): cannot handle SIGUSR1");
}
/* Mark thread as alive (initialized) */
pthread_mutex_lock(&thpool_p->thcount_lock);
thpool_p->num_threads_alive += 1;
pthread_mutex_unlock(&thpool_p->thcount_lock);
while(threads_keepalive){
bsem_wait(thpool_p->jobqueue.has_jobs);
if (threads_keepalive){
pthread_mutex_lock(&thpool_p->thcount_lock);
thpool_p->num_threads_working++;
pthread_mutex_unlock(&thpool_p->thcount_lock);
/* Read job from queue and execute it */
void (*func_buff)(void*);
void* arg_buff;
job* job_p = jobqueue_pull(&thpool_p->jobqueue);
if (job_p) {
func_buff = job_p->function;
arg_buff = job_p->arg;
func_buff(arg_buff);
free(job_p);
}
pthread_mutex_lock(&thpool_p->thcount_lock);
thpool_p->num_threads_working--;
if (!thpool_p->num_threads_working) {
pthread_cond_signal(&thpool_p->threads_all_idle);
}
pthread_mutex_unlock(&thpool_p->thcount_lock);
}
}
pthread_mutex_lock(&thpool_p->thcount_lock);
thpool_p->num_threads_alive --;
pthread_mutex_unlock(&thpool_p->thcount_lock);
return NULL;
}
/* Frees a thread */
static void thread_destroy (thread* thread_p){
free(thread_p);
}
/* ============================ JOB QUEUE =========================== */
/* Initialize queue */
static int jobqueue_init(jobqueue* jobqueue_p){
jobqueue_p->len = 0;
jobqueue_p->front = NULL;
jobqueue_p->rear = NULL;
jobqueue_p->has_jobs = (struct bsem*)malloc(sizeof(struct bsem));
if (jobqueue_p->has_jobs == NULL){
return -1;
}
pthread_mutex_init(&(jobqueue_p->rwmutex), NULL);
bsem_init(jobqueue_p->has_jobs, 0);
return 0;
}
/* Clear the queue */
static void jobqueue_clear(jobqueue* jobqueue_p){
while(jobqueue_p->len){
free(jobqueue_pull(jobqueue_p));
}
jobqueue_p->front = NULL;
jobqueue_p->rear = NULL;
bsem_reset(jobqueue_p->has_jobs);
jobqueue_p->len = 0;
}
/* Add (allocated) job to queue
*/
static void jobqueue_push(jobqueue* jobqueue_p, struct job* newjob){
pthread_mutex_lock(&jobqueue_p->rwmutex);
newjob->prev = NULL;
switch(jobqueue_p->len){
case 0: /* if no jobs in queue */
jobqueue_p->front = newjob;
jobqueue_p->rear = newjob;
break;
default: /* if jobs in queue */
jobqueue_p->rear->prev = newjob;
jobqueue_p->rear = newjob;
}
jobqueue_p->len++;
bsem_post(jobqueue_p->has_jobs);
pthread_mutex_unlock(&jobqueue_p->rwmutex);
}
/* Get first job from queue(removes it from queue)
* Notice: Caller MUST hold a mutex
*/
static struct job* jobqueue_pull(jobqueue* jobqueue_p){
pthread_mutex_lock(&jobqueue_p->rwmutex);
job* job_p = jobqueue_p->front;
switch(jobqueue_p->len){
case 0: /* if no jobs in queue */
break;
case 1: /* if one job in queue */
jobqueue_p->front = NULL;
jobqueue_p->rear = NULL;
jobqueue_p->len = 0;
break;
default: /* if >1 jobs in queue */
jobqueue_p->front = job_p->prev;
jobqueue_p->len--;
/* more than one job in queue -> post it */
bsem_post(jobqueue_p->has_jobs);
}
pthread_mutex_unlock(&jobqueue_p->rwmutex);
return job_p;
}
/* Free all queue resources back to the system */
static void jobqueue_destroy(jobqueue* jobqueue_p){
jobqueue_clear(jobqueue_p);
free(jobqueue_p->has_jobs);
}
/* ======================== SYNCHRONISATION ========================= */
/* Init semaphore to 1 or 0 */
static void bsem_init(bsem *bsem_p, int value) {
if (value < 0 || value > 1) {
err("bsem_init(): Binary semaphore can take only values 1 or 0");
exit(1);
}
pthread_mutex_init(&(bsem_p->mutex), NULL);
pthread_cond_init(&(bsem_p->cond), NULL);
bsem_p->v = value;
}
/* Reset semaphore to 0 */
static void bsem_reset(bsem *bsem_p) {
pthread_mutex_destroy(&(bsem_p->mutex));
pthread_cond_destroy(&(bsem_p->cond));
bsem_init(bsem_p, 0);
}
/* Post to at least one thread */
static void bsem_post(bsem *bsem_p) {
pthread_mutex_lock(&bsem_p->mutex);
bsem_p->v = 1;
pthread_cond_signal(&bsem_p->cond);
pthread_mutex_unlock(&bsem_p->mutex);
}
/* Post to all threads */
static void bsem_post_all(bsem *bsem_p) {
pthread_mutex_lock(&bsem_p->mutex);
bsem_p->v = 1;
pthread_cond_broadcast(&bsem_p->cond);
pthread_mutex_unlock(&bsem_p->mutex);
}
/* Wait on semaphore until semaphore has value 0 */
static void bsem_wait(bsem* bsem_p) {
pthread_mutex_lock(&bsem_p->mutex);
while (bsem_p->v != 1) {
pthread_cond_wait(&bsem_p->cond, &bsem_p->mutex);
}
bsem_p->v = 0;
pthread_mutex_unlock(&bsem_p->mutex);
}

View File

@@ -1,187 +0,0 @@
/**********************************
* @author Johan Hanssen Seferidis
* License: MIT
*
**********************************/
#ifndef _THPOOL_
#define _THPOOL_
#ifdef __cplusplus
extern "C" {
#endif
/* =================================== API ======================================= */
typedef struct thpool_* threadpool;
/**
* @brief Initialize threadpool
*
* Initializes a threadpool. This function will not return until all
* threads have initialized successfully.
*
* @example
*
* ..
* threadpool thpool; //First we declare a threadpool
* thpool = thpool_init(4); //then we initialize it to 4 threads
* ..
*
* @param num_threads number of threads to be created in the threadpool
* @return threadpool created threadpool on success,
* NULL on error
*/
threadpool thpool_init(int num_threads);
/**
* @brief Add work to the job queue
*
* Takes an action and its argument and adds it to the threadpool's job queue.
* If you want to add to work a function with more than one arguments then
* a way to implement this is by passing a pointer to a structure.
*
* NOTICE: You have to cast both the function and argument to not get warnings.
*
* @example
*
* void print_num(int num){
* printf("%d\n", num);
* }
*
* int main() {
* ..
* int a = 10;
* thpool_add_work(thpool, (void*)print_num, (void*)a);
* ..
* }
*
* @param threadpool threadpool to which the work will be added
* @param function_p pointer to function to add as work
* @param arg_p pointer to an argument
* @return 0 on success, -1 otherwise.
*/
int thpool_add_work(threadpool, void (*function_p)(void*), void* arg_p);
/**
* @brief Wait for all queued jobs to finish
*
* Will wait for all jobs - both queued and currently running to finish.
* Once the queue is empty and all work has completed, the calling thread
* (probably the main program) will continue.
*
* Smart polling is used in wait. The polling is initially 0 - meaning that
* there is virtually no polling at all. If after 1 seconds the threads
* haven't finished, the polling interval starts growing exponentially
* until it reaches max_secs seconds. Then it jumps down to a maximum polling
* interval assuming that heavy processing is being used in the threadpool.
*
* @example
*
* ..
* threadpool thpool = thpool_init(4);
* ..
* // Add a bunch of work
* ..
* thpool_wait(thpool);
* puts("All added work has finished");
* ..
*
* @param threadpool the threadpool to wait for
* @return nothing
*/
void thpool_wait(threadpool);
/**
* @brief Pauses all threads immediately
*
* The threads will be paused no matter if they are idle or working.
* The threads return to their previous states once thpool_resume
* is called.
*
* While the thread is being paused, new work can be added.
*
* @example
*
* threadpool thpool = thpool_init(4);
* thpool_pause(thpool);
* ..
* // Add a bunch of work
* ..
* thpool_resume(thpool); // Let the threads start their magic
*
* @param threadpool the threadpool where the threads should be paused
* @return nothing
*/
void thpool_pause(threadpool);
/**
* @brief Unpauses all threads if they are paused
*
* @example
* ..
* thpool_pause(thpool);
* sleep(10); // Delay execution 10 seconds
* thpool_resume(thpool);
* ..
*
* @param threadpool the threadpool where the threads should be unpaused
* @return nothing
*/
void thpool_resume(threadpool);
/**
* @brief Destroy the threadpool
*
* This will wait for the currently active threads to finish and then 'kill'
* the whole threadpool to free up memory.
*
* @example
* int main() {
* threadpool thpool1 = thpool_init(2);
* threadpool thpool2 = thpool_init(2);
* ..
* thpool_destroy(thpool1);
* ..
* return 0;
* }
*
* @param threadpool the threadpool to destroy
* @return nothing
*/
void thpool_destroy(threadpool);
/**
* @brief Show currently working threads
*
* Working threads are the threads that are performing work (not idle).
*
* @example
* int main() {
* threadpool thpool1 = thpool_init(2);
* threadpool thpool2 = thpool_init(2);
* ..
* printf("Working threads: %d\n", thpool_num_threads_working(thpool1));
* ..
* return 0;
* }
*
* @param threadpool the threadpool of interest
* @return integer number of threads working
*/
int thpool_num_threads_working(threadpool);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -19,7 +19,6 @@ If docker version is lower than 23.0, build is failed by dockerignore [pattern i
!testdata/*.php
!testdata/*.txt
+!caddy
+!C-Thread-Pool
+!internal
```

View File

@@ -1,4 +1,7 @@
# syntax=docker/dockerfile:1
#checkov:skip=CKV_DOCKER_2
#checkov:skip=CKV_DOCKER_3
#checkov:skip=CKV_DOCKER_7
FROM php-base AS common
WORKDIR /app
@@ -27,8 +30,8 @@ CMD ["--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
HEALTHCHECK CMD curl -f http://localhost:2019/metrics || exit 1
# See https://caddyserver.com/docs/conventions#file-locations for details
ENV XDG_CONFIG_HOME /config
ENV XDG_DATA_HOME /data
ENV XDG_CONFIG_HOME=/config
ENV XDG_DATA_HOME=/data
EXPOSE 80
EXPOSE 443
@@ -50,7 +53,7 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
COPY --from=golang-base /usr/local/go /usr/local/go
ENV PATH /usr/local/go/bin:$PATH
ENV PATH=/usr/local/go/bin:$PATH
# This is required to link the FrankenPHP binary to the PHP binary
RUN apt-get update && \
@@ -80,13 +83,13 @@ RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get
WORKDIR /go/src/app
COPY --link *.* ./
COPY --link caddy caddy
COPY --link C-Thread-Pool C-Thread-Pool
COPY --link internal internal
COPY --link testdata testdata
# todo: automate this?
# see https://github.com/docker-library/php/blob/master/8.2/bookworm/zts/Dockerfile#L57-L59 for PHP values
ENV CGO_LDFLAGS="-lssl -lcrypto -lreadline -largon2 -lcurl -lonig -lz $PHP_LDFLAGS" CGO_CFLAGS="-DFRANKENPHP_VERSION=$FRANKENPHP_VERSION $PHP_CFLAGS" CGO_CPPFLAGS=$PHP_CPPFLAGS
# See https://github.com/docker-library/php/blob/master/8.3/bookworm/zts/Dockerfile#L57-L59 for PHP values
ENV CGO_CFLAGS="-DFRANKENPHP_VERSION=$FRANKENPHP_VERSION $PHP_CFLAGS"
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 install -ldflags "-w -s -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy'" && \

View File

@@ -55,7 +55,8 @@ You can also run command-line scripts with:
* [Real-time](https://frankenphp.dev/docs/mercure/)
* [Configuration](https://frankenphp.dev/docs/config/)
* [Docker images](https://frankenphp.dev/docs/docker/)
* [Deploy in production](docs/production.md)
* [Deploy in production](https://frankenphp.dev/docs/production/)
* [Performance optimization](https://frankenphp.dev/docs/performance/)
* [Create **standalone**, self-executable PHP apps](https://frankenphp.dev/docs/embed/)
* [Create static binaries](https://frankenphp.dev/docs/static/)
* [Compile from sources](https://frankenphp.dev/docs/compile/)
@@ -71,7 +72,7 @@ You can also run command-line scripts with:
* [API Platform](https://api-platform.com/docs/distribution/)
* [Laravel](https://frankenphp.dev/docs/laravel/)
* [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp)
* [WordPress](https://github.com/dunglas/frankenphp-wordpress)
* [WordPress](https://github.com/StephenMiracle/frankenwp)
* [Drupal](https://github.com/dunglas/frankenphp-drupal)
* [Joomla](https://github.com/alexandreelise/frankenphp-joomla)
* [TYPO3](https://github.com/ochorocho/franken-typo3)

16
SECURITY.md Normal file
View File

@@ -0,0 +1,16 @@
# Security Policy
## Supported Versions
Only the latest version is supported.
Please ensure that you're always using the latest release.
Binaries and Docker images are rebuilt nightly using the latest versions of dependencies.
## Reporting a Vulnerability
If you believe you have discovered a security issue directly affecting FrankenPHP,
please do **NOT** report it publicly but send a detailed report to [kevin+frankenphp-security@dunglas.dev](mailto:kevin+frankenphp-security@dunglas.dev?subject=Security%20issue%20affecting%20FrankenPHP).
Only vulnerabilities directly affecting FrankenPHP should be reported using this email.
Flaws affecting components used by FrankenPHP (PHP, Caddy, Go...) or using FrankenPHP (Laravel Octane, PHP Runtime...) should be reported to the relevant projects.

View File

@@ -1,6 +1,11 @@
# syntax=docker/dockerfile:1
#checkov:skip=CKV_DOCKER_2
#checkov:skip=CKV_DOCKER_3
#checkov:skip=CKV_DOCKER_7
FROM php-base AS common
ARG TARGETARCH
WORKDIR /app
RUN apk add --no-cache \
@@ -24,8 +29,8 @@ CMD ["--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
HEALTHCHECK CMD curl -f http://localhost:2019/metrics || exit 1
# See https://caddyserver.com/docs/conventions#file-locations for details
ENV XDG_CONFIG_HOME /config
ENV XDG_DATA_HOME /data
ENV XDG_CONFIG_HOME=/config
ENV XDG_DATA_HOME=/data
EXPOSE 80
EXPOSE 443
@@ -47,7 +52,7 @@ SHELL ["/bin/ash", "-eo", "pipefail", "-c"]
COPY --link --from=golang-base /usr/local/go /usr/local/go
ENV PATH /usr/local/go/bin:$PATH
ENV PATH=/usr/local/go/bin:$PATH
# hadolint ignore=SC2086
RUN apk add --no-cache --virtual .build-deps \
@@ -64,7 +69,25 @@ RUN apk add --no-cache --virtual .build-deps \
openssl-dev \
readline-dev \
sqlite-dev \
upx
upx \
# Needed for the custom Go build
git \
bash
# FIXME: temporary workaround for https://github.com/golang/go/issues/68285
WORKDIR /
RUN git clone https://go.googlesource.com/go goroot
WORKDIR /goroot
# Revert https://github.com/golang/go/commit/3560cf0afb3c29300a6c88ccd98256949ca7a6f6 to prevent the crash with musl
RUN git config --global user.email "build@example.com" && \
git config --global user.name "Build" && \
git checkout "$(go env GOVERSION)" && \
git revert 3560cf0afb3c29300a6c88ccd98256949ca7a6f6
WORKDIR /goroot/src
ENV GOHOSTARCH="$TARGETARCH"
RUN ./make.bash
ENV PATH="/goroot/bin:$PATH"
RUN go version
WORKDIR /go/src/app
@@ -78,13 +101,13 @@ RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get
WORKDIR /go/src/app
COPY --link *.* ./
COPY --link caddy caddy
COPY --link C-Thread-Pool C-Thread-Pool
COPY --link internal internal
COPY --link testdata testdata
# todo: automate this?
# see https://github.com/docker-library/php/blob/master/8.2/bookworm/zts/Dockerfile#L57-L59 for php values
ENV CGO_LDFLAGS="-lssl -lcrypto -lreadline -largon2 -lcurl -lonig -lz $PHP_LDFLAGS" CGO_CFLAGS="-DFRANKENPHP_VERSION=$FRANKENPHP_VERSION $PHP_CFLAGS" CGO_CPPFLAGS=$PHP_CPPFLAGS
# See https://github.com/docker-library/php/blob/master/8.3/alpine3.20/zts/Dockerfile#L53-L55
ENV CGO_CFLAGS="-DFRANKENPHP_VERSION=$FRANKENPHP_VERSION $PHP_CFLAGS"
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 install -ldflags "-w -s -extldflags '-Wl,-z,stack-size=0x80000' -X 'github.com/caddyserver/caddy/v2.CustomVersion=FrankenPHP $FRANKENPHP_VERSION PHP $PHP_VERSION Caddy'" && \

View File

@@ -1,142 +1,240 @@
#!/bin/sh
set -o errexit
set -x
if ! type "git" > /dev/null; then
echo "The \"git\" command must be installed."
exit 1
if ! type "git" >/dev/null 2>&1; then
echo "The \"git\" command must be installed."
exit 1
fi
arch="$(uname -m)"
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
md5binary="md5sum"
if [ "${os}" = "darwin" ]; then
os="mac"
md5binary="md5 -q"
os="mac"
md5binary="md5 -q"
fi
if [ "${os}" = "linux" ] && ! type "cmake" >/dev/null 2>&1; then
echo "The \"cmake\" command must be installed."
exit 1
fi
if [ -z "${PHP_EXTENSIONS}" ]; then
export PHP_EXTENSIONS="apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,gd,iconv,igbinary,intl,ldap,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pcntl,pdo,pdo_mysql,pdo_pgsql,pdo_sqlite,pgsql,phar,posix,readline,redis,session,simplexml,sockets,sodium,sqlite3,sysvsem,tokenizer,xml,xmlreader,xmlwriter,zip,zlib"
if [ -n "${EMBED}" ] && [ -f "${EMBED}/composer.json" ]; then
cd "${EMBED}"
PHP_EXTENSIONS="$(composer check-platform-reqs --no-dev 2>/dev/null | grep ^ext | sed -e 's/^ext-//' -e 's/ .*//' | xargs | tr ' ' ',')"
export PHP_EXTENSIONS
cd -
else
export PHP_EXTENSIONS="apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,ftp,gd,gmp,gettext,iconv,igbinary,imagick,intl,ldap,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,pcntl,pdo,pdo_mysql,pdo_pgsql,pdo_sqlite,pgsql,phar,posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sodium,sqlite3,ssh2,sysvmsg,sysvsem,sysvshm,tidy,tokenizer,xlswriter,xml,xmlreader,xmlwriter,zip,zlib,yaml,zstd"
fi
fi
if [ -z "${PHP_EXTENSION_LIBS}" ]; then
export PHP_EXTENSION_LIBS="bzip2,freetype,libavif,libjpeg,liblz4,libwebp,libzip"
export PHP_EXTENSION_LIBS="bzip2,freetype,libavif,libjpeg,liblz4,libwebp,libzip,nghttp2"
fi
# the Brotli library must always be built as it is required by http://github.com/dunglas/caddy-cbrotli
# The Brotli library must always be built as it is required by http://github.com/dunglas/caddy-cbrotli
if ! echo "${PHP_EXTENSION_LIBS}" | grep -q "\bbrotli\b"; then
export PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},brotli"
export PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},brotli"
fi
if [ -z "${PHP_VERSION}" ]; then
export PHP_VERSION="8.3"
export PHP_VERSION="8.3"
fi
if [ -z "${FRANKENPHP_VERSION}" ]; then
FRANKENPHP_VERSION="$(git rev-parse --verify HEAD)"
export FRANKENPHP_VERSION
FRANKENPHP_VERSION="$(git rev-parse --verify HEAD)"
export FRANKENPHP_VERSION
elif [ -d ".git/" ]; then
CURRENT_REF="$(git rev-parse --abbrev-ref HEAD)"
export CURRENT_REF
CURRENT_REF="$(git rev-parse --abbrev-ref HEAD)"
export CURRENT_REF
if echo "${FRANKENPHP_VERSION}" | grep -F -q "."; then
# Tag
if echo "${FRANKENPHP_VERSION}" | grep -F -q "."; then
# Tag
# Trim "v" prefix if any
FRANKENPHP_VERSION=${FRANKENPHP_VERSION#v}
export FRANKENPHP_VERSION
# Trim "v" prefix if any
FRANKENPHP_VERSION=${FRANKENPHP_VERSION#v}
export FRANKENPHP_VERSION
git checkout "v${FRANKENPHP_VERSION}"
else
git checkout "${FRANKENPHP_VERSION}"
fi
git checkout "v${FRANKENPHP_VERSION}"
else
git checkout "${FRANKENPHP_VERSION}"
fi
fi
bin="frankenphp-${os}-${arch}"
if [ -n "${CLEAN}" ]; then
rm -Rf dist/
go clean -cache
rm -Rf dist/
go clean -cache
fi
# Build libphp if necessary
if [ -f "dist/static-php-cli/buildroot/lib/libphp.a" ]; then
cd dist/static-php-cli
cd dist/static-php-cli
else
mkdir -p dist/
cd dist/
mkdir -p dist/
cd dist/
if [ -d "static-php-cli/" ]; then
cd static-php-cli/
git pull
else
git clone --depth 1 https://github.com/crazywhalecc/static-php-cli
cd static-php-cli/
fi
if [ -d "static-php-cli/" ]; then
cd static-php-cli/
git pull
else
git clone --depth 1 https://github.com/crazywhalecc/static-php-cli
cd static-php-cli/
fi
if type "brew" > /dev/null; then
if ! type "composer" > /dev/null; then
packages="composer"
fi
if ! type "go" > /dev/null; then
packages="${packages} go"
fi
if [ -n "${RELEASE}" ] && ! type "gh" > /dev/null; then
packages="${packages} gh"
fi
if type "brew" >/dev/null 2>&1; then
if ! type "composer" >/dev/null; then
packages="composer"
fi
if ! type "go" >/dev/null; then
packages="${packages} go"
fi
if [ -n "${RELEASE}" ] && ! type "gh" >/dev/null 2>&1; then
packages="${packages} gh"
fi
if [ -n "${packages}" ]; then
# shellcheck disable=SC2086
brew install --formula --quiet ${packages}
fi
fi
if [ -n "${packages}" ]; then
# shellcheck disable=SC2086
brew install --formula --quiet ${packages}
fi
fi
composer install --no-dev -a
composer install --no-dev -a
if [ "${os}" = "linux" ]; then
extraOpts="--disable-opcache-jit"
fi
if [ "${os}" = "linux" ]; then
extraOpts="--disable-opcache-jit"
fi
if [ -n "${DEBUG_SYMBOLS}" ]; then
extraOpts="${extraOpts} --no-strip"
fi
if [ -n "${DEBUG_SYMBOLS}" ]; then
extraOpts="${extraOpts} --no-strip"
fi
./bin/spc doctor --auto-fix
./bin/spc download --with-php="${PHP_VERSION}" --for-extensions="${PHP_EXTENSIONS}" --for-libs="${PHP_EXTENSION_LIBS}" --ignore-cache-sources=php-src
# shellcheck disable=SC2086
./bin/spc build --debug --enable-zts --build-embed ${extraOpts} "${PHP_EXTENSIONS}" --with-libs="${PHP_EXTENSION_LIBS}"
./bin/spc doctor --auto-fix
./bin/spc download --with-php="${PHP_VERSION}" --for-extensions="${PHP_EXTENSIONS}" --for-libs="${PHP_EXTENSION_LIBS}" --ignore-cache-sources=php-src --prefer-pre-built
# shellcheck disable=SC2086
./bin/spc build --debug --enable-zts --build-embed ${extraOpts} "${PHP_EXTENSIONS}" --with-libs="${PHP_EXTENSION_LIBS}"
fi
# See https://github.com/docker-library/php/blob/master/8.3/alpine3.20/zts/Dockerfile#L53-L55
CGO_CFLAGS="-DFRANKENPHP_VERSION=${FRANKENPHP_VERSION} -I${PWD}/buildroot/include/ $(./buildroot/bin/php-config --includes | sed s#-I/#-I"${PWD}"/buildroot/#g)"
if [ -n "${DEBUG_SYMBOLS}" ]; then
CGO_CFLAGS="-g ${CGO_CFLAGS}"
CGO_CFLAGS="-g ${CGO_CFLAGS}"
else
CGO_CFLAGS="-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 ${CGO_CFLAGS}"
fi
export CGO_CFLAGS
export CGO_CPPFLAGS="${CGO_CFLAGS}"
if [ "${os}" = "mac" ]; then
export CGO_LDFLAGS="-framework CoreFoundation -framework SystemConfiguration"
export CGO_LDFLAGS="-framework CoreFoundation -framework SystemConfiguration"
elif [ "${os}" = "linux" ] && [ -z "${DEBUG_SYMBOLS}" ]; then
CGO_LDFLAGS="-Wl,-O1 -pie"
fi
CGO_LDFLAGS="${CGO_LDFLAGS} ${PWD}/buildroot/lib/libbrotlicommon.a ${PWD}/buildroot/lib/libbrotlienc.a ${PWD}/buildroot/lib/libbrotlidec.a $(./buildroot/bin/php-config --ldflags) $(./buildroot/bin/php-config --libs)"
CGO_LDFLAGS="${CGO_LDFLAGS} ${PWD}/buildroot/lib/libbrotlicommon.a ${PWD}/buildroot/lib/libbrotlienc.a ${PWD}/buildroot/lib/libbrotlidec.a $(./buildroot/bin/php-config --ldflags || true) $(./buildroot/bin/php-config --libs || true)"
if [ "${os}" = "linux" ]; then
if echo "${PHP_EXTENSIONS}" | grep -qE "\b(intl|imagick|grpc|v8js|protobuf|mongodb|tbb)\b"; then
CGO_LDFLAGS="${CGO_LDFLAGS} -lstdc++"
fi
fi
export CGO_LDFLAGS
LIBPHP_VERSION="$(./buildroot/bin/php-config --version)"
export LIBPHP_VERSION
cd ../..
# Embed PHP app, if any
if [ -n "${EMBED}" ] && [ -d "${EMBED}" ]; then
tar -cf app.tar -C "${EMBED}" .
${md5binary} app.tar > app_checksum.txt
fi
cd ../
if [ "${os}" = "linux" ]; then
extraExtldflags="-Wl,-z,stack-size=0x80000"
if [ -n "${MIMALLOC}" ]; then
# Replace musl's mallocng by mimalloc
# The default musl allocator is slow, especially when used by multi-threaded apps,
# and triggers weird bugs
# Adapted from https://www.tweag.io/blog/2023-08-10-rust-static-link-with-mimalloc/
echo 'The USE_MIMALLOC environment variable is EXPERIMENTAL.'
echo 'This option can be removed or its behavior modified at any time.'
if [ ! -f "mimalloc/out/libmimalloc.a" ]; then
if [ -d "mimalloc" ]; then
cd mimalloc/
git reset --hard
git clean -xdf
git fetch --tags
else
git clone https://github.com/microsoft/mimalloc.git
cd mimalloc/
fi
git checkout "$(git describe --tags "$(git rev-list --tags --max-count=1 || true)" || true)"
curl -f -L --retry 5 https://raw.githubusercontent.com/tweag/rust-alpine-mimalloc/b26002b49d466a295ea8b50828cb7520a71a872a/mimalloc.diff -o mimalloc.diff
patch -p1 <mimalloc.diff
mkdir -p out/
cd out/
if [ -n "${DEBUG_SYMBOLS}" ]; then
cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DMI_BUILD_SHARED=OFF \
-DMI_BUILD_OBJECT=OFF \
-DMI_BUILD_TESTS=OFF \
../
else
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DMI_BUILD_SHARED=OFF \
-DMI_BUILD_OBJECT=OFF \
-DMI_BUILD_TESTS=OFF \
../
fi
make -j"$(nproc || true)"
cd ../../
fi
if [ -n "${DEBUG_SYMBOLS}" ]; then
libmimalloc_path=mimalloc/out/libmimalloc-debug.a
else
libmimalloc_path=mimalloc/out/libmimalloc.a
fi
# Patch musl library to use mimalloc
for libc_path in "/usr/local/musl/lib/libc.a" "/usr/local/musl/$(uname -m)-linux-musl/lib/libc.a" "/usr/lib/libc.a"; do
if [ ! -f "${libc_path}" ] || [ -f "${libc_path}.unpatched" ]; then
continue
fi
{
echo "CREATE libc.a"
echo "ADDLIB ${libc_path}"
echo "DELETE aligned_alloc.lo calloc.lo donate.lo free.lo libc_calloc.lo lite_malloc.lo malloc.lo malloc_usable_size.lo memalign.lo posix_memalign.lo realloc.lo reallocarray.lo valloc.lo"
echo "ADDLIB ${libmimalloc_path}"
echo "SAVE"
} | ar -M
mv "${libc_path}" "${libc_path}.unpatched"
mv libc.a "${libc_path}"
done
fi
# Increase the default stack size to prevents issues with code including many files such as Symfony containers
extraExtldflags="-Wl,-z,stack-size=0x80000"
fi
if [ -z "${DEBUG_SYMBOLS}" ]; then
extraLdflags="-w -s"
extraLdflags="-w -s"
fi
cd ../
# Embed PHP app, if any
if [ -n "${EMBED}" ] && [ -d "${EMBED}" ]; then
tar -cf app.tar -C "${EMBED}" .
${md5binary} app.tar | awk '{printf $1}' >app_checksum.txt
fi
cd caddy/frankenphp/
@@ -145,20 +243,20 @@ go build -buildmode=pie -tags "cgo netgo osusergo static_build" -ldflags "-linkm
cd ../..
if [ -d "${EMBED}" ]; then
truncate -s 0 app.tar
truncate -s 0 app_checksum.txt
truncate -s 0 app.tar
truncate -s 0 app_checksum.txt
fi
if type "upx" > /dev/null && [ -z "${DEBUG_SYMBOLS}" ] && [ -z "${NO_COMPRESS}" ]; then
upx --best "dist/${bin}"
if type "upx" >/dev/null 2>&1 && [ -z "${DEBUG_SYMBOLS}" ] && [ -z "${NO_COMPRESS}" ]; then
upx --best "dist/${bin}"
fi
"dist/${bin}" version
if [ -n "${RELEASE}" ]; then
gh release upload "v${FRANKENPHP_VERSION}" "dist/${bin}" --repo dunglas/frankenphp --clobber
gh release upload "v${FRANKENPHP_VERSION}" "dist/${bin}" --repo dunglas/frankenphp --clobber
fi
if [ -n "${CURRENT_REF}" ]; then
git checkout "${CURRENT_REF}"
git checkout "${CURRENT_REF}"
fi

View File

@@ -6,9 +6,11 @@ package caddy
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"path/filepath"
"strconv"
"strings"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig"
@@ -26,9 +28,14 @@ const defaultDocumentRoot = "public"
func init() {
caddy.RegisterModule(FrankenPHPApp{})
caddy.RegisterModule(FrankenPHPModule{})
httpcaddyfile.RegisterGlobalOption("frankenphp", parseGlobalOption)
httpcaddyfile.RegisterHandlerDirective("php", parseCaddyfile)
httpcaddyfile.RegisterDirectiveOrder("php", "before", "file_server")
httpcaddyfile.RegisterDirective("php_server", parsePhpServer)
httpcaddyfile.RegisterDirectiveOrder("php_server", "before", "file_server")
}
type mainPHPinterpreterKeyType int
@@ -205,8 +212,12 @@ type FrankenPHPModule struct {
// ResolveRootSymlink enables resolving the `root` directory to its actual value by evaluating a symbolic link, if one exists.
ResolveRootSymlink *bool `json:"resolve_root_symlink,omitempty"`
// Env sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables.
Env frankenphp.PreparedEnv `json:"env,omitempty"`
logger *zap.Logger
Env map[string]string `json:"env,omitempty"`
resolvedDocumentRoot string
preparedEnv frankenphp.PreparedEnv
preparedEnvNeedsReplacement bool
logger *zap.Logger
}
// CaddyModule returns the Caddy module information.
@@ -244,26 +255,69 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error {
f.ResolveRootSymlink = &rrs
}
if !needReplacement(f.Root) {
root, err := filepath.Abs(f.Root)
if err != nil {
return fmt.Errorf("unable to make the root path absolute: %w", err)
}
f.resolvedDocumentRoot = root
if *f.ResolveRootSymlink {
root, err := filepath.EvalSymlinks(root)
if err != nil {
return fmt.Errorf("unable to resolve root symlink: %w", err)
}
f.resolvedDocumentRoot = root
}
}
if f.preparedEnv == nil {
f.preparedEnv = frankenphp.PrepareEnv(f.Env)
for e := range f.preparedEnv {
if needReplacement(e) {
f.preparedEnvNeedsReplacement = true
break
}
}
}
return nil
}
// needReplacement checks if a string contains placeholdes.
func needReplacement(s string) bool {
return strings.Contains(s, "{") || strings.Contains(s, "}")
}
// ServeHTTP implements caddyhttp.MiddlewareHandler.
// TODO: Expose TLS versions as env vars, as Apache's mod_ssl: https://github.com/caddyserver/caddy/blob/master/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go#L298
func (f FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ caddyhttp.Handler) error {
origReq := r.Context().Value(caddyhttp.OriginalRequestCtxKey).(http.Request)
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
documentRoot := repl.ReplaceKnown(f.Root, "")
var documentRootOption frankenphp.RequestOption
if f.resolvedDocumentRoot == "" {
documentRootOption = frankenphp.WithRequestDocumentRoot(repl.ReplaceKnown(f.Root, ""), *f.ResolveRootSymlink)
} else {
documentRootOption = frankenphp.WithRequestResolvedDocumentRoot(f.resolvedDocumentRoot)
}
env := make(map[string]string, len(f.Env)+1)
env := make(map[string]string, len(f.preparedEnv)+1)
env["REQUEST_URI\x00"] = origReq.URL.RequestURI()
for k, v := range f.Env {
env[k] = repl.ReplaceKnown(v, "")
for k, v := range f.preparedEnv {
if f.preparedEnvNeedsReplacement {
env[k] = repl.ReplaceKnown(v, "")
} else {
env[k] = v
}
}
fr, err := frankenphp.NewRequestWithContext(
r,
frankenphp.WithRequestDocumentRoot(documentRoot, *f.ResolveRootSymlink),
documentRootOption,
frankenphp.WithRequestSplitPath(f.SplitPath),
frankenphp.WithRequestPreparedEnv(env),
)
@@ -298,24 +352,26 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.ArgErr()
}
if f.Env == nil {
f.Env = make(frankenphp.PreparedEnv)
f.Env = make(map[string]string)
f.preparedEnv = make(frankenphp.PreparedEnv)
}
f.Env[args[0]+"\x00"] = args[1]
f.Env[args[0]] = args[1]
f.preparedEnv[args[0]+"\x00"] = args[1]
case "resolve_root_symlink":
if !d.NextArg() {
continue
}
v, err := strconv.ParseBool(d.Val())
if err != nil {
return err
}
if d.NextArg() {
if v, err := strconv.ParseBool(d.Val()); err == nil {
f.ResolveRootSymlink = &v
if d.NextArg() {
return d.ArgErr()
}
}
return d.ArgErr()
}
rrs := true
f.ResolveRootSymlink = &rrs
f.ResolveRootSymlink = &v
}
}
}

View File

@@ -120,7 +120,7 @@ func TestEnv(t *testing.T) {
frankenphp {
worker {
file ../testdata/env.php
file ../testdata/worker-env.php
num 1
env FOO bar
}
@@ -137,7 +137,90 @@ func TestEnv(t *testing.T) {
}
`, "caddyfile")
tester.AssertGetResponse("http://localhost:9080/env.php", http.StatusOK, "bazbar")
tester.AssertGetResponse("http://localhost:9080/worker-env.php", http.StatusOK, "bazbar")
}
func TestJsonEnv(t *testing.T) {
tester := caddytest.NewTester(t)
tester.InitServer(`
{
"admin": {
"listen": "localhost:2999"
},
"apps": {
"frankenphp": {
"workers": [
{
"env": {
"FOO": "bar"
},
"file_name": "../testdata/worker-env.php",
"num": 1
}
]
},
"http": {
"http_port": 9080,
"https_port": 9443,
"servers": {
"srv0": {
"listen": [
":9080"
],
"routes": [
{
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"env": {
"FOO": "baz"
},
"handler": "php",
"root": "../testdata"
}
]
}
]
}
]
}
]
}
],
"match": [
{
"host": [
"localhost"
]
}
],
"terminal": true
}
]
}
}
},
"pki": {
"certificate_authorities": {
"local": {
"install_trust": false
}
}
}
}
}
`, "json")
tester.AssertGetResponse("http://localhost:9080/worker-env.php", http.StatusOK, "bazbar")
}
func TestPHPServerDirective(t *testing.T) {
@@ -150,7 +233,6 @@ func TestPHPServerDirective(t *testing.T) {
https_port 9443
frankenphp
order php_server before reverse_proxy
}
localhost:9080 {

View File

@@ -5,12 +5,6 @@
#worker /path/to/your/worker.php
{$FRANKENPHP_CONFIG}
}
# https://caddyserver.com/docs/caddyfile/directives#sorting-algorithm
order mercure after encode
order vulcain after reverse_proxy
order php_server before file_server
order php before file_server
}
{$CADDY_EXTRA_CONFIG}
@@ -19,11 +13,8 @@
#log {
# # Redact the authorization query parameter that can be set by Mercure
# format filter {
# wrap console
# fields {
# uri query {
# replace authorization REDACTED
# }
# request>uri query {
# replace authorization REDACTED
# }
# }
#}

View File

@@ -1,10 +1,7 @@
package main
import (
"github.com/caddyserver/caddy/v2"
caddycmd "github.com/caddyserver/caddy/v2/cmd"
"go.uber.org/automaxprocs/maxprocs"
"go.uber.org/zap"
// plug in Caddy modules here.
_ "github.com/caddyserver/caddy/v2/modules/standard"
@@ -15,11 +12,5 @@ import (
)
func main() {
undo, err := maxprocs.Set()
defer undo()
if err != nil {
caddy.Log().Warn("failed to set GOMAXPROCS", zap.Error(err))
}
caddycmd.Main()
}

View File

@@ -1,22 +1,19 @@
module github.com/dunglas/frankenphp/caddy
go 1.21
toolchain go1.22.0
go 1.22.0
replace github.com/dunglas/frankenphp => ../
retract v1.0.0-rc.1 // Human error
require (
github.com/caddyserver/caddy/v2 v2.7.6
github.com/caddyserver/certmagic v0.20.0
github.com/caddyserver/caddy/v2 v2.8.4
github.com/caddyserver/certmagic v0.21.3
github.com/dunglas/caddy-cbrotli v1.0.0
github.com/dunglas/frankenphp v1.1.2
github.com/dunglas/mercure/caddy v0.15.10
github.com/dunglas/vulcain/caddy v1.0.2
github.com/spf13/cobra v1.8.0
go.uber.org/automaxprocs v1.5.3
github.com/dunglas/frankenphp v1.2.5
github.com/dunglas/mercure/caddy v0.16.3
github.com/dunglas/vulcain/caddy v1.0.5
github.com/spf13/cobra v1.8.1
go.uber.org/zap v1.27.0
)
@@ -25,175 +22,179 @@ require github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/MauriceGit/skiplist v0.0.0-20211105230623-77f5c8d3e145 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/RoaringBitmap/roaring v1.9.0 // indirect
github.com/alecthomas/chroma/v2 v2.12.0 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
github.com/MicahParks/jwkset v0.5.18 // indirect
github.com/MicahParks/keyfunc/v3 v3.3.3 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/RoaringBitmap/roaring v1.9.4 // indirect
github.com/alecthomas/chroma/v2 v2.14.0 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/bits-and-blooms/bitset v1.14.2 // indirect
github.com/caddyserver/zerossl v0.1.3 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/dgraph-io/badger v1.6.2 // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dlclark/regexp2 v1.11.0 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/dolthub/maphash v0.1.0 // indirect
github.com/dunglas/httpsfv v1.0.2 // indirect
github.com/dunglas/mercure v0.15.10 // indirect
github.com/dunglas/vulcain v1.0.2 // indirect
github.com/dunglas/mercure v0.16.3 // indirect
github.com/dunglas/vulcain v1.0.5 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gammazero/deque v0.2.1 // indirect
github.com/getkin/kin-openapi v0.123.0 // indirect
github.com/go-chi/chi/v5 v5.0.10 // indirect
github.com/getkin/kin-openapi v0.124.0 // indirect
github.com/go-chi/chi/v5 v5.1.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
github.com/go-kit/kit v0.13.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/glog v1.2.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/glog v1.2.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/brotli/go/cbrotli v0.0.0-20240116120200-adbc354d23af // indirect
github.com/google/cel-go v0.15.1 // indirect
github.com/google/certificate-transparency-go v1.1.7 // indirect
github.com/google/cel-go v0.21.0 // indirect
github.com/google/certificate-transparency-go v1.1.8-0.20240110162603-74a5dd331745 // indirect
github.com/google/go-tpm v0.9.0 // indirect
github.com/google/go-tspi v0.3.0 // indirect
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/handlers v1.5.2 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/invopop/yaml v0.2.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.14.3 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/invopop/yaml v0.3.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jackc/pgtype v1.14.2 // indirect
github.com/jackc/pgx/v4 v4.18.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.6.0 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kevburnsjr/skipfilter v0.0.1 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/libdns/libdns v0.2.1 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/libdns/libdns v0.2.2 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/mastercactapus/proxyprotocol v0.0.4 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/maypok86/otter v1.2.0 // indirect
github.com/maypok86/otter v1.2.2 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mholt/acmez v1.2.0 // indirect
github.com/micromdm/scep/v2 v2.1.0 // indirect
github.com/miekg/dns v1.1.58 // indirect
github.com/mholt/acmez/v2 v2.0.2 // indirect
github.com/miekg/dns v1.1.62 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/onsi/ginkgo/v2 v2.15.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/ginkgo/v2 v2.20.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/pires/go-proxyproto v0.7.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.19.0 // indirect
github.com/prometheus/client_model v0.6.0 // indirect
github.com/prometheus/common v0.50.0 // indirect
github.com/prometheus/procfs v0.13.0 // indirect
github.com/prometheus/client_golang v1.20.2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/quic-go v0.41.0 // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/quic-go/quic-go v0.46.0 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/slackhq/nebula v1.8.2 // indirect
github.com/smallstep/certificates v0.25.0 // indirect
github.com/smallstep/nosql v0.6.0 // indirect
github.com/slackhq/nebula v1.9.3 // indirect
github.com/smallstep/certificates v0.27.2 // indirect
github.com/smallstep/nosql v0.7.0 // indirect
github.com/smallstep/pkcs7 v0.0.0-20240723090913-5e2c6a136dfa // indirect
github.com/smallstep/scep v0.0.0-20240214080410-892e41795b99 // indirect
github.com/smallstep/truststore v0.13.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.18.2 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tailscale/tscert v0.0.0-20230806124524-28a91b69a046 // indirect
github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53 // indirect
github.com/tidwall/gjson v1.17.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/unrolled/secure v1.14.0 // indirect
github.com/urfave/cli v1.22.14 // indirect
github.com/unrolled/secure v1.15.0 // indirect
github.com/urfave/cli v1.22.15 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
github.com/yuin/goldmark v1.7.0 // indirect
github.com/yuin/goldmark v1.7.4 // indirect
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
go.etcd.io/bbolt v1.3.9 // indirect
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect
github.com/zeebo/blake3 v0.2.4 // indirect
go.etcd.io/bbolt v1.3.11 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/contrib/propagators/autoprop v0.45.0 // indirect
go.opentelemetry.io/contrib/propagators/aws v1.20.0 // indirect
go.opentelemetry.io/contrib/propagators/b3 v1.20.0 // indirect
go.opentelemetry.io/contrib/propagators/jaeger v1.20.0 // indirect
go.opentelemetry.io/contrib/propagators/ot v1.20.0 // indirect
go.opentelemetry.io/otel v1.23.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect
go.opentelemetry.io/otel/metric v1.23.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.21.0 // indirect
go.opentelemetry.io/otel/trace v1.23.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.step.sm/cli-utils v0.8.0 // indirect
go.step.sm/crypto v0.36.0 // indirect
go.step.sm/linkedca v0.20.1 // indirect
go.step.sm/cli-utils v0.9.0 // indirect
go.step.sm/crypto v0.51.1 // indirect
go.step.sm/linkedca v0.22.1 // indirect
go.uber.org/automaxprocs v1.5.3 // indirect
go.uber.org/mock v0.4.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240228224816-df926f6c8641 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect
google.golang.org/grpc v1.62.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
go.uber.org/zap/exp v0.2.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/crypto/x509roots/fallback v0.0.0-20240806160748-b2d3a6a4b4d3 // indirect
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
golang.org/x/mod v0.20.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/term v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.6.0 // indirect
golang.org/x/tools v0.24.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
howett.net/plist v1.0.1 // indirect
)

View File

@@ -1,22 +1,28 @@
cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y=
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI=
cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
cloud.google.com/go/kms v1.15.2 h1:lh6qra6oC4AyWe5fUUUBe/S27k12OHAleOOOw6KakdE=
cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w=
cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE=
cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs=
cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI=
cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I=
cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg=
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
cloud.google.com/go/iam v1.1.10 h1:ZSAr64oEhQSClwBL670MsJAW5/RLiC6kfw3Bqmd5ZDI=
cloud.google.com/go/iam v1.1.10/go.mod h1:iEgMq62sg8zx446GCaijmA2Miwg5o3UbO+nI47WHJps=
cloud.google.com/go/kms v1.18.3 h1:8+Z2S4bQDSCdghB5ZA5dVDDJTLmnkRlowtFiXqMFd74=
cloud.google.com/go/kms v1.18.3/go.mod h1:y/Lcf6fyhbdn7MrG1VaDqXxM8rhOBc5rWcWAhcvZjQU=
cloud.google.com/go/longrunning v0.5.9 h1:haH9pAuXdPAMqHvzX0zlWQigXT7B0+CL4/2nXXdBo5k=
cloud.google.com/go/longrunning v0.5.9/go.mod h1:HD+0l9/OOW0za6UWdKJtXoFAX/BGg/3Wj8p10NeWF7c=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
@@ -25,47 +31,78 @@ github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBa
github.com/MauriceGit/skiplist v0.0.0-20191117202105-643e379adb62/go.mod h1:877WBceefKn14QwVVn4xRFUsHsZb9clICgdeTj4XsUg=
github.com/MauriceGit/skiplist v0.0.0-20211105230623-77f5c8d3e145 h1:1yw6O62BReQ+uA1oyk9XaQTvLhcoHWmoQAgXmDFXpIY=
github.com/MauriceGit/skiplist v0.0.0-20211105230623-77f5c8d3e145/go.mod h1:877WBceefKn14QwVVn4xRFUsHsZb9clICgdeTj4XsUg=
github.com/MicahParks/jwkset v0.5.18 h1:WLdyMngF7rCrnstQxA7mpRoxeaWqGzPM/0z40PJUK4w=
github.com/MicahParks/jwkset v0.5.18/go.mod h1:q8ptTGn/Z9c4MwbcfeCDssADeVQb3Pk7PnVxrvi+2QY=
github.com/MicahParks/keyfunc/v3 v3.3.3 h1:c6j9oSu1YUo0k//KwF1miIQlEMtqNlj7XBFLB8jtEmY=
github.com/MicahParks/keyfunc/v3 v3.3.3/go.mod h1:f/UMyXdKfkZzmBeBFUeYk+zu066J1Fcl48f7Wnl5Z48=
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/RoaringBitmap/roaring v0.9.4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
github.com/RoaringBitmap/roaring v1.9.0 h1:lwKhr90/j0jVXJyh5X+vQN1VVn77rQFfYnh6RDRGCcE=
github.com/RoaringBitmap/roaring v1.9.0/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2K2ink=
github.com/alecthomas/assert/v2 v2.2.1/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/RoaringBitmap/roaring v1.9.4 h1:yhEIoH4YezLYT04s1nHehNO64EKFTop/wBhxv2QzDdQ=
github.com/RoaringBitmap/roaring v1.9.4/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
github.com/alecthomas/chroma/v2 v2.12.0 h1:Wh8qLEgMMsN7mgyG8/qIpegky2Hvzr4By6gEF7cmWgw=
github.com/alecthomas/chroma/v2 v2.12.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b h1:uUXgbcPDK3KpW29o4iy7GtuappbWT0l5NaMo9H9pJDw=
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/aws/aws-sdk-go v1.46.4 h1:48tKgtm9VMPkb6y7HuYlsfhQmoIRAsTEXTsWLVlty4M=
github.com/aws/aws-sdk-go v1.46.4/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY=
github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90=
github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg=
github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI=
github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII=
github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 h1:UPTdlTOwWUX49fVi7cymEN6hDqCwe3LNv1vi7TXUutk=
github.com/aws/aws-sdk-go-v2/service/kms v1.35.3/go.mod h1:gjDP16zn+WWalyaUqwCCioQ8gU8lzttCCc9jYsiQI/8=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ=
github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/caddyserver/caddy/v2 v2.7.6 h1:w0NymbG2m9PcvKWsrXO6EEkY9Ru4FJK8uQbYcev1p3A=
github.com/caddyserver/caddy/v2 v2.7.6/go.mod h1:JCiwFMnRWjk8lOa7po0wM/75kwd38ccJPMSrXvQCMQ0=
github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc=
github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg=
github.com/bits-and-blooms/bitset v1.14.2 h1:YXVoyPndbdvcEVcseEovVfp0qjJp7S+i5+xgp/Nfbdc=
github.com/bits-and-blooms/bitset v1.14.2/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/caddyserver/caddy/v2 v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=
github.com/caddyserver/caddy/v2 v2.8.4/go.mod h1:vmDAHp3d05JIvuhc24LmnxVlsZmWnUwbP5WMjzcMPWw=
github.com/caddyserver/certmagic v0.21.3 h1:pqRRry3yuB4CWBVq9+cUqu+Y6E2z8TswbhNx1AZeYm0=
github.com/caddyserver/certmagic v0.21.3/go.mod h1:Zq6pklO9nVRl3DIFUw9gVUfXKdpc/0qwTUAQMBlfgtI=
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
@@ -75,18 +112,12 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -104,22 +135,22 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ=
github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4=
github.com/dunglas/caddy-cbrotli v1.0.0 h1:+WNqXBkWyMcIpXB2rVZ3nwcElUbuAzf0kPxNXU4D+u0=
github.com/dunglas/caddy-cbrotli v1.0.0/go.mod h1:KZsUu3fnQBgO0o3YDoQuO3Z61dFgUncr1F8rg8acwQw=
github.com/dunglas/httpsfv v1.0.2 h1:iERDp/YAfnojSDJ7PW3dj1AReJz4MrwbECSSE59JWL0=
github.com/dunglas/httpsfv v1.0.2/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg=
github.com/dunglas/mercure v0.15.10 h1:U2CmOmOg2b8CFipjHCLweywjII6iwrIFfWepdkWdekU=
github.com/dunglas/mercure v0.15.10/go.mod h1:RLRg+ZBrNLqmvgO5yIAdXjR9s4gR3p3r/bgCl/Wd5rQ=
github.com/dunglas/mercure/caddy v0.15.10 h1:DGIUJpvwT127XYQguTmA+aS3RTL0+fFv4c7Naqs/iDE=
github.com/dunglas/mercure/caddy v0.15.10/go.mod h1:4Ai8/5HMYU/wkVRQ54G2REpGIEwV73RgeycbBEW8EAI=
github.com/dunglas/vulcain v1.0.2 h1:SVZ1zPn4sw5xC0oVOoUdw+5nQF1yZ5tyJkyzWtZ7vTw=
github.com/dunglas/vulcain v1.0.2/go.mod h1:KcW9ni72f6qjfxMq+/yvHT7ZSbdQErEwj4cWNaTkS/k=
github.com/dunglas/vulcain/caddy v1.0.2 h1:nTR5uGHPUHj8D5oI0E8TpZ0BMSTlqQvsQD1TMaNJ2mk=
github.com/dunglas/vulcain/caddy v1.0.2/go.mod h1:t9P6SbtnTj0qyGaIx765YjthZ0hxLYutvM4+oKuVG68=
github.com/dunglas/mercure v0.16.3 h1:zDEBFpvV61SlJnJYhFM87GKB4c2F4zdOKfs/xnrw/7Y=
github.com/dunglas/mercure v0.16.3/go.mod h1:hjqBKhcZDPMwa3oeOL5jQOghUgBl5bBiArQQTz9KX1M=
github.com/dunglas/mercure/caddy v0.16.3 h1:/xRZmM48kmaXtsjW1w0IAwoKlsqrQqi3oDKcMoz2i2s=
github.com/dunglas/mercure/caddy v0.16.3/go.mod h1:uwjaRLR3FnePFB8KmqxzcL696PYBXNvR7k/DpGepMRA=
github.com/dunglas/vulcain v1.0.5 h1:oWZFD5d2NQL5HdTvE5ZDlWzLTAjN3yyxHha5TMrLtCU=
github.com/dunglas/vulcain v1.0.5/go.mod h1:IgSv0R4mqNmJtfinnl9TcRGHqsPaBFesT5TSvY4PTY0=
github.com/dunglas/vulcain/caddy v1.0.5 h1:GOkyqoOu3uTnOSnFXMKgHU+jL1D/BXSzVfoQM5MnQOI=
github.com/dunglas/vulcain/caddy v1.0.5/go.mod h1:44+4e7q60jhdNqud8Ms4j+xb43pIU2jeTplKhMry9bo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
@@ -130,55 +161,52 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE=
github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/gammazero/deque v0.2.1 h1:qSdsbG6pgp6nL7A0+K/B7s12mcCY/5l5SIUpMOl+dC0=
github.com/gammazero/deque v0.2.1/go.mod h1:LFroj8x4cMYCukHJDbxFCkT+r9AndaJnFMuZDV34tuU=
github.com/getkin/kin-openapi v0.123.0 h1:zIik0mRwFNLyvtXK274Q6ut+dPh6nlxBp0x7mNrPhs8=
github.com/getkin/kin-openapi v0.123.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/getkin/kin-openapi v0.124.0 h1:VSFNMB9C9rTKBnQ/fpyDU8ytMTr4dWI9QovSKj9kz/M=
github.com/getkin/kin-openapi v0.124.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
github.com/go-kit/kit v0.4.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU=
github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -186,23 +214,22 @@ github.com/google/brotli/go/cbrotli v0.0.0-20240116120200-adbc354d23af h1:u7V797
github.com/google/brotli/go/cbrotli v0.0.0-20240116120200-adbc354d23af/go.mod h1:nOPhAkwVliJdNTkj3gXpljmWhjc4wCaVqbMJcPKWP4s=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.15.1 h1:iTgVZor2x9okXtmTrqO8cg4uvqIeaBcWhXtruaWFMYQ=
github.com/google/cel-go v0.15.1/go.mod h1:YzWEoI07MC/a/wj9in8GeVatqfypkldgBlwXh9bCwqY=
github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI=
github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc=
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
github.com/google/certificate-transparency-go v1.1.7 h1:IASD+NtgSTJLPdzkthwvAG1ZVbF2WtFg4IvoA68XGSw=
github.com/google/certificate-transparency-go v1.1.7/go.mod h1:FSSBo8fyMVgqptbfF6j5p/XNdgQftAhSmXcIxV9iphE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/certificate-transparency-go v1.1.8-0.20240110162603-74a5dd331745 h1:heyoXNxkRT155x4jTAiSv5BVSVkueifPUm+Q8LUXMRo=
github.com/google/certificate-transparency-go v1.1.8-0.20240110162603-74a5dd331745/go.mod h1:zN0wUQgV9LjwLZeFHnrAbQi8hzMVvEWePyk+MhPOk7k=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk=
github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU=
github.com/google/go-tpm-tools v0.4.1 h1:gYU6iwRo0tY3V6NDnS6m+XYog+b3g6YFhHQl3sYaUL4=
github.com/google/go-tpm-tools v0.4.1/go.mod h1:w03m0jynhTo7puXTYoyfpNOMqyQ9SB7sixnKWsS/1L0=
github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98=
github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY=
github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus=
github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 h1:y3N7Bm7Y9/CtpiVkw/ZWj6lSlDF3F74SfKwfTCer72Q=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -210,15 +237,12 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s=
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
github.com/gorilla/mux v1.4.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/groob/finalizer v0.0.0-20170707115354-4c2ed49aabda/go.mod h1:MyndkAZd5rUMdNogn35MWXBX1UiBigrU8eTj8DoAC2c=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
@@ -229,97 +253,46 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.14.2 h1:QBdZQTKpPdBlw2AdKwHEyqUcm/lrl2cwWAHjCMyln/o=
github.com/jackc/pgtype v1.14.2/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA=
github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kevburnsjr/skipfilter v0.0.1 h1:EWl1lWUJfIehrKYIEkps0Cl67lCfS2pUM9iZFNajp7g=
github.com/kevburnsjr/skipfilter v0.0.1/go.mod h1:jfaRyFOYVUtIa6IIC+0mB1qiZqhHw+DKvFowCBuijSk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
@@ -327,28 +300,19 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
github.com/mastercactapus/proxyprotocol v0.0.4 h1:qSY75IZF30ZqIU9iW1ip3I7gTnm8wRAnGWqPxCBVgq0=
github.com/mastercactapus/proxyprotocol v0.0.4/go.mod h1:X8FRVEDZz9FkrIoL4QYTBF4Ka4ELwTv0sah0/5NxCPw=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/maypok86/otter v1.2.0 h1:djwBBNpp9+dyzBTY0zscIG+pyAQVXRRRMbzztf8iJ4U=
github.com/maypok86/otter v1.2.0/go.mod h1:mKLfoI7v1HOmQMwFgX4QkRk23mX6ge3RDvjdHOWG4R4=
github.com/maypok86/otter v1.2.2 h1:jJi0y8ruR/ZcKmJ4FbQj3QQTqKwV+LNrSOo2S1zbF5M=
github.com/maypok86/otter v1.2.2/go.mod h1:mKLfoI7v1HOmQMwFgX4QkRk23mX6ge3RDvjdHOWG4R4=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
github.com/micromdm/scep/v2 v2.1.0 h1:2fS9Rla7qRR266hvUoEauBJ7J6FhgssEiq2OkSKXmaU=
github.com/micromdm/scep/v2 v2.1.0/go.mod h1:BkF7TkPPhmgJAMtHfP+sFTKXmgzNJgLQlvvGoOExBcc=
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
github.com/mholt/acmez/v2 v2.0.2 h1:OmK6xckte2JfKGPz4OAA8aNHTiLvGp8tLzmrd/wfSyw=
github.com/mholt/acmez/v2 v2.0.2/go.mod h1:fX4c9r5jYwMyMsC+7tkYRxHibkOTgta5DIFGoe67e1U=
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
@@ -365,18 +329,21 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo=
github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/peterbourgon/diskv/v3 v3.0.1 h1:x06SQA46+PKIUftmEujdwSEpIx8kR+M9eLYsUxeYveU=
github.com/peterbourgon/diskv/v3 v3.0.1/go.mod h1:kJ5Ny7vLdARGU3WUuy6uzO6T0nb/2gWcT1JiBvRmb5o=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -385,57 +352,54 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
github.com/prometheus/common v0.50.0 h1:YSZE6aa9+luNa2da6/Tik0q0A5AbR+U003TItK57CPQ=
github.com/prometheus/common v0.50.0/go.mod h1:wHFBCEVWVmHMUpg7pYcOm2QUR/ocQdYSJVQJKnHc3xQ=
github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/quic-go v0.41.0 h1:aD8MmHfgqTURWNJy48IYFg2OnxwHT3JL7ahGs73lb4k=
github.com/quic-go/quic-go v0.41.0/go.mod h1:qCkNjqczPEvgsOnxZ0eCD14lv+B2LHlFAB++CNOh9hA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/quic-go/quic-go v0.46.0 h1:uuwLClEEyk1DNvchH8uCByQVjo3yKL9opKulExNDs7Y=
github.com/quic-go/quic-go v0.46.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/schollz/jsonstore v1.1.0 h1:WZBDjgezFS34CHI+myb4s8GGpir3UMpy7vWoCeO0n6E=
github.com/schollz/jsonstore v1.1.0/go.mod h1:15c6+9guw8vDRyozGjN3FoILt0wpruJk9Pi66vjaZfg=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/slackhq/nebula v1.8.2 h1:9lpJlivzjBPWxs9Y2tQqmJ1cP6hq+3kIodw021t3LrQ=
github.com/slackhq/nebula v1.8.2/go.mod h1:SVVwnlGdmLg387U0XQMOSHRrD3VlJeXqd2/x/w/vxPs=
github.com/slackhq/nebula v1.9.3 h1:WK5Oipy4NsVfNm41pywGmdy048F8RRkfSRG+lPHxcJQ=
github.com/slackhq/nebula v1.9.3/go.mod h1:PMJer5rZe0H/O+kUiKOL9AJ/pL9+ryzNXtSN7ABfjfM=
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY=
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc=
github.com/smallstep/certificates v0.25.0 h1:WWihtjQ7SprnRxDV44mBp8t5SMsNO5EWsQaEwy1rgFg=
github.com/smallstep/certificates v0.25.0/go.mod h1:thJmekMKUplKYip+la99Lk4IwQej/oVH/zS9PVMagEE=
github.com/smallstep/certificates v0.27.2 h1:MrSJvJviS9pCUtGYYguYyB1VQzZBmkL6ngLQZfVwRqU=
github.com/smallstep/certificates v0.27.2/go.mod h1:v+u39A+fMBM3cFELPfAweaNce4RPm9AHUx9iwE0ene8=
github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935 h1:kjYvkvS/Wdy0PVRDUAA0gGJIVSEZYhiAJtfwYgOYoGA=
github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935/go.mod h1:vNAduivU014fubg6ewygkAvQC0IQVXqdc8vaGl/0er4=
github.com/smallstep/nosql v0.6.0 h1:ur7ysI8s9st0cMXnTvB8tA3+x5Eifmkb6hl4uqNV5jc=
github.com/smallstep/nosql v0.6.0/go.mod h1:jOXwLtockXORUPPZ2MCUcIkGR6w0cN1QGZniY9DITQA=
github.com/smallstep/nosql v0.7.0 h1:YiWC9ZAHcrLCrayfaF+QJUv16I2bZ7KdLC3RpJcnAnE=
github.com/smallstep/nosql v0.7.0/go.mod h1:H5VnKMCbeq9QA6SRY5iqPylfxLfYcLwvUff3onQ8+HU=
github.com/smallstep/pkcs7 v0.0.0-20231024181729-3b98ecc1ca81/go.mod h1:SoUAr/4M46rZ3WaLstHxGhLEgoYIDRqxQEXLOmOEB0Y=
github.com/smallstep/pkcs7 v0.0.0-20240723090913-5e2c6a136dfa h1:FtxzVccOwaK+bK4bnWBPGua0FpCOhrVyeo6Fy9nxdlo=
github.com/smallstep/pkcs7 v0.0.0-20240723090913-5e2c6a136dfa/go.mod h1:SoUAr/4M46rZ3WaLstHxGhLEgoYIDRqxQEXLOmOEB0Y=
github.com/smallstep/scep v0.0.0-20240214080410-892e41795b99 h1:e85HuLX5/MW15yJ7yWb/PMNFW1Kx1N+DeQtpQnlMUbw=
github.com/smallstep/scep v0.0.0-20240214080410-892e41795b99/go.mod h1:4d0ub42ut1mMtvGyMensjuHYEUpRrASvkzLEJvoRQcU=
github.com/smallstep/truststore v0.13.0 h1:90if9htAOblavbMeWlqNLnO9bsjjgVv2hQeQJCi/py4=
github.com/smallstep/truststore v0.13.0/go.mod h1:3tmMp2aLKZ/OA/jnFUB0cYPcho402UG2knuJoPh4j7A=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
@@ -448,30 +412,28 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -481,8 +443,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tailscale/tscert v0.0.0-20230806124524-28a91b69a046 h1:8rUlviSVOEe7TMk7W0gIPrW8MqEzYfZHpsNWSf8s2vg=
github.com/tailscale/tscert v0.0.0-20230806124524-28a91b69a046/go.mod h1:kNGUQ3VESx3VZwRwA9MSCUegIl6+saPL8Noq82ozCaU=
github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53 h1:uxMgm0C+EjytfAqyfBG55ZONKQ7mvd7x4YYCWsf8QHQ=
github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53/go.mod h1:kNGUQ3VESx3VZwRwA9MSCUegIl6+saPL8Noq82ozCaU=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@@ -496,10 +458,10 @@ github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/unrolled/secure v1.14.0 h1:u9vJTU/pR4Bny0ntLUMxdfLtmIRGvQf2sEFuA0TG9AE=
github.com/unrolled/secure v1.14.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk=
github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA=
github.com/unrolled/secure v1.15.0 h1:q7x+pdp8jAHnbzxu6UheP8fRlG/rwYTb8TPuQ3rn9Og=
github.com/unrolled/secure v1.15.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
github.com/urfave/cli v1.22.15 h1:nuqt+pdC/KqswQKhETJjo7pvn/k4xMUxgW6liI7XpnM=
github.com/urfave/cli v1.22.15/go.mod h1:wSan1hmo5zeyLGBjRJbzRTNk8gwoYa2B9n4q9dmRIc0=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
@@ -507,26 +469,24 @@ github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zI
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA=
github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/blake3 v0.2.3 h1:TFoLXsjeXqRNFxSbk35Dk4YtszE/MQQGK10BH4ptoTg=
github.com/zeebo/blake3 v0.2.3/go.mod h1:mjJjZpnsyIVtVgTOSpJ9vmRE4wgDeyt2HU3qXvvKCaQ=
github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
go.mozilla.org/pkcs7 v0.0.0-20210730143726-725912489c62/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak=
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
go.opentelemetry.io/contrib/propagators/autoprop v0.45.0 h1:FT/JCFzjzXgyp/aXkQeywnI/Tl8ZtKhvusVtZOokmFM=
go.opentelemetry.io/contrib/propagators/autoprop v0.45.0/go.mod h1:L/2JIbqAmGzBvGJ3rXA+KXmWXUuUYUDZnhXeJttjJRg=
go.opentelemetry.io/contrib/propagators/aws v1.20.0 h1:PByDRx6xPygwFP+L3FTlOifJoCB10T2LdRBZcDYMTJw=
@@ -537,99 +497,73 @@ go.opentelemetry.io/contrib/propagators/jaeger v1.20.0 h1:iVhNKkMIpzyZqxk8jkDU2n
go.opentelemetry.io/contrib/propagators/jaeger v1.20.0/go.mod h1:cpSABr0cm/AH/HhbJjn+AudBVUMgZWdfN3Gb+ZqxSZc=
go.opentelemetry.io/contrib/propagators/ot v1.20.0 h1:duH7mgL6VGQH7e7QEAVOFkCQXWpCb4PjTtrhdrYrJRQ=
go.opentelemetry.io/contrib/propagators/ot v1.20.0/go.mod h1:gijQzxOq0JLj9lyZhTvqjDddGV/zaNagpPIn+2r8CEI=
go.opentelemetry.io/otel v1.23.0 h1:Df0pqjqExIywbMCMTxkAwzjLZtRf+bBKLbUcpxO2C9E=
go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0=
go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo=
go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI=
go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.step.sm/cli-utils v0.8.0 h1:b/Tc1/m3YuQq+u3ghTFP7Dz5zUekZj6GUmd5pCvkEXQ=
go.step.sm/cli-utils v0.8.0/go.mod h1:S77aISrC0pKuflqiDfxxJlUbiXcAanyJ4POOnzFSxD4=
go.step.sm/crypto v0.36.0 h1:njrVQqjWVyCzHxqQUDprR7HXypZX8IxtOqe4IIHSjgU=
go.step.sm/crypto v0.36.0/go.mod h1:XMRbgkhoigPLaPMjZeY1VFIYXVw03Wul0+5lENF6l7c=
go.step.sm/linkedca v0.20.1 h1:bHDn1+UG1NgRrERkWbbCiAIvv4lD5NOFaswPDTyO5vU=
go.step.sm/linkedca v0.20.1/go.mod h1:Vaq4+Umtjh7DLFI1KuIxeo598vfBzgSYZUjgVJ7Syxw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.step.sm/cli-utils v0.9.0 h1:55jYcsQbnArNqepZyAwcato6Zy2MoZDRkWW+jF+aPfQ=
go.step.sm/cli-utils v0.9.0/go.mod h1:Y/CRoWl1FVR9j+7PnAewufAwKmBOTzR6l9+7EYGAnp8=
go.step.sm/crypto v0.51.1 h1:ktUg/2hetEMiBAqgz502ktZDGoDoGrcHFg3XpkmkvvA=
go.step.sm/crypto v0.51.1/go.mod h1:PdrhttNU/tG9/YsVd4fdlysBN+UV503p0o2irFZQlAw=
go.step.sm/linkedca v0.22.1 h1:GvprpH9P4Sv9U+eZ3bxDgRSSpW14cFDYpe1kS6yWLkw=
go.step.sm/linkedca v0.22.1/go.mod h1:dOKdF4HSn73YUEkfS5/FECngZmBtj2Il5DTKWXY4S6Y=
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap/exp v0.2.0 h1:FtGenNNeCATRB3CmB/yEUnjEFeJWpB/pMcy7e2bKPYs=
go.uber.org/zap/exp v0.2.0/go.mod h1:t0gqAIdh1MfKv9EwN/dLwfZnJxe9ITAZN78HEWPFWDQ=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f h1:3CW0unweImhOzd5FmYuRsD4Y4oQFKZIjAnKbjV4WIrw=
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/crypto/x509roots/fallback v0.0.0-20240806160748-b2d3a6a4b4d3 h1:oWb21rU9Q9XrRwXLB7jHc1rbp6EiiimZZv5MLxpu4T0=
golang.org/x/crypto/x509roots/fallback v0.0.0-20240806160748-b2d3a6a4b4d3/go.mod h1:kNa9WdvYnzFwC79zRpLRMJbdEFlhyM5RPFBBZp/wWH8=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20170726083632-f5079bd7f6f7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20170728174421-0f826bdd13b5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -641,80 +575,62 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.153.0 h1:N1AwGhielyKFaUqH07/ZSIQR3uNPcV7NVw0vj+j4iR4=
google.golang.org/api v0.153.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
google.golang.org/genproto/googleapis/api v0.0.0-20240228224816-df926f6c8641 h1:SO1wX9btGFrwj9EzH3ocqfwiPVOxfv4ggAJajzlHA5s=
google.golang.org/genproto/googleapis/api v0.0.0-20240228224816-df926f6c8641/go.mod h1:wLupoVsUfYPgOMwjzhYFbaVklw/INms+dqTp0tc1fv8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 h1:DKU1r6Tj5s1vlU/moGhuGz7E3xRfwjdAfDzbsaQJtEY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs=
google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk=
google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/api v0.189.0 h1:equMo30LypAkdkLMBqfeIqtyAnlyig1JSZArl4XPwdI=
google.golang.org/api v0.189.0/go.mod h1:FLWGJKb0hb+pU2j+rJqwbnsF+ym+fQs73rbJ+KAUgy8=
google.golang.org/genproto v0.0.0-20240722135656-d784300faade h1:lKFsS7wpngDgSCeFn7MoLy+wBDQZ1UQIJD4UNM1Qvkg=
google.golang.org/genproto v0.0.0-20240722135656-d784300faade/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY=
google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw=
google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=

View File

@@ -11,6 +11,7 @@ import (
"time"
mercureModule "github.com/dunglas/mercure/caddy"
"go.uber.org/zap/zapcore"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig"
@@ -21,7 +22,6 @@ import (
"github.com/caddyserver/caddy/v2/modules/caddyhttp/rewrite"
"github.com/caddyserver/certmagic"
"github.com/dunglas/frankenphp"
"go.uber.org/zap"
"github.com/spf13/cobra"
)
@@ -313,7 +313,7 @@ func cmdPHPServer(fs caddycmd.Flags) (int, error) {
cfg.Logging = &caddy.Logging{
Logs: map[string]*caddy.CustomLog{
"default": {
BaseLog: caddy.BaseLog{Level: zap.DebugLevel.CapitalString()},
BaseLog: caddy.BaseLog{Level: zapcore.DebugLevel.CapitalString()},
},
},
}

View File

@@ -1,8 +1,10 @@
# syntax=docker/dockerfile:1
#checkov:skip=CKV_DOCKER_2
#checkov:skip=CKV_DOCKER_3
FROM golang:1.22-alpine
ENV CFLAGS="-ggdb3"
ENV PHPIZE_DEPS \
ENV PHPIZE_DEPS="\
autoconf \
dpkg-dev \
file \
@@ -11,7 +13,7 @@ ENV PHPIZE_DEPS \
libc-dev \
make \
pkgconfig \
re2c
re2c"
RUN apk add --no-cache \
$PHPIZE_DEPS \

View File

@@ -1,8 +1,10 @@
# syntax=docker/dockerfile:1
#checkov:skip=CKV_DOCKER_2
#checkov:skip=CKV_DOCKER_3
FROM golang:1.22
ENV CFLAGS="-ggdb3"
ENV PHPIZE_DEPS \
ENV PHPIZE_DEPS="\
autoconf \
dpkg-dev \
file \
@@ -11,7 +13,7 @@ ENV PHPIZE_DEPS \
libc-dev \
make \
pkg-config \
re2c
re2c"
# hadolint ignore=DL3009
RUN apt-get update && \
@@ -65,7 +67,7 @@ WORKDIR /go/src/app
COPY . .
WORKDIR /go/src/app/caddy/frankenphp
RUN go build
RUN go build -buildvcs=false
WORKDIR /go/src/app
CMD [ "zsh" ]

View File

@@ -17,7 +17,7 @@ variable "GO_VERSION" {
variable "SHA" {}
variable "LATEST" {
default = false
default = true
}
variable "CACHE" {
@@ -31,14 +31,14 @@ variable DEFAULT_PHP_VERSION {
function "tag" {
params = [version, os, php-version, tgt]
result = [
version != "" ? format("%s:%s%s-php%s-%s", IMAGE_NAME, version, tgt == "builder" ? "-builder" : "", php-version, os) : "",
php-version == DEFAULT_PHP_VERSION && os == "bookworm" && version != "" ? format("%s:%s%s", IMAGE_NAME, version, tgt == "builder" ? "-builder" : "") : "",
php-version == DEFAULT_PHP_VERSION && version != "" ? format("%s:%s%s-%s", IMAGE_NAME, version, tgt == "builder" ? "-builder" : "", os) : "",
php-version == DEFAULT_PHP_VERSION && version == "latest" ? format("%s:%s%s", IMAGE_NAME, os, tgt == "builder" ? "-builder" : "") : "",
os == "bookworm" && version != "" ? format("%s:%s%s-php%s", IMAGE_NAME, version, tgt == "builder" ? "-builder" : "", php-version) : "",
version == "" ? "" : "${IMAGE_NAME}:${trimprefix("${version}${tgt == "builder" ? "-builder" : ""}-php${php-version}-${os}", "latest-")}",
php-version == DEFAULT_PHP_VERSION && os == "bookworm" && version != "" ? "${IMAGE_NAME}:${trimprefix("${version}${tgt == "builder" ? "-builder" : ""}", "latest-")}" : "",
php-version == DEFAULT_PHP_VERSION && version != "" ? "${IMAGE_NAME}:${trimprefix("${version}${tgt == "builder" ? "-builder" : ""}-${os}", "latest-")}" : "",
os == "bookworm" && version != "" ? "${IMAGE_NAME}:${trimprefix("${version}${tgt == "builder" ? "-builder" : ""}-php${php-version}", "latest-")}" : "",
]
}
# cleanTag ensures that the tag is a valid Docker tag
# cleanTag ensures that the tag is a valid Docker tag
# see https://github.com/distribution/distribution/blob/v2.8.2/reference/regexp.go#L37
function "clean_tag" {
@@ -60,7 +60,7 @@ function "_semver" {
function "__semver" {
params = [v]
result = v == {} ? [clean_tag(VERSION)] : v.prerelease == null ? ["latest", v.major, "${v.major}.${v.minor}", "${v.major}.${v.minor}.${v.patch}"] : ["${v.major}.${v.minor}.${v.patch}-${v.prerelease}"]
result = v == {} ? [clean_tag(VERSION)] : v.prerelease == null ? [v.major, "${v.major}.${v.minor}", "${v.major}.${v.minor}.${v.patch}"] : ["${v.major}.${v.minor}.${v.patch}-${v.prerelease}"]
}
function "php_version" {
@@ -91,7 +91,8 @@ target "default" {
platforms = os == "alpine" ? [
"linux/amd64",
"linux/386",
"linux/arm/v6",
# FIXME: armv6 doesn't build in GitHub actions because we use a custom Go build
#"linux/arm/v6",
"linux/arm/v7",
"linux/arm64",
] : [
@@ -103,8 +104,8 @@ target "default" {
tags = distinct(flatten(
[for pv in php_version(php-version) : flatten([
LATEST ? tag("latest", os, pv, tgt) : [],
tag(SHA == "" ? "" : "sha-${substr(SHA, 0, 7)}", os, pv, tgt),
[for v in semver(VERSION) : tag(v, os, pv, tgt)]
tag(SHA == "" || VERSION != "dev" ? "" : "sha-${substr(SHA, 0, 7)}", os, pv, tgt),
VERSION == "dev" ? [] : [for v in semver(VERSION) : tag(v, os, pv, tgt)]
])
]))
labels = {
@@ -129,8 +130,8 @@ target "static-builder" {
]
tags = distinct(flatten([
LATEST ? "${IMAGE_NAME}:static-builder" : "",
SHA == "" ? "" : "${IMAGE_NAME}:static-builder-sha-${substr(SHA, 0, 7)}",
[for v in semver(VERSION) : v == "latest" ? "${IMAGE_NAME}:static-builder": "${IMAGE_NAME}:static-builder-${v}"]
SHA == "" || VERSION != "dev" ? "" : "${IMAGE_NAME}:static-builder-sha-${substr(SHA, 0, 7)}",
VERSION == "dev" ? [] : [for v in semver(VERSION) : "${IMAGE_NAME}:static-builder-${v}"]
]))
labels = {
"org.opencontainers.image.created" = "${timestamp()}"

215
docs/cn/CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,215 @@
# 贡献
## 编译 PHP
### 使用 Docker (Linux)
构建开发环境 Docker 镜像:
```console
docker build -t frankenphp-dev -f dev.Dockerfile .
docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 8080:8080 -p 443:443 -p 443:443/udp -v $PWD:/go/src/app -it frankenphp-dev
```
该镜像包含常用的开发工具Go、GDB、Valgrind、Neovim等
如果 docker 版本低于 23.0,则会因为 dockerignore [pattern issue](https://github.com/moby/moby/pull/42676) 而导致构建失败。将目录添加到 `.dockerignore`
```patch
!testdata/*.php
!testdata/*.txt
+!caddy
+!internal
```
### 不使用 Docker (Linux 和 macOS)
[按照说明从源代码编译](https://frankenphp.dev/docs/compile/) 并传递 `--debug` 配置标志。
## 运行测试套件
```console
go test -race -v ./...
```
## Caddy 模块
使用 FrankenPHP Caddy 模块构建 Caddy
```console
cd caddy/frankenphp/
go build
cd ../../
```
使用 FrankenPHP Caddy 模块运行 Caddy
```console
cd testdata/
../caddy/frankenphp/frankenphp run
```
服务器正在监听 `127.0.0.1:8080`
```console
curl -vk https://localhost/phpinfo.php
```
## 最小测试服务器
构建最小测试服务器:
```console
cd internal/testserver/
go build
cd ../../
```
运行测试服务器:
```console
cd testdata/
../internal/testserver/testserver
```
服务器正在监听 `127.0.0.1:8080`
```console
curl -v http://127.0.0.1:8080/phpinfo.php
```
## 本地构建 Docker 镜像
打印 bake 计划:
```console
docker buildx bake -f docker-bake.hcl --print
```
本地构建 amd64 的 FrankenPHP 镜像:
```console
docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/amd64"
```
本地构建 arm64 的 FrankenPHP 镜像:
```console
docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/arm64"
```
从头开始为 arm64 和 amd64 构建 FrankenPHP 镜像并推送到 Docker Hub
```console
docker buildx bake -f docker-bake.hcl --pull --no-cache --push
```
## 使用静态构建调试分段错误
1. 从 GitHub 下载 FrankenPHP 二进制文件的调试版本或创建包含调试符号的自定义静态构建:
```console
docker buildx bake \
--load \
--set static-builder.args.DEBUG_SYMBOLS=1 \
--set "static-builder.platform=linux/amd64" \
static-builder
docker cp $(docker create --name static-builder dunglas/frankenphp:static-builder):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp
```
2. 将当前版本的 `frankenphp` 替换为 debug FrankenPHP 可执行文件
3. 照常启动 FrankenPHP或者你可以直接使用 GDB 启动 FrankenPHP `gdb --args ./frankenphp run`
4. 使用 GDB 附加到进程:
```console
gdb -p `pidof frankenphp`
```
5. 如有必要,请在 GDB shell 中输入 `continue`
6. 使 FrankenPHP 崩溃
7. 在 GDB shell 中输入 `bt`
8. 复制输出
## 在 GitHub Actions 中调试分段错误
1. 打开 `.github/workflows/tests.yml`
2. 启用 PHP 调试符号
```patch
- uses: shivammathur/setup-php@v2
# ...
env:
phpts: ts
+ debug: true
```
3. 启用 `tmate` 以连接到容器
```patch
-
name: Set CGO flags
run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV"
+ -
+ run: |
+ sudo apt install gdb
+ mkdir -p /home/runner/.config/gdb/
+ printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit
+ -
+ uses: mxschmitt/action-tmate@v3
```
4. 连接到容器
5. 打开 `frankenphp.go`
6. 启用 `cgosymbolizer`
```patch
- //_ "github.com/ianlancetaylor/cgosymbolizer"
+ _ "github.com/ianlancetaylor/cgosymbolizer"
```
7. 下载模块: `go get`
8. 在容器中,可以使用 GDB 和以下:
```console
go test -c -ldflags=-w
gdb --args ./frankenphp.test -test.run ^MyTest$
```
9. 当错误修复后,恢复所有这些更改
## 其他开发资源
* [PHP 嵌入 uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c)
* [PHP 嵌入 NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c)
* [PHP 嵌入 Go (go-php)](https://github.com/deuill/go-php)
* [PHP 嵌入 Go (GoEmPHP)](https://github.com/mikespook/goemphp)
* [PHP 嵌入 C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7)
* [扩展和嵌入 PHP 作者Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false)
* [TSRMLS_CC到底是什么](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html)
* [Mac 上的 PHP 嵌入](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4)
* [SDL 绑定](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main)
## Docker 相关资源
* [Bake 文件定义](https://docs.docker.com/build/customize/bake/file-definition/)
* [docker buildx 构建](https://docs.docker.com/engine/reference/commandline/buildx_build/)
## 有用的命令
```console
apk add strace util-linux gdb
strace -e 'trace=!futex,epoll_ctl,epoll_pwait,tgkill,rt_sigreturn' -p 1
```
## 翻译文档
要将文档和网站翻译成新语言,请按照下列步骤操作:
1. 在此存储库的 `docs/` 目录中创建一个以语言的 2 个字符的 ISO 代码命名的新目录
2. 将 `docs/` 目录根目录中的所有 `.md` 文件复制到新目录中(始终使用英文版本作为翻译源,因为它始终是最新的)
3. 将 `README.md` 和 `CONTRIBUTING.md` 文件从根目录复制到新目录
4. 翻译文件的内容,但不要更改文件名,也不要翻译以 `> [!` 开头的字符串(这是 GitHub 的特殊标记)
5. 创建翻译的拉取请求
6. 在 [站点存储库](https://github.com/dunglas/frankenphp-website/tree/main) 中,复制并翻译 `content/``data/``i18n/` 目录中的翻译文件
7. 转换创建的 YAML 文件中的值
8. 在站点存储库上打开拉取请求

View File

@@ -71,7 +71,7 @@ docker run -v $PWD:/app/public \
* [API Platform](https://api-platform.com/docs/distribution/)
* [Laravel](laravel.md)
* [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp)
* [WordPress](https://github.com/dunglas/frankenphp-wordpress)
* [WordPress](https://github.com/StephenMiracle/frankenwp)
* [Drupal](https://github.com/dunglas/frankenphp-drupal)
* [Joomla](https://github.com/alexandreelise/frankenphp-joomla)
* [TYPO3](https://github.com/ochorocho/franken-typo3)

View File

@@ -16,7 +16,9 @@ tar xf php-*
cd php-*/
```
然后,为您的平台配置 PHP
然后,为您的平台配置 PHP.
这些参数是必需的,但你也可以添加其他编译参数(例如额外的扩展)。
### Linux
@@ -28,13 +30,6 @@ cd php-*/
--enable-zend-max-execution-timers
```
最后,编译并安装 PHP
```console
make -j$(nproc)
sudo make install
```
### Mac
使用 [Homebrew](https://brew.sh/) 包管理器安装 `libiconv``bison``re2c``pkg-config`
@@ -57,12 +52,12 @@ echo 'export PATH="/opt/homebrew/opt/bison/bin:$PATH"' >> ~/.zshrc
--with-iconv=/opt/homebrew/opt/libiconv/
```
这些参数是必需的,但你也可以添加其他编译参数(例如额外的扩展)。
## 编译并安装 PHP
最后,编译并安装 PHP
```console
make -j$(sysctl -n hw.logicalcpu)
make -j"$(getconf _NPROCESSORS_ONLN)"
sudo make install
```
@@ -71,7 +66,7 @@ sudo make install
您现在可以使用 Go 库并编译我们的 Caddy 构建:
```console
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar x
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz
cd frankenphp-main/caddy/frankenphp
CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build
```
@@ -86,6 +81,7 @@ XCADDY_GO_BUILD_FLAGS="-ldflags '-w -s'" \
xcaddy build \
--output frankenphp \
--with github.com/dunglas/frankenphp/caddy \
--with github.com/dunglas/caddy-cbrotli \
--with github.com/dunglas/mercure/caddy \
--with github.com/dunglas/vulcain/caddy
# Add extra Caddy modules here

View File

@@ -28,8 +28,6 @@ RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
{
# 启用 FrankenPHP
frankenphp
# 配置何时必须执行指令
order php_server before file_server
}
localhost {

View File

@@ -55,6 +55,7 @@ RUN xcaddy build \
--output /usr/local/bin/frankenphp \
--with github.com/dunglas/frankenphp=./ \
--with github.com/dunglas/frankenphp/caddy=./caddy/ \
--with github.com/dunglas/caddy-cbrotli \
# Mercure 和 Vulcain 包含在官方版本中,如果不需要你可以删除它们
--with github.com/dunglas/mercure/caddy \
--with github.com/dunglas/vulcain/caddy

View File

@@ -22,7 +22,6 @@ docker run -p 80:80 -p 443:443 -p 443:443/udp -v $PWD:/app dunglas/frankenphp
```caddyfile
{
frankenphp
order php_server before file_server
}
# 服务器的域名
@@ -52,13 +51,13 @@ composer require laravel/octane
php artisan octane:install --server=frankenphp
```
Octane 服务可以通过 `octane:start` Artisan 命令启动。
Octane 服务可以通过 `octane:frankenphp` Artisan 命令启动。
```console
php artisan octane:start
php artisan octane:frankenphp
```
`octane:start` 命令可以采用以下选项:
`octane:frankenphp` 命令可以采用以下选项:
* `--host`: 服务器应绑定到的 IP 地址(默认值: `127.0.0.1`
* `--port`: 服务器应可用的端口(默认值: `8000`

View File

@@ -5,7 +5,7 @@ Mercure 允许将事件实时推送到所有连接的设备:它们将立即收
无需 JS 库或 SDK
![Mercure](https://mercure.rocks/static/main.png)
![Mercure](../mercure-hub.png)
要启用 Mercure Hub请按照 [Mercure 网站](https://mercure.rocks/docs/hub/config) 中的说明更新 `Caddyfile`

View File

@@ -68,11 +68,11 @@ $myApp->boot();
// 循环外的处理程序以获得更好的性能(减少工作量)
$handler = static function () use ($myApp) {
// 收到请求时调用
// 超全局变量 php://input
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
// 收到请求时调用
// 超全局变量 php://input
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
};
for($nbRequests = 0, $running = true; isset($_SERVER['MAX_REQUESTS']) && ($nbRequests < ((int)$_SERVER['MAX_REQUESTS'])) && $running; ++$nbRequests) {
for ($nbRequests = 0, $running = true; isset($_SERVER['MAX_REQUESTS']) && ($nbRequests < ((int)$_SERVER['MAX_REQUESTS'])) && $running; ++$nbRequests) {
$running = \frankenphp_handle_request($handler);
// 发送 HTTP 响应后执行某些操作

View File

@@ -1,22 +1,23 @@
# Compile From Sources
This document explain how to create a FrankenPHP build that will load PHP as a dynamic library.
This document explains how to create a FrankenPHP binary that will load PHP as a dynamic library.
This is the recommended method.
Alternatively, [creating static builds](static.md) is also possible.
Alternatively, [static builds](static.md) can also be created.
## Install PHP
FrankenPHP is compatible with the PHP 8.2 and superior.
FrankenPHP is compatible with PHP 8.2 and superior.
First, [get the sources of PHP](https://www.php.net/downloads.php) and extract them:
First, [get the PHP sources](https://www.php.net/downloads.php) and extract them:
```console
tar xf php-*
cd php-*/
```
Then, configure PHP for your platform:
Then, run the `configure` script with the options needed for your platform.
Th following `./configure` flags are mandatory, but you can add others, for example to compile extensions or additional features.
### Linux
@@ -28,13 +29,6 @@ Then, configure PHP for your platform:
--enable-zend-max-execution-timers
```
Finally, compile and install PHP:
```console
make -j$(nproc)
sudo make install
```
### Mac
Use the [Homebrew](https://brew.sh/) package manager to install
@@ -58,22 +52,21 @@ Then run the configure script:
--with-iconv=/opt/homebrew/opt/libiconv/
```
These flags are required, but you can add other flags (e.g. extra extensions)
if needed.
## Compile PHP
Finally, compile and install PHP:
```console
make -j$(sysctl -n hw.logicalcpu)
make -j"$(getconf _NPROCESSORS_ONLN)"
sudo make install
```
## Compile the Go App
You can now use the Go library and compile our Caddy build:
You can now build the final binary:
```console
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar x
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz
cd frankenphp-main/caddy/frankenphp
CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build
```
@@ -88,6 +81,7 @@ XCADDY_GO_BUILD_FLAGS="-ldflags '-w -s'" \
xcaddy build \
--output frankenphp \
--with github.com/dunglas/frankenphp/caddy \
--with github.com/dunglas/caddy-cbrotli \
--with github.com/dunglas/mercure/caddy \
--with github.com/dunglas/vulcain/caddy
# Add extra Caddy modules here

View File

@@ -2,11 +2,11 @@
FrankenPHP, Caddy as well as the Mercure and Vulcain modules can be configured using [the formats supported by Caddy](https://caddyserver.com/docs/getting-started#your-first-config).
In the Docker image, the `Caddyfile` is located at `/etc/caddy/Caddyfile`.
In [the Docker images](docker.md), the `Caddyfile` is located at `/etc/caddy/Caddyfile`.
You can also configure PHP using `php.ini` as usual.
In the Docker image, the `php.ini` file is not present, you can create it manually or copy an official template:
In the Docker images, the `php.ini` file is not present, you can create it manually or copy an official template:
```dockerfile
FROM dunglas/frankenphp
@@ -18,6 +18,9 @@ RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
```
The static binary will look for a `php.ini` file in the current working directory,
in `/lib/` as well as [the other standard locations](https://www.php.net/manual/en/configuration.file.php).
## Caddyfile Config
To register the FrankenPHP executor, the `frankenphp` [global option](https://caddyserver.com/docs/caddyfile/concepts#global-options) must be set, then the `php_server` or the `php` [HTTP directives](https://caddyserver.com/docs/caddyfile/concepts#directives) may be used within the site blocks to serve your PHP app.
@@ -28,8 +31,6 @@ Minimal example:
{
# Enable FrankenPHP
frankenphp
# Configure when the directive must be executed
order php_server before file_server
}
localhost {
@@ -126,9 +127,36 @@ php_server [<matcher>] {
split_path <delim...> # Sets the substrings for splitting the URI into two parts. The first matching substring will be used to split the "path info" from the path. The first piece is suffixed with the matching substring and will be assumed as the actual resource (CGI script) name. The second piece will be set to PATH_INFO for the script to use. Default: `.php`
resolve_root_symlink false # Disables resolving the `root` directory to its actual value by evaluating a symbolic link, if one exists (enabled by default).
env <key> <value> # Sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables.
file_server off # Disables the built-in file_server directive.
}
```
### Full Duplex (HTTP/1)
When using HTTP/1.x, it may be desirable to enable full-duplex mode to allow writing a response before the entire body
has been read. (for example: WebSocket, Server-Sent Events, etc.)
This is an opt-in configuration that needs to be added to the global options in the `Caddyfile`:
```caddyfile
{
servers {
enable_full_duplex
}
}
```
> ![CAUTION]
>
> Enabling this option may cause old HTTP/1.x clients that don't support full-duplex to deadlock.
This can also be configured using the `CADDY_GLOBAL_OPTIONS` environment config:
```sh
CADDY_GLOBAL_OPTIONS="servers { enable_full_duplex }"
```
You can find more information about this setting in the [Caddy documentation](https://caddyserver.com/docs/caddyfile/options#enable-full-duplex).
## Environment Variables
The following environment variables can be used to inject Caddy directives in the `Caddyfile` without modifying it:

View File

@@ -2,7 +2,14 @@
[FrankenPHP Docker images](https://hub.docker.com/r/dunglas/frankenphp) are based on [official PHP images](https://hub.docker.com/_/php/). Debian and Alpine Linux variants are provided for popular architectures. Debian variants are recommended.
Variants for PHP 8.2 and PHP 8.3 are provided. [Browse tags](https://hub.docker.com/r/dunglas/frankenphp/tags).
Variants for PHP 8.2 and PHP 8.3 are provided.
The tags follow this pattern: `dunglas/frankenphp:<frankenphp-version>-php<php-version>-<os>`
* `<frankenphp-version>` and `<php-version>` are version numbers of FrankenPHP and PHP respectively, with specifities ranging from major (e.g. `1`), minor (e.g. `1.2`) to patch versions (e.g. `1.2.3`).
* `<os>` is either `bookworm` (for Debian Bookworm) or `alpine` (for the latest stable version of Alpine).
[Browse tags](https://hub.docker.com/r/dunglas/frankenphp/tags).
## How to Use The Images
@@ -56,8 +63,8 @@ RUN xcaddy build \
--output /usr/local/bin/frankenphp \
--with github.com/dunglas/frankenphp=./ \
--with github.com/dunglas/frankenphp/caddy=./caddy/ \
# Mercure and Vulcain are included in the official build, but feel free to remove them
--with github.com/dunglas/caddy-cbrotli \
# Mercure and Vulcain are included in the official build, but feel free to remove them
--with github.com/dunglas/mercure/caddy \
--with github.com/dunglas/vulcain/caddy
# Add extra Caddy modules here
@@ -146,11 +153,38 @@ RUN \
# Add additional capability to bind to port 80 and 443
setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \
# Give write access to /data/caddy and /config/caddy
chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy;
chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy
USER ${USER}
```
### Running With No Capabilities
Even when running rootless, FrankenPHP needs the `CAP_NET_BIND_SERVICE` capability to bind the
web server on privileged ports (80 and 443).
If you expose FrankenPHP on a non-privileged port (1024 and above), it's possible to run
the webserver as a non-root user, and without the need for any capability:
```dockerfile
FROM dunglas/frankenphp
ARG USER=www-data
RUN \
# Use "adduser -D ${USER}" for alpine based distros
useradd -D ${USER}; \
# Remove default capability
setcap -r /usr/local/bin/frankenphp; \
# Give write access to /data/caddy and /config/caddy
chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy
USER ${USER}
```
Next, set the `SERVER_NAME` environment variable to use an unprivileged port.
Example: `:8000`
## Updates
The Docker images are built:

View File

@@ -2,20 +2,22 @@
FrankenPHP has the ability to embed the source code and assets of PHP applications in a static, self-contained binary.
Thanks to this feature, PHP applications can be distributed as standalone binaries that include the application itself, the PHP interpreter and Caddy, a production-level web server.
Thanks to this feature, PHP applications can be distributed as standalone binaries that include the application itself, the PHP interpreter, and Caddy, a production-level web server.
Learn more about this feature [in the presentation made by Kévin at SymfonyCon 2023](https://dunglas.dev/2023/12/php-and-symfony-apps-as-standalone-binaries/).
For embedding Laravel applications, [read this specific documentation entry](laravel.md#laravel-apps-as-standalone-binaries).
## Preparing Your App
Before creating the self-contained binary be sure that your app is ready for embedding.
For instance you likely want to:
For instance, you likely want to:
* Install the production dependencies of the app
* Dump the autoloader
* Enable the production mode of your application (if any)
* Strip uneeded files such as `.git` or tests to reduce the size of your final binary
* Strip unneeded files such as `.git` or tests to reduce the size of your final binary
For instance, for a Symfony app, you can use the following commands:
@@ -29,7 +31,8 @@ cd $TMPDIR/my-prepared-app
echo APP_ENV=prod > .env.local
echo APP_DEBUG=0 >> .env.local
# Remove the tests
# Remove the tests and other unneeded files to save space
# Alternatively, add these files with the export-ignore attribute in your .gitattributes file
rm -Rf tests/
# Install the dependencies
@@ -39,11 +42,16 @@ composer install --ignore-platform-reqs --no-dev -a
composer dump-env prod
```
### Customizing the Configuration
To customize [the configuration](config.md), you can put a `Caddyfile` as well as a `php.ini` file
in the main directory of the app to be embedded (`$TMPDIR/my-prepared-app` in the previous example).
## Creating a Linux Binary
The easiest way to create a Linux binary is to use the Docker-based builder we provide.
1. Create a file named `static-build.Dockerfile` in the repository of your prepared app:
1. Create a file named `static-build.Dockerfile` in the repository of your app:
```dockerfile
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
@@ -52,11 +60,9 @@ The easiest way to create a Linux binary is to use the Docker-based builder we p
WORKDIR /go/src/app/dist/app
COPY . .
# Build the static binary, be sure to select only the PHP extensions you want
# Build the static binary
WORKDIR /go/src/app/
RUN EMBED=dist/app/ \
PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \
./build-static.sh
RUN EMBED=dist/app/ ./build-static.sh
```
> [!CAUTION]
@@ -85,9 +91,7 @@ If you don't want to use Docker, or want to build a macOS binary, use the shell
```console
git clone https://github.com/dunglas/frankenphp
cd frankenphp
EMBED=/path/to/your/app \
PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \
./build-static.sh
EMBED=/path/to/your/app ./build-static.sh
```
The resulting binary is the file named `frankenphp-<os>-<arch>` in the `dist/` directory.
@@ -108,7 +112,7 @@ If your app contains a [worker script](worker.md), start the worker with somethi
./my-app php-server --worker public/index.php
```
To enable HTTPS (a Let's Encrypt certificate is automatically created), HTTP/2 and HTTP/3, specify the domain name to use:
To enable HTTPS (a Let's Encrypt certificate is automatically created), HTTP/2, and HTTP/3, specify the domain name to use:
```console
./my-app php-server --domain localhost
@@ -120,6 +124,13 @@ You can also run the PHP CLI scripts embedded in your binary:
./my-app php-cli bin/console
```
## PHP Extensions
By default, the script will build extensions required by the `composer.json` file of your project, if any.
If the `composer.json` file doesn't exist, the default extensions are built, as documented in [the static builds entry](static.md).
To customize the extensions, use the `PHP_EXTENSIONS` environment variable.
## Customizing The Build
[Read the static build documentation](static.md) to see how to customize the binary (extensions, PHP version...).

View File

@@ -19,7 +19,6 @@ Si la version de Docker est inférieure à 23.0, la construction échoue à caus
!testdata/*.php
!testdata/*.txt
+!caddy
+!C-Thread-Pool
+!internal
```

View File

@@ -56,6 +56,7 @@ Vous pouvez également exécuter des scripts en ligne de commande avec :
* [Configuration](config.md)
* [Images Docker](docker.md)
* [Déploiement en production](production.md)
* [Optimisation des performances](performance.md)
* [Créer des applications PHP **standalone**, auto-exécutables](embed.md)
* [Créer un build statique](static.md)
* [Compiler depuis les sources](compile.md)
@@ -71,7 +72,7 @@ Vous pouvez également exécuter des scripts en ligne de commande avec :
* [API Platform](https://api-platform.com/docs/distribution/)
* [Laravel](laravel.md)
* [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp)
* [WordPress](https://github.com/dunglas/frankenphp-wordpress)
* [WordPress](https://github.com/StephenMiracle/frankenwp)
* [Drupal](https://github.com/dunglas/frankenphp-drupal)
* [Joomla](https://github.com/alexandreelise/frankenphp-joomla)
* [TYPO3](https://github.com/ochorocho/franken-typo3)

View File

@@ -1,8 +1,9 @@
# Compiler depuis les sources
Ce document explique comment créer un build FrankenPHP qui chargera PHP comme une bibliothèque dynamique. C'est la méthode recommandée.
Ce document explique comment créer un build FrankenPHP qui chargera PHP en tant que bibliothèque dynamique.
C'est la méthode recommandée.
En alternative, il est aussi possible de [créer des builds statiques](static.md).
Alternativement, il est aussi possible de [créer des builds statiques](static.md).
## Installer PHP
@@ -15,7 +16,9 @@ tar xf php-*
cd php-*/
```
Ensuite, configurez PHP pour votre système d'exploitation :
Ensuite, configurez PHP pour votre système d'exploitation.
Les options de configuration suivantes sont nécessaires pour la compilation, mais vous pouvez également inclure d'autres options selon vos besoins, par exemple pour ajouter des extensions et fonctionnalités supplémentaires.
### Linux
@@ -27,13 +30,6 @@ Ensuite, configurez PHP pour votre système d'exploitation :
--enable-zend-max-execution-timers
```
Finalement, compilez et installez PHP :
```console
make -j$(nproc)
sudo make install
```
### Mac
Utilisez le gestionnaire de paquets [Homebrew](https://brew.sh/) pour installer `libiconv`, `bison`, `re2c` et `pkg-config` :
@@ -56,28 +52,28 @@ Puis exécutez le script de configuration :
--with-iconv=/opt/homebrew/opt/libiconv/
```
Les options de configuration spécifiées sont nécessaires pour la compilation, mais vous pouvez également inclure d'autres options selon vos besoins, par exemple pour ajouter des extensions supplémentaires.
## Compilez PHP
Finalement, compilez et installez PHP :
```console
make -j$(sysctl -n hw.logicalcpu)
make -j"$(getconf _NPROCESSORS_ONLN)"
sudo make install
```
## Compiler l'application Go
Vous pouvez maintenant utiliser la bibliothèque Go et compiler notre build de Caddy :
Vous pouvez maintenant compilez FrankenPHP :
```console
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar x
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz
cd frankenphp-main/caddy/frankenphp
CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build
```
### Utiliser xcaddy
Vous pouvez utiliser à la place [xcaddy](https://github.com/caddyserver/xcaddy) pour compiler FrankenPHP avec [des modules Caddy additionnels](https://caddyserver.com/docs/modules/):
Alternativement, Vous pouvez utiliser [xcaddy](https://github.com/caddyserver/xcaddy) pour compiler FrankenPHP avec [des modules Caddy additionnels](https://caddyserver.com/docs/modules/):
```console
CGO_ENABLED=1 \
@@ -85,6 +81,7 @@ XCADDY_GO_BUILD_FLAGS="-ldflags '-w -s'" \
xcaddy build \
--output frankenphp \
--with github.com/dunglas/frankenphp/caddy \
--with github.com/dunglas/caddy-cbrotli \
--with github.com/dunglas/mercure/caddy \
--with github.com/dunglas/vulcain/caddy
# Add extra Caddy modules here

View File

@@ -18,6 +18,9 @@ RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini
```
Le binaire statique cherchera un fichier `php.ini` dans le répertoire de travail courant,
dans `/lib/` ainsi que [les autres emplacements standards](https://www.php.net/manual/fr/configuration.file.php).
## Configuration du Caddyfile
Pour enregistrer l'exécutable de FrankenPHP, l'[option globale](https://caddyserver.com/docs/caddyfile/concepts#global-options) `frankenphp` doit être définie, puis les [directives HTTP](https://caddyserver.com/docs/caddyfile/concepts#directives) `php_server` ou `php` peuvent être utilisées dans les blocs de site pour servir votre application PHP.
@@ -28,8 +31,6 @@ Exemple minimal :
{
# Activer FrankenPHP
frankenphp
# Configurer l'ordre d'exécution de la directive
order php_server before file_server
}
localhost {

View File

@@ -56,6 +56,7 @@ RUN xcaddy build \
--output /usr/local/bin/frankenphp \
--with github.com/dunglas/frankenphp=./ \
--with github.com/dunglas/frankenphp/caddy=./caddy/ \
--with github.com/dunglas/caddy-cbrotli \
# Mercure et Vulcain sont inclus dans la construction officielle, mais n'hésitez pas à les retirer
--with github.com/dunglas/mercure/caddy \
--with github.com/dunglas/vulcain/caddy
@@ -145,11 +146,37 @@ RUN \
# Ajouter la capacité supplémentaire de se lier aux ports 80 et 443
setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \
# Donner l'accès en écriture à /data/caddy et /config/caddy
chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy;
chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy
USER ${USER}
```
### Exécution sans capacité
Même lorsqu'il s'exécute en tant qu'utilisateur autre que root, FrankenPHP a besoin de la capacité `CAP_NET_BIND_SERVICE`
pour que son serveur utilise les ports privilégiés (80 et 443).
Si vous exposez FrankenPHP sur un port non privilégié (à partir de 1024), il est possible de faire fonctionner le serveur web avec un utilisateur qui n'est pas root, et sans avoir besoin d'aucune capacité.
```dockerfile
FROM dunglas/frankenphp
ARG USER=www-data
RUN
# Utiliser "adduser -D ${USER}" pour les distros basées sur Alpine
useradd -D ${USER};
# Supprimer la capacité par défaut
setcap -r /usr/local/bin/frankenphp; \
# Donner un accès en écriture à /data/caddy et /config/caddy
chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy
USER ${USER}
```
Ensuite, définissez la variable d'environnement `SERVER_NAME` pour utiliser un port non privilégié.
Exemple `:8000`
## Mises à jour
Les images Docker sont construites :

View File

@@ -39,6 +39,13 @@ composer install --ignore-platform-reqs --no-dev -a
composer dump-env prod
```
### Personnaliser la configuration
Pour personnaliser [la configuration](config.md),
vous pouvez mettre un fichier `Caddyfile` ainsi qu'un fichier `php.ini`
dans le répertoire principal de l'application à intégrer
(`$TMPDIR/my-prepared-app` dans l'exemple précédent).
## Créer un binaire Linux
La manière la plus simple de créer un binaire Linux est d'utiliser le builder basé sur Docker que nous fournissons.

View File

@@ -34,20 +34,19 @@ $fiber->resume();
Les extensions suivantes sont connues pour ne pas être compatibles avec FrankenPHP :
| Nom | Problème |
|---------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [XDebug](https://xdebug.org) | XDebug peut planter, ou se bloquer quand utilisé avec PHP 8.3. Une solution consiste à dwongrader vers PHP 8.2. Ce problème est [suivi par XDebug](https://github.com/dunglas/frankenphp/issues/563#issuecomment-1952226212). |
| [Tideways](https://tideways.com/) | En mode worker, l'extension Tideways [empêche les scripts workers de se terminer correctement ou consomme 100% du CPU](https://github.com/dunglas/frankenphp/issues/578#issuecomment-1966620351). Ce problème a été signalé à Tideways. |
| [ext-openssl](https://www.php.net/manual/fr/book.openssl.php) | Lors de l'utilisation d'une version statique de FrankenPHP (construite avec la libc musl), l'extension OpenSSL peut planter sous de fortes charges. Une solution consiste à utiliser une version liée dynamiquement (comme celle utilisée dans les images Docker). Ce bogue est [suivi par PHP](https://github.com/php/php-src/issues/13648). |
| Nom | Raison | Alternatives |
| ---------------------------------------------------------------------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------- |
| [imap](https://www.php.net/manual/en/imap.installation.php) | Non thread-safe | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) |
| [newrelic](https://docs.newrelic.com/docs/apm/agents/php-agent/getting-started/introduction-new-relic-php/)| Non thread-safe | - |
## Extensions PHP boguées
Les extensions suivantes ont des bugs connus ou des comportements inattendus lorsqu'elles sont utilisées avec FrankenPHP :
Nom | Problème
[XDebug](https://xdebug.org/) | XDebug peut planter, ou se bloquer quand utilisé avec PHP 8.3. Une solution consiste à dwongrader vers PHP 8.2. Ce problème est [suivi par XDebug](https://github.com/dunglas/frankenphp/issues/563#issuecomment-1952226212).
[Tideways](https://tideways.com/) | En mode worker, l'extension Tideways [empêche les scripts workers de se terminer correctement ou consomme 100% du CPU](https://github.com/dunglas/frankenphp/issues/578#issuecomment-1966620351). Ce problème a été signalé à Tideways.
[ext-openssl](https://www.php.net/manual/fr/book.openssl.php) | Lors de l'utilisation d'une version statique de FrankenPHP (construite avec la libc musl), l'extension OpenSSL peut planter sous de fortes charges. Une solution consiste à utiliser une version liée dynamiquement (comme celle utilisée dans les images Docker). Ce bogue est [suivi par PHP](https://github.com/php/php-src/issues/13648).
| Nom | Problème |
|---------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [ext-openssl](https://www.php.net/manual/fr/book.openssl.php) | Lors de l'utilisation d'une version statique de FrankenPHP (construite avec la libc musl), l'extension OpenSSL peut planter sous de fortes charges. Une solution consiste à utiliser une version liée dynamiquement (comme celle utilisée dans les images Docker). Ce bogue est [suivi par PHP](https://github.com/php/php-src/issues/13648). |
| [parallel](https://github.com/krakjoe/parallel) | `parallel` fait geler et planter FrankenPHP. [Rapport de bogue](https://github.com/krakjoe/parallel/issues/308) |
## get_browser

View File

@@ -23,7 +23,6 @@ Vous pouvez également exécuter vos projets Laravel avec FrankenPHP depuis votr
```caddyfile
{
frankenphp
order php_server before file_server
}
# Le nom de domaine de votre serveur
@@ -53,13 +52,13 @@ Après avoir installé Octane, vous pouvez exécuter la commande Artisan `octane
php artisan octane:install --server=frankenphp
```
Le serveur Octane peut être démarré via la commande Artisan `octane:start`.
Le serveur Octane peut être démarré via la commande Artisan `octane:frankenphp`.
```console
php artisan octane:start
php artisan octane:frankenphp
```
La commande `octane:start` peut prendre les options suivantes :
La commande `octane:frankenphp` peut prendre les options suivantes :
* `--host` : L'adresse IP à laquelle le serveur doit se lier (par défaut : `127.0.0.1`)
* `--port` : Le port sur lequel le serveur doit être disponible (par défaut : `8000`)

View File

@@ -5,7 +5,7 @@ Mercure permet de pousser des événements en temps réel vers tous les appareil
Aucune bibliothèque JS ou SDK requis !
![Mercure](https://mercure.rocks/static/main.png)
![Mercure](../mercure-hub.png)
Pour activer le hub Mercure, mettez à jour le `Caddyfile` comme décrit [sur le site de Mercure](https://mercure.rocks/docs/hub/config).

110
docs/fr/performance.md Normal file
View File

@@ -0,0 +1,110 @@
# Performance
Par défaut, FrankenPHP essaie d'offrir un bon compromis entre performance et facilité d'utilisation.
Cependant, il est possible d'améliorer considérablement les performances en utilisant une configuration appropriée.
## Nombre de threads et de workers
Par défaut, FrankenPHP démarre 2 fois plus de threads et de workers (en mode worker) que le nombre de CPU disponibles.
Les valeurs appropriées dépendent fortement de la manière dont votre application est écrite, de ce qu'elle fait et de votre matériel.
Nous recommandons fortement de modifier ces valeurs.
Pour trouver les bonnes valeurs, il est souhaitable d'effectuer des tests de charge simulant le trafic réel.
[k6](https://k6.io) et [Gatling](https://gatling.io) sont de bons outils pour cela.
Pour configurer le nombre de threads, utilisez l'option `num_threads` des directives `php_server` et `php`.
Pour changer le nombre de travailleurs, utilisez l'option `num` de la section `worker` de la directive `frankenphp`.
## Mode worker
Activer [le mode worker](worker.md) améliorere considérablement les performances,
mais votre application doit être adaptée pour être compatible avec ce mode :
vous devez créer un script worker et vous assurer que l'application n'a pas de fuite de mémoire.
## Ne pas utiliser musl
Les binaires statiques que nous fournissons et la variante Alpine Linux des images Docker officielles
utilisent [la librairie musl](https://musl.libc.org).
PHP est connu pour être significativement plus lent lorsqu'il utilise cette bibliothèque C alternative au lieu de la bibliothèque GNU traditionnelle,
surtout lorsqu'il est compilé en mode ZTS (thread-safe), ce qui est nécessaire pour FrankenPHP.
En outre, certains bogues ne se produisent que lors de l'utilisation de musl.
Dans les environnements de production, nous recommandons fortement d'utiliser la glibc.
Ceci peut être réalisé en utilisant les images Docker Debian (par défaut) et [en compilant FrankenPHP à partir des sources](compile.md).
Alternativement, nous fournissons des binaires statiques compilés avec [l'allocateur mimalloc](https://github.com/microsoft/mimalloc), ce qui rend FrankenPHP+musl plus rapide (mais toujours plus lent que FrankenPHP+glibc).
## Configuration du runtime Go
FrankenPHP est écrit en Go.
En général, le runtime Go ne nécessite pas de configuration particulière, mais dans certaines circonstances,
une configuration spécifique améliore les performances.
Vous voudrez probablement mettre la variable d'environnement `GODEBUG` à `cgocheck=0` (la valeur par défaut dans les images Docker de FrankenPHP).
Si vous exécutez FrankenPHP dans des conteneurs (Docker, Kubernetes, LXC...) et que vous limitez la mémoire disponible pour les conteneurs,
mettez la variable d'environnement `GOMEMLIMIT` à la quantité de mémoire disponible.
Pour plus de détails, [la page de documentation Go dédiée à ce sujet](https://pkg.go.dev/runtime#hdr-Environment_Variables) est à lire absolument pour tirer le meilleur parti du runtime.
## `file_server`
Par défaut, la directive `php_server` met automatiquement en place un serveur de fichiers pour
pour servir les fichiers statiques (assets) stockés dans le répertoire racine.
Cette fonctionnalité est pratique, mais a un coût.
Pour la désactiver, utilisez la configuration suivante :
```caddyfile
php_server {
file_server off
}
```
## *Placeholders*
Vous pouvez utiliser des [*placeholders*](https://caddyserver.com/docs/conventions#placeholders) dans les directives `root` et `env`.
Cependant, cela empêche la mise en cache de ces valeurs et a un coût important en termes de performances.
Si possible, évitez les *placeholders* dans ces directives.
## `resolve_root_symlink`
Par défaut, si le *document root* est un lien symbolique, il est automatiquement résolu par FrankenPHP (c'est nécessaire pour le bon fonctionnement de PHP).
Si la racine du document n'est pas un lien symbolique, vous pouvez désactiver cette fonctionnalité.
```caddyfile
php_server {
resolve_root_symlink false
}
```
Cela améliorera les performances si la directive `root` contient des [*placeholders*](https://caddyserver.com/docs/conventions#placeholders).
Le gain sera négligeable dans les autres cas.
## Journaux
La journalisation est évidemment très utile, mais, par définition, elle nécessite des opérations d'*I/O* et des allocations de mémoire,
ce qui réduit considérablement les performances.
Assurez-vous de [définir le niveau de journalisation](https://caddyserver.com/docs/caddyfile/options#log) correctement,
et de ne journaliser que ce qui est nécessaire.
## Performances de PHP
FrankenPHP utilise l'interpréteur PHP officiel.
Toutes les optimisations de performances habituelles liées à PHP s'appliquent à FrankenPHP.
En particulier :
* vérifiez que [OPcache](https://www.php.net/manual/en/book.opcache.php) est installé, activé et correctement configuré
* activez [les optimisations de l'autoloader de Composer](https://getcomposer.org/doc/articles/autoloader-optimization.md)
* assurez-vous que le cache `realpath` est suffisamment grand pour les besoins de votre application
* utilisez le [pré-chargement](https://www.php.net/manual/en/opcache.preloading.php)
Pour plus de détails, lisez [l'entrée de la documentation dédiée de Symfony](https://symfony.com/doc/current/performance.html)
(la plupart des conseils sont utiles même si vous n'utilisez pas Symfony).

View File

@@ -77,4 +77,5 @@ Les variables d'environnement suivantes peuvent être transmises à `docker buil
* `CLEAN` : lorsque défini, `libphp` et toutes ses dépendances sont construites à partir de zéro (pas de cache)
* `DEBUG_SYMBOLS` : lorsque défini, les symboles de débogage ne seront pas supprimés et seront ajoutés dans le binaire
* `NO_COMPRESS`: ne pas compresser le binaire avec UPX
* `MIMALLOC`: (expérimental, Linux seulement) remplace l'allocateur mallocng de musl par [mimalloc](https://github.com/microsoft/mimalloc) pour des performances améliorées
* `RELEASE` : (uniquement pour les mainteneurs) lorsque défini, le binaire résultant sera uploadé sur GitHub

View File

@@ -71,12 +71,12 @@ $myApp->boot();
// En dehors de la boucle pour de meilleures performances (moins de travail effectué)
$handler = static function () use ($myApp) {
// Appelé lorsqu'une requête est reçue,
// les superglobales, php://input, etc., sont réinitialisés
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
// Appelé lorsqu'une requête est reçue,
// les superglobales, php://input, etc., sont réinitialisés
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
};
for($nbRequests = 0, $running = true; isset($_SERVER['MAX_REQUESTS']) && ($nbRequests < ((int)$_SERVER['MAX_REQUESTS'])) && $running; ++$nbRequests) {
for ($nbRequests = 0, $running = true; isset($_SERVER['MAX_REQUESTS']) && ($nbRequests < ((int)$_SERVER['MAX_REQUESTS'])) && $running; ++$nbRequests) {
$running = \frankenphp_handle_request($handler);
// Faire quelque chose après l'envoi de la réponse HTTP
@@ -117,3 +117,26 @@ Comme PHP n'a pas été initialement conçu pour des processus de longue durée,
Une solution pour utiliser ce type de code en mode worker est de redémarrer le script worker après avoir traité un certain nombre de requêtes :
Le code du worker précédent permet de configurer un nombre maximal de requêtes à traiter en définissant une variable d'environnement nommée `MAX_REQUESTS`.
## Comportement des superglobales
[Les superglobales PHP](https://www.php.net/manual/fr/language.variables.superglobals.php) (`$_SERVER`, `$_ENV`, `$_GET`...)
se comportent comme suit :
* avant le premier appel à `frankenphp_handle_request()`, les superglobales contiennent des valeurs liées au script worker lui-même
* pendant et après l'appel à `frankenphp_handle_request()`, les superglobales contiennent des valeurs générées à partir de la requête HTTP traitée, chaque appel à `frankenphp_handle_request()` change les valeurs des superglobales
Pour accéder aux superglobales du script worker à l'intérieur de la fonction de rappel, vous devez les copier et importer la copie dans le scope de la fonction :
```php
<?php
// Copier la superglobale $_SERVER du worker avant le premier appel à frankenphp_handle_request()
$workerServer = $_SERVER;
$handler = static function () use ($workerServer) {
var_dump($_SERVER); // $_SERVER lié à la requête
var_dump($workerServer); // $_SERVER du script worker
};
// ...
```

View File

@@ -8,8 +8,8 @@ every approved pull request or on your own fork once setup.
In the repository settings, under secrets, add the following secrets:
- `REGISTRY_LOGIN_SERVER`: The docker registry to use (e.g. `docker.io`).
- `REGISTRY_USERNAME`: The username to use to login to the registry (e.g. `dunglas`).
- `REGISTRY_PASSWORD`: The password to use to login to the registry (e.g. an access key).
- `REGISTRY_USERNAME`: The username to use to log in to the registry (e.g. `dunglas`).
- `REGISTRY_PASSWORD`: The password to use to log in to the registry (e.g. an access key).
- `IMAGE_NAME`: The name of the image (e.g. `dunglas/frankenphp`).
## Building and Pushing the Image

View File

@@ -34,10 +34,10 @@ $fiber->resume();
The following extensions are known not to be compatible with FrankenPHP:
| Name | Reason | Alternatives |
| ---------------------------------------------------------------------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------- |
| [imap](https://www.php.net/manual/en/imap.installation.php) | Not thread-safe | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) |
| [newrelic](https://docs.newrelic.com/docs/apm/agents/php-agent/getting-started/introduction-new-relic-php/)| Not thread-safe | - |
| Name | Reason | Alternatives |
|-------------------------------------------------------------------------------------------------------------|-----------------|----------------------------------------------------------------------------------------------------------------------|
| [imap](https://www.php.net/manual/en/imap.installation.php) | Not thread-safe | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) |
| [newrelic](https://docs.newrelic.com/docs/apm/agents/php-agent/getting-started/introduction-new-relic-php/) | Not thread-safe | - |
## Buggy PHP Extensions
@@ -45,9 +45,8 @@ The following extensions have known bugs and unexpected behaviors when used with
| Name | Problem |
|---------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [XDebug](https://xdebug.org/) | XDebug may crash, or hang on PHP 8.3. A workaround is to downgrade to PHP 8.2. This problem is [being tracked by XDebug](https://github.com/dunglas/frankenphp/issues/563#issuecomment-1952226212). |
| [Tideways](https://tideways.com/) | In worker mode, the Tideways extension [prevents worker scripts to finish properly](https://github.com/dunglas/frankenphp/issues/578#issuecomment-1966620351) or consumes 100% of the CPU. This has been reported to Tideways. |
| [ext-openssl](https://www.php.net/manual/en/book.openssl.php) | When using a static build of FrankenPHP (built with the musl libc), the OpenSSL extension may crash under heavy loads. A workaround is to use a dynamically linked build (like the one used in Docker images). This bug is [being tracked by PHP](https://github.com/php/php-src/issues/13648). |
| [parallel](https://github.com/krakjoe/parallel) | `parallel` makes FrankenPHP freeze and crash. [Bug report](https://github.com/krakjoe/parallel/issues/308) |
## get_browser
@@ -133,9 +132,42 @@ done
/usr/local/bin/frankenphp php-cli ${args[@]}
```
Then set the environment variable `PHP_BINARY` to the path of our php script and composer should pass:
Then set the environment variable `PHP_BINARY` to the path of our `php` script and run Composer:
```bash
```console
export PHP_BINARY=/usr/local/bin/php
composer install
```
## Troubleshooting TLS/SSL Issues with Static Binaries
When using the static binaries, you may encounter the following TLS-related errors, for instance when sending emails using STARTTLS:
```text
Unable to connect with STARTTLS: stream_socket_enable_crypto(): SSL operation failed with code 5. OpenSSL Error messages:
error:80000002:system library::No such file or directory
error:80000002:system library::No such file or directory
error:80000002:system library::No such file or directory
error:0A000086:SSL routines::certificate verify failed
```
As the static binary doesn't bundle TLS certificates, you need to point OpenSSL to your local CA certificates installation.
Inspect the output of [`openssl_get_cert_locations()`](https://www.php.net/manual/en/function.openssl-get-cert-locations.php),
to find where CA certificates must be installed and store them at this location.
> ![WARNING]
> Web and CLI contexts may have different settings.
> Be sure to run `openssl_get_cert_locations()` in the proper context.
[CA certificates extracted from Mozilla can be downloaded on the curl site](https://curl.se/docs/caextract.html).
Alternatively, many distributions, including Debian, Ubuntu, and Alpine provide packages named `ca-certificates` that contain these certificates.
It's also possible to use the `SSL_CERT_FILE` and `SSL_CERT_DIR` to hint OpenSSL where to look for CA certificates:
```console
# Set TLS certificates environment variables
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
export SSL_CERT_DIR=/etc/ssl/certs
```

View File

@@ -22,7 +22,6 @@ Alternatively, you can run your Laravel projects with FrankenPHP from your local
```caddyfile
{
frankenphp
order php_server before file_server
}
# The domain name of your server
@@ -52,13 +51,13 @@ After installing Octane, you may execute the `octane:install` Artisan command, w
php artisan octane:install --server=frankenphp
```
The Octane server can be started via the `octane:start` Artisan command.
The Octane server can be started via the `octane:frankenphp` Artisan command.
```console
php artisan octane:start
php artisan octane:frankenphp
```
The `octane:start` command can take the following options:
The `octane:frankenphp` command can take the following options:
* `--host`: The IP address the server should bind to (default: `127.0.0.1`)
* `--port`: The port the server should be available on (default: `8000`)
@@ -73,3 +72,108 @@ The `octane:start` command can take the following options:
* `--log-level`: Log messages at or above the specified log level
Learn more about [Laravel Octane in its official documentation](https://laravel.com/docs/octane).
## Laravel Apps As Standalone Binaries
Using [FrankenPHP's application embedding feature](embed.md), it's possible to distribute Laravel
apps as standalone binaries.
Follow these steps to package your Laravel app as a standalone binary for Linux:
1. Create a file named `static-build.Dockerfile` in the repository of your app:
```dockerfile
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
# Copy your app
WORKDIR /go/src/app/dist/app
COPY . .
# Remove the tests and other unneeded files to save space
# Alternatively, add these files to a .dockerignore file
RUN rm -Rf tests/
# Copy .env file
RUN cp .env.example .env
# Change APP_ENV and APP_DEBUG to be production ready
RUN sed -i'' -e 's/^APP_ENV=.*/APP_ENV=production/' -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' .env
# Make other changes to your .env file if needed
# Install the dependencies
RUN composer install --ignore-platform-reqs --no-dev -a
# Build the static binary
WORKDIR /go/src/app/
RUN EMBED=dist/app/ ./build-static.sh
```
> [!CAUTION]
>
> Some `.dockerignore` files
> will ignore the `vendor/` directory and `.env` files. Be sure to adjust or remove the `.dockerignore` file before the build.
2. Build:
```console
docker build -t static-laravel-app -f static-build.Dockerfile .
```
3. Extract the binary:
```console
docker cp $(docker create --name static-laravel-app-tmp static-laravel-app):/go/src/app/dist/frankenphp-linux-x86_64 frankenphp ; docker rm static-laravel-app-tmp
```
4. Populate caches:
```console
./frankenphp php-cli artisan optimize
```
5. Run database migrations (if any):
```console
./frankenphp php-cli artisan migrate
````
6. Generate app's secret key:
```console
./frankenphp php-cli artisan key:generate
```
7. Start the server:
```console
./frankenphp php-server
```
Your app is now ready!
Learn more about the options available and how to build binaries for other OSes in the [applications embedding](embed.md)
documentation.
### Changing The Storage Path
By default, Laravel stores uploaded files, caches, logs, etc. in the application's `storage/` directory.
This is not suitable for embedded applications, as each new version will be extracted into a different temporary directory.
Set the `LARAVEL_STORAGE_PATH` environment variable (for example, in your `.env` file) or call the `Illuminate\Foundation\Application::useStoragePath()` method to use a directory outside the temporary directory.
### Running Octane With Standalone Binaries
It's even possible to package Laravel Octane apps as standalone binaries!
To do so, [install Octane properly](#laravel-octane) and follow the steps described in [the previous section](#laravel-apps-as-standalone-binaries).
Then, to start FrankenPHP in worker mode through Octane, run:
```console
PATH="$PWD:$PATH" ./frankenphp php-cli artisan octane:frankenphp
```
> ![CAUTION]
>
> For the command to work, the standalone binary **must** be named `frankenphp`
> because Octane needs a program named `frankenphp` available in the path.

BIN
docs/mercure-hub.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@@ -5,7 +5,7 @@ Mercure allows to push events in real-time to all the connected devices: they wi
No JS library or SDK required!
![Mercure](https://mercure.rocks/static/main.png)
![Mercure](mercure-hub.png)
To enable the Mercure hub, update the `Caddyfile` as described [on Mercure's site](https://mercure.rocks/docs/hub/config).

110
docs/performance.md Normal file
View File

@@ -0,0 +1,110 @@
# Performance
By default, FrankenPHP tries to offer a good compromise between performance and ease of use.
However, it is possible to substantially improve performance using an appropriate configuration.
## Number of Threads and Workers
By default, FrankenPHP starts 2 times more threads and workers (in worker mode) than the available numbers of CPU.
The appropriate values depend heavily on how your application is written, what it does and your hardware.
We strongly recommend changing these values.
To find the right values, it's best to run load tests simulating real traffic.
[k6](https://k6.io) and [Gatling](https://gatling.io) are good tools for this.
To configure the number of threads, use the `num_threads` option of the `php_server` and `php` directives.
To change the number of workers, use the `num` option of the `worker` section of the `frankenphp` directive.
## Worker Mode
Enabling [the worker mode](worker.md) dramatically improves performance,
but your app must be adapted to be compatible with this mode:
you need to create a worker script and to be sure that the app is not leaking memory.
## Don't Use musl
The static binaries we provide and the Alpine Linux variant of the official Docker images
are using [the musl libc](https://musl.libc.org).
PHP is known to be significantly slower when using this alternative C library instead of the traditional GNU library,
especially when compiled in ZTS mode (thread-safe), which is required for FrankenPHP.
Also, some bugs also only happen when using musl.
In production environements, we strongly recommend to use the glibc.
This can be achieved by using the Debian Docker images (the default) and [by compiling FrankenPHP from sources](compile.md).
Alternatively, we provide static binaries compiled with [the mimalloc allocator](https://github.com/microsoft/mimalloc), which makes FrankenPHP+musl faster (but still slower than FrankenPHP+glibc).
## Go Runtime Configuration
FrankenPHP is written in Go.
In general, the Go runtime doesn't require any special configuration, but in certain circumstances,
specific configuration improves performance.
You likely want to set the `GODEBUG` environment variable to `cgocheck=0` (the default in the FrankenPHP Docker images).
If you run FrankenPHP in containers (Docker, Kubernetes, LXC...) and limit the memory available for the containers,
set the `GOMEMLIMIT` environment variable to the available amount of memory.
For more details, [the Go documentation page dedicated to this subject](https://pkg.go.dev/runtime#hdr-Environment_Variables) is a must-read to get the most out of the runtime.
## `file_server`
By default, the `php_server` directive automatically sets up a file server to
serve static files (assets) stored in the root directory.
This feature is convenient, but comes with a cost.
To disable it, use the following config:
```caddyfile
php_server {
file_server off
}
```
## Placeholders
You can use [placeholders](https://caddyserver.com/docs/conventions#placeholders) in the `root` and `env` directives.
However, this prevents caching these values, and comes with a significant performance cost.
If possible, avoid placeholders in these directives.
## `resolve_root_symlink`
By default, if the document root is a symbolic link, it is automatically resolved by FrankenPHP (this is necessary for PHP to work properly).
If the document root is not a symlink, you can disable this feature.
```caddyfile
php_server {
resolve_root_symlink false
}
```
This will improve performance if the `root` directive contains [placeholders](https://caddyserver.com/docs/conventions#placeholders).
The gain will be negligible in other cases.
## Logs
Logging is obviously very useful, but, by definition,
it requires I/O operations and memory allocations, which considerably reduces performance.
Make sure you [set the logging level](https://caddyserver.com/docs/caddyfile/options#log) correctly,
and only log what's necessary.
## PHP Performance
FrankenPHP uses the official PHP interpreter.
All usual PHP-related performance optimizations apply with FrankenPHP.
In particular:
* check that [OPcache](https://www.php.net/manual/en/book.opcache.php) is installed, enabled and properly configured
* enable [Composer autoloader optimizations](https://getcomposer.org/doc/articles/autoloader-optimization.md)
* ensure that the `realpath` cache is big enough for the needs of your application
* use [preloading](https://www.php.net/manual/en/opcache.preloading.php)
For more details, read [the dedicated Symfony documentation entry](https://symfony.com/doc/current/performance.html)
(most tips are useful even if you don't use Symfony).

View File

@@ -127,7 +127,7 @@ Go into the directory containing your project (`<project-name>`), and start the
docker compose up -d --wait
```
Your server is up and running, and a HTTPS certificate has been automatically generated for you.
Your server is up and running, and an HTTPS certificate has been automatically generated for you.
Go to `https://your-domain-name.example.com` and enjoy!
> [!CAUTION]

View File

@@ -79,4 +79,5 @@ script to customize the static build:
* `CLEAN`: when set, libphp and all its dependencies are built from scratch (no cache)
* `NO_COMPRESS`: don't compress the resulting binary using UPX
* `DEBUG_SYMBOLS`: when set, debug-symbols will not be stripped and will be added within the binary
* `MIMALLOC`: (experimental, Linux-only) replace musl's mallocng by [mimalloc](https://github.com/microsoft/mimalloc) for improved performance
* `RELEASE`: (maintainers only) when set, the resulting binary will be uploaded on GitHub

View File

@@ -19,7 +19,6 @@ Docker sürümü 23.0'dan düşükse, derleme dockerignore [pattern issue](https
!testdata/*.php
!testdata/*.txt
+!caddy
+!C-Thread-Pool
+!internal
```

View File

@@ -71,7 +71,7 @@ Ayrıca aşağıdaki tek komut satırı ile de çalıştırabilirsiniz:
* [API Platform](https://api-platform.com/docs/distribution/)
* [Laravel](https://frankenphp.dev/docs/laravel/)
* [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp)
* [WordPress](https://github.com/dunglas/frankenphp-wordpress)
* [WordPress](https://github.com/StephenMiracle/frankenwp)
* [Drupal](https://github.com/dunglas/frankenphp-drupal)
* [Joomla](https://github.com/alexandreelise/frankenphp-joomla)
* [TYPO3](https://github.com/ochorocho/franken-typo3)

View File

@@ -16,7 +16,10 @@ tar xf php-*
cd php-*/
```
Ardından, PHP'yi platformunuz için yapılandırın:
Ardından, PHP'yi platformunuz için yapılandırın.
Bu şekilde yapılandırma gereklidir, ancak başka opsiyonlar da ekleyebilirsiniz (örn. ekstra uzantılar)
İhtiyaç halinde.
### Linux
@@ -28,13 +31,6 @@ Ardından, PHP'yi platformunuz için yapılandırın:
--enable-zend-max-execution-timers
```
Son olarak, PHP'yi derleyin ve kurun:
```console
make -j$(nproc)
sudo make install
```
### Mac
Yüklemek için [Homebrew](https://brew.sh/) paket yöneticisini kullanın
@@ -58,13 +54,12 @@ Ardından yapılandırma betiğini çalıştırın:
--with-iconv=/opt/homebrew/opt/libiconv/
```
Bu şekilde yapılandırma gereklidir, ancak başka opsiyonlar da ekleyebilirsiniz (örn. ekstra uzantılar)
İhtiyaç halinde.
## PHP Derleyin
Son olarak, PHP'yi derleyin ve yükleyin:
Son olarak, PHP'yi derleyin ve kurun:
```console
make -j$(sysctl -n hw.logicalcpu)
make -j"$(getconf _NPROCESSORS_ONLN)"
sudo make install
```
@@ -73,7 +68,7 @@ sudo make install
Artık Go kütüphanesini kullanabilir ve Caddy yapımızı derleyebilirsiniz:
```console
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar x
curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz
cd frankenphp-main/caddy/frankenphp
CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build
```
@@ -88,6 +83,7 @@ XCADDY_GO_BUILD_FLAGS="-ldflags '-w -s'" \
xcaddy build \
--output frankenphp \
--with github.com/dunglas/frankenphp/caddy \
--with github.com/dunglas/caddy-cbrotli \
--with github.com/dunglas/mercure/caddy \
--with github.com/dunglas/vulcain/caddy
# Add extra Caddy modules here

View File

@@ -28,8 +28,6 @@ Minimal örnek:
{
# FrankenPHP'yi aktif et
frankenphp
# Yönergenin ne zaman yürütülmesi gerektiğini yapılandırma
order php_server before file_server
}
localhost {

View File

@@ -56,8 +56,9 @@ RUN xcaddy build \
--output /usr/local/bin/frankenphp \
--with github.com/dunglas/frankenphp=./ \
--with github.com/dunglas/frankenphp/caddy=./caddy/ \
# Mercure ve Vulcain resmi yapıya dahil edilmiştir, ancak bunları kaldırmaktan çekinmeyin
--with github.com/dunglas/caddy-cbrotli \
--with github.com/dunglas/caddy-cbrotli \
# Mercure ve Vulcain resmi yapıya dahil edilmiştir, ancak bunları kaldırmaktan çekinmeyin
--with github.com/dunglas/mercure/caddy \
--with github.com/dunglas/vulcain/caddy
# Buraya ekstra Caddy modülleri ekleyin

View File

@@ -44,8 +44,6 @@ Aşağıdaki eklentiler FrankenPHP ile kullanıldığında bilinen hatalara ve b
| Adı | Problem |
|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [XDebug](https://xdebug.org/) | XDebug çökebilir veya askıda kalabilir. Bu sorun [XDebug tarafından takip ediliyor](https://github.com/dunglas/frankenphp/issues/563#issuecomment-1952226212). |
| [Tideways](https://tideways.com/) | Worker modunda, Tideways eklentisi [worker komut dosyalarının düzgün şekilde sonlandırılmasını engelliyor](https://github.com/dunglas/frankenphp/issues/578#issuecomment-1966620351) veya CPU'nun %100'ünü tüketiyor. Bu durum Tideways'e bildirilmiştir. |
## get_browser

View File

@@ -22,7 +22,6 @@ Alternatif olarak, Laravel projelerinizi FrankenPHP ile yerel makinenizden çal
```caddyfile
{
frankenphp
order php_server before file_server
}
# Sunucunuzun alan adı
@@ -52,13 +51,13 @@ Octane'ı kurduktan sonra, Octane'ın yapılandırma dosyasını uygulamanıza y
php artisan octane:install --server=frankenphp
```
Octane sunucusu `octane:start` Artisan komutu aracılığıyla başlatılabilir.
Octane sunucusu `octane:frankenphp` Artisan komutu aracılığıyla başlatılabilir.
```console
php artisan octane:start
php artisan octane:frankenphp
```
`octane:start` komutu aşağıdaki seçenekleri alabilir:
`octane:frankenphp` komutu aşağıdaki seçenekleri alabilir:
* `--host`: Sunucunun bağlanması gereken IP adresi (varsayılan: `127.0.0.1`)
* `--port`: Sunucunun erişilebilir olması gereken port (varsayılan: `8000`)

View File

@@ -5,7 +5,7 @@ Mercure, olayları tüm bağlı cihazlara gerçek zamanlı olarak göndermeye ol
JS kütüphanesi veya SDK gerekmez!
![Mercure](https://mercure.rocks/static/main.png)
![Mercure](../mercure-hub.png)
Mercure hub'ını etkinleştirmek için [Mercure'ün sitesinde](https://mercure.rocks/docs/hub/config) açıklandığı gibi `Caddyfile`'ı güncelleyin.

View File

@@ -71,12 +71,12 @@ $myApp->boot();
// Daha iyi performans için döngü dışında işleyici (daha az iş yapıyor)
$handler = static function () use ($myApp) {
// Bir istek alındığında çağrılır,
// superglobals, php://input ve benzerleri sıfırlanır
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
// Bir istek alındığında çağrılır,
// superglobals, php://input ve benzerleri sıfırlanır
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
};
for($nbRequests = 0, $running = true; isset($_SERVER['MAX_REQUESTS']) && ($nbRequests < ((int)$_SERVER['MAX_REQUESTS'])) && $running; ++$nbRequests) {
for ($nbRequests = 0, $running = true; isset($_SERVER['MAX_REQUESTS']) && ($nbRequests < ((int)$_SERVER['MAX_REQUESTS'])) && $running; ++$nbRequests) {
$running = \frankenphp_handle_request($handler);
// HTTP yanıtını gönderdikten sonra bir şey yapın

View File

@@ -71,19 +71,22 @@ $myApp->boot();
// Handler outside the loop for better performance (doing less work)
$handler = static function () use ($myApp) {
// Called when a request is received,
// superglobals, php://input and the like are reset
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
// Called when a request is received,
// superglobals, php://input and the like are reset
echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
};
for($nbRequests = 0, $running = true; isset($_SERVER['MAX_REQUESTS']) && ($nbRequests < ((int)$_SERVER['MAX_REQUESTS'])) && $running; ++$nbRequests) {
$running = \frankenphp_handle_request($handler);
$maxRequests = (int)($_SERVER['MAX_REQUESTS'] ?? 0);
for ($nbRequests = 0; !$maxRequests || $nbRequests < $maxRequests; ++$nbRequests) {
$keepRunning = \frankenphp_handle_request($handler);
// Do something after sending the HTTP response
$myApp->terminate();
// Call the garbage collector to reduce the chances of it being triggered in the middle of a page generation
gc_collect_cycles();
if (!$keepRunning) break;
}
// Cleanup
@@ -117,3 +120,26 @@ As PHP was not originally designed for long-running processes, there are still m
A workaround to using this type of code in worker mode is to restart the worker script after processing a certain number of requests:
The previous worker snippet allows configuring a maximum number of request to handle by setting an environment variable named `MAX_REQUESTS`.
## Superglobals Behavior
[PHP superglobals](https://www.php.net/manual/en/language.variables.superglobals.php) (`$_SERVER`, `$_ENV`, `$_GET`...)
behave as follows:
* before the first call to `frankenphp_handle_request()`, superglobals contain values bound to the worker script itself
* during and after the call to `frankenphp_handle_request()`, superglobals contain values generated from the processed HTTP request, each call to `frankenphp_handle_request()` changes the superglobals values
To access the superglobals of the worker script inside the callback, you must copy them and import the copy in the scope of the callback:
```php
<?php
// Copy worker's $_SERVER superglobal before the first call to frankenphp_handle_request()
$workerServer = $_SERVER;
$handler = static function () use ($workerServer) {
var_dump($_SERVER); // Request-bound $_SERVER
var_dump($workerServer); // $_SERVER of the worker script
};
// ...
```

View File

@@ -32,7 +32,7 @@ func init() {
return
}
appPath := filepath.Join(os.TempDir(), "frankenphp_"+strings.TrimSuffix(string(embeddedAppChecksum[:]), "\n"))
appPath := filepath.Join(os.TempDir(), "frankenphp_"+string(embeddedAppChecksum))
if _, err := os.Stat(appPath); os.IsNotExist(err) {
if err := untar(appPath); err != nil {

View File

@@ -6,6 +6,7 @@
#include <errno.h>
#include <ext/spl/spl_exceptions.h>
#include <ext/standard/head.h>
#include <inttypes.h>
#include <php.h>
#include <php_config.h>
#include <php_main.h>
@@ -17,9 +18,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "C-Thread-Pool/thpool.c"
#include "C-Thread-Pool/thpool.h"
#if defined(__linux__)
#include <sys/prctl.h>
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
#include <pthread_np.h>
#endif
#include "_cgo_export.h"
#include "frankenphp_arginfo.h"
@@ -28,8 +31,8 @@
ZEND_TSRMLS_CACHE_DEFINE()
#endif
/* Timeouts are currently fundamentally broken with ZTS except on Linux:
* https://bugs.php.net/bug.php?id=79464 */
/* Timeouts are currently fundamentally broken with ZTS except on Linux and
* FreeBSD: https://bugs.php.net/bug.php?id=79464 */
#ifndef ZEND_MAX_EXECUTION_TIMERS
static const char HARDCODED_INI[] = "max_execution_time=0\n"
"max_input_time=-1\n\0";
@@ -73,11 +76,13 @@ typedef struct frankenphp_server_context {
bool finished;
} frankenphp_server_context;
static uintptr_t frankenphp_clean_server_context() {
__thread frankenphp_server_context *local_ctx = NULL;
static void frankenphp_free_request_context() {
frankenphp_server_context *ctx = SG(server_context);
if (ctx == NULL) {
return 0;
}
free(ctx->cookie_data);
ctx->cookie_data = NULL;
free(SG(request_info).auth_password);
SG(request_info).auth_password = NULL;
@@ -99,19 +104,13 @@ static uintptr_t frankenphp_clean_server_context() {
free(SG(request_info).request_uri);
SG(request_info).request_uri = NULL;
return ctx->current_request;
}
static void frankenphp_request_reset() {
static void frankenphp_destroy_super_globals() {
zend_try {
int i;
for (i = 0; i < NUM_TRACK_VARS; i++) {
zval_ptr_dtor(&PG(http_globals)[i]);
for (int i = 0; i < NUM_TRACK_VARS; i++) {
zval_ptr_dtor_nogc(&PG(http_globals)[i]);
}
memset(&PG(http_globals), 0, sizeof(zval) * NUM_TRACK_VARS);
}
zend_end_try();
}
@@ -122,7 +121,7 @@ static void frankenphp_worker_request_shutdown() {
zend_try { php_output_end_all(); }
zend_end_try();
// TODO: store the list of modules to reload in a global module variable
/* TODO: store the list of modules to reload in a global module variable */
const char **module_name;
zend_module_entry *module;
for (module_name = MODULES_TO_RELOAD; *module_name; module_name++) {
@@ -137,15 +136,15 @@ static void frankenphp_worker_request_shutdown() {
zend_try { php_output_deactivate(); }
zend_end_try();
/* Clean super globals */
frankenphp_request_reset();
/* SAPI related shutdown (free stuff) */
frankenphp_clean_server_context();
frankenphp_free_request_context();
zend_try { sapi_deactivate(); }
zend_end_try();
zend_set_memory_limit(PG(memory_limit));
/* TODO: remove next line when https://github.com/php/php-src/pull/14499 will
* be available */
SG(rfc1867_uploaded_files) = NULL;
}
/* Adapted from php_request_startup() */
@@ -153,6 +152,7 @@ static int frankenphp_worker_request_startup() {
int retval = SUCCESS;
zend_try {
frankenphp_destroy_super_globals();
php_output_activate();
/* initialize global variables */
@@ -162,16 +162,13 @@ static int frankenphp_worker_request_startup() {
/* Keep the current execution context */
sapi_activate();
/*
* Timeouts are currently fundamentally broken with ZTS:
*https://bugs.php.net/bug.php?id=79464
*
*if (PG(max_input_time) == -1) {
* zend_set_timeout(EG(timeout_seconds), 1);
*} else {
* zend_set_timeout(PG(max_input_time), 1);
*}
*/
#ifdef ZEND_MAX_EXECUTION_TIMERS
if (PG(max_input_time) == -1) {
zend_set_timeout(EG(timeout_seconds), 1);
} else {
zend_set_timeout(PG(max_input_time), 1);
}
#endif
if (PG(expose_php)) {
sapi_add_header(SAPI_PHP_VERSION_HEADER,
@@ -196,11 +193,11 @@ static int frankenphp_worker_request_startup() {
zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER));
// unfinish the request
/* Unfinish the request */
frankenphp_server_context *ctx = SG(server_context);
ctx->finished = false;
// TODO: store the list of modules to reload in a global module variable
/* TODO: store the list of modules to reload in a global module variable */
const char **module_name;
zend_module_entry *module;
for (module_name = MODULES_TO_RELOAD; *module_name; module_name++) {
@@ -266,12 +263,13 @@ PHP_FUNCTION(frankenphp_request_headers) {
}
/* }}} */
// add_response_header and apache_response_headers are copied from
// https://github.com/php/php-src/blob/master/sapi/cli/php_cli_server.c
// Copyright (c) The PHP Group
// Licensed under The PHP License
// Original authors: Moriyoshi Koizumi <moriyoshi@php.net> and Xinchen Hui
// <laruence@php.net>
/* add_response_header and apache_response_headers are copied from
* https://github.com/php/php-src/blob/master/sapi/cli/php_cli_server.c
* Copyright (c) The PHP Group
* Licensed under The PHP License
* Original authors: Moriyoshi Koizumi <moriyoshi@php.net> and Xinchen Hui
* <laruence@php.net>
*/
static void add_response_header(sapi_header_struct *h,
zval *return_value) /* {{{ */
{
@@ -329,7 +327,7 @@ PHP_FUNCTION(frankenphp_handle_request) {
frankenphp_server_context *ctx = SG(server_context);
if (ctx->main_request == 0) {
// not a worker, throw an error
/* not a worker, throw an error */
zend_throw_exception(
spl_ce_RuntimeException,
"frankenphp_handle_request() called while not in worker mode", 0);
@@ -347,7 +345,7 @@ PHP_FUNCTION(frankenphp_handle_request) {
}
#ifdef ZEND_MAX_EXECUTION_TIMERS
// Disable timeouts while waiting for a request to handle
/* Disable timeouts while waiting for a request to handle */
zend_unset_timeout();
#endif
@@ -360,9 +358,12 @@ PHP_FUNCTION(frankenphp_handle_request) {
}
#ifdef ZEND_MAX_EXECUTION_TIMERS
// Reset default timeout
// TODO: add support for max_input_time
zend_set_timeout(INI_INT("max_execution_time"), 0);
/*
* Reset default timeout
*/
if (PG(max_input_time) != -1) {
zend_set_timeout(INI_INT("max_execution_time"), 0);
}
#endif
/* Call the PHP func */
@@ -373,8 +374,10 @@ PHP_FUNCTION(frankenphp_handle_request) {
zval_ptr_dtor(&retval);
}
/* If an exception occured, print the message to the client before closing the
* connection */
/*
* If an exception occured, print the message to the client before closing the
* connection
*/
if (EG(exception)) {
zend_exception_error(EG(exception), E_ERROR);
}
@@ -419,28 +422,17 @@ static zend_module_entry frankenphp_module = {
TOSTRING(FRANKENPHP_VERSION),
STANDARD_MODULE_PROPERTIES};
static uintptr_t frankenphp_request_shutdown() {
static void frankenphp_request_shutdown() {
frankenphp_server_context *ctx = SG(server_context);
if (ctx->main_request && ctx->current_request) {
frankenphp_request_reset();
frankenphp_destroy_super_globals();
}
php_request_shutdown((void *)0);
frankenphp_free_request_context();
free(ctx->cookie_data);
((frankenphp_server_context *)SG(server_context))->cookie_data = NULL;
uintptr_t rh = frankenphp_clean_server_context();
free(ctx);
SG(server_context) = NULL;
ctx = NULL;
#if defined(ZTS)
ts_free_thread();
#endif
return rh;
memset(local_ctx, 0, sizeof(frankenphp_server_context));
}
int frankenphp_update_server_context(
@@ -452,21 +444,9 @@ int frankenphp_update_server_context(
frankenphp_server_context *ctx;
if (create) {
#ifdef ZTS
/* initial resource fetch */
(void)ts_resource(0);
#ifdef PHP_WIN32
ZEND_TSRMLS_CACHE_UPDATE();
#endif
#endif
/* todo: use a pool */
ctx = (frankenphp_server_context *)calloc(
1, sizeof(frankenphp_server_context));
if (ctx == NULL) {
return FAILURE;
}
ctx = local_ctx;
ctx->worker_ready = false;
ctx->cookie_data = NULL;
ctx->finished = false;
@@ -475,6 +455,9 @@ int frankenphp_update_server_context(
ctx = (frankenphp_server_context *)SG(server_context);
}
// It is not reset by zend engine, set it to 200.
SG(sapi_headers).http_response_code = 200;
ctx->main_request = main_request;
ctx->current_request = current_request;
@@ -504,7 +487,8 @@ static size_t frankenphp_ub_write(const char *str, size_t str_length) {
frankenphp_server_context *ctx = SG(server_context);
if (ctx->finished) {
// TODO: maybe log a warning that we tried to write to a finished request?
/* TODO: maybe log a warning that we tried to write to a finished request?
*/
return 0;
}
@@ -726,9 +710,54 @@ sapi_module_struct frankenphp_sapi_module = {
STANDARD_SAPI_MODULE_PROPERTIES};
static void *manager_thread(void *arg) {
// SIGPIPE must be masked in non-Go threads:
// https://pkg.go.dev/os/signal#hdr-Go_programs_that_use_cgo_or_SWIG
/* Sets thread name for profiling and debugging.
*
* Adapted from https://github.com/Pithikos/C-Thread-Pool
* Copyright: Johan Hanssen Seferidis
* License: MIT
*/
static void set_thread_name(char *thread_name) {
#if defined(__linux__)
/* Use prctl instead to prevent using _GNU_SOURCE flag and implicit
* declaration */
prctl(PR_SET_NAME, thread_name);
#elif defined(__APPLE__) && defined(__MACH__)
pthread_setname_np(thread_name);
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
pthread_set_name_np(pthread_self(), thread_name);
#endif
}
static void *php_thread(void *arg) {
char thread_name[16] = {0};
snprintf(thread_name, 16, "php-%" PRIxPTR, (uintptr_t)arg);
set_thread_name(thread_name);
#ifdef ZTS
/* initial resource fetch */
(void)ts_resource(0);
#ifdef PHP_WIN32
ZEND_TSRMLS_CACHE_UPDATE();
#endif
#endif
local_ctx = malloc(sizeof(frankenphp_server_context));
while (go_handle_request()) {
}
#ifdef ZTS
ts_free_thread();
#endif
return NULL;
}
static void *php_main(void *arg) {
/*
* SIGPIPE must be masked in non-Go threads:
* https://pkg.go.dev/os/signal#hdr-Go_programs_that_use_cgo_or_SWIG
*/
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGPIPE);
@@ -738,9 +767,9 @@ static void *manager_thread(void *arg) {
exit(EXIT_FAILURE);
}
int num_threads = *((int *)arg);
free(arg);
arg = NULL;
intptr_t num_threads = (intptr_t)arg;
set_thread_name("php-main");
#ifdef ZTS
#if (PHP_VERSION_ID >= 80300)
@@ -761,6 +790,10 @@ static void *manager_thread(void *arg) {
frankenphp_sapi_module.ini_entries = HARDCODED_INI;
#else
frankenphp_sapi_module.ini_entries = malloc(sizeof(HARDCODED_INI));
if (frankenphp_sapi_module.ini_entries == NULL) {
perror("malloc failed");
exit(EXIT_FAILURE);
}
memcpy(frankenphp_sapi_module.ini_entries, HARDCODED_INI,
sizeof(HARDCODED_INI));
#endif
@@ -768,17 +801,30 @@ static void *manager_thread(void *arg) {
frankenphp_sapi_module.startup(&frankenphp_sapi_module);
threadpool thpool = thpool_init(num_threads);
uintptr_t rh;
while ((rh = go_fetch_request())) {
thpool_add_work(thpool, go_execute_script, (void *)rh);
pthread_t *threads = malloc(num_threads * sizeof(pthread_t));
if (threads == NULL) {
perror("malloc failed");
exit(EXIT_FAILURE);
}
/* channel closed, shutdown gracefully */
thpool_wait(thpool);
thpool_destroy(thpool);
for (uintptr_t i = 0; i < num_threads; i++) {
if (pthread_create(&(*(threads + i)), NULL, &php_thread, (void *)i) != 0) {
perror("failed to create PHP thread");
free(threads);
exit(EXIT_FAILURE);
}
}
for (int i = 0; i < num_threads; i++) {
if (pthread_join((*(threads + i)), NULL) != 0) {
perror("failed to join PHP thread");
free(threads);
exit(EXIT_FAILURE);
}
}
free(threads);
/* channel closed, shutdown gracefully */
frankenphp_sapi_module.shutdown(&frankenphp_sapi_module);
sapi_shutdown();
@@ -801,10 +847,7 @@ static void *manager_thread(void *arg) {
int frankenphp_init(int num_threads) {
pthread_t thread;
int *num_threads_ptr = calloc(1, sizeof(int));
*num_threads_ptr = num_threads;
if (pthread_create(&thread, NULL, *manager_thread, (void *)num_threads_ptr) !=
if (pthread_create(&thread, NULL, &php_main, (void *)(intptr_t)num_threads) !=
0) {
go_shutdown();
@@ -819,11 +862,6 @@ int frankenphp_request_startup() {
return SUCCESS;
}
frankenphp_server_context *ctx = SG(server_context);
SG(server_context) = NULL;
free(ctx);
ctx = NULL;
php_request_shutdown((void *)0);
return FAILURE;
@@ -856,23 +894,25 @@ int frankenphp_execute_script(char *file_name) {
zend_destroy_file_handle(&file_handle);
frankenphp_clean_server_context();
frankenphp_free_request_context();
frankenphp_request_shutdown();
return status;
}
// Use global variables to store CLI arguments to prevent useless allocations
/* Use global variables to store CLI arguments to prevent useless allocations */
static char *cli_script;
static int cli_argc;
static char **cli_argv;
// CLI code is adapted from
// https://github.com/php/php-src/blob/master/sapi/cli/php_cli.c Copyright (c)
// The PHP Group Licensed under The PHP License Original uthors: Edin Kadribasic
// <edink@php.net>, Marcus Boerger <helly@php.net> and Johannes Schlueter
// <johannes@php.net> Parts based on CGI SAPI Module by Rasmus Lerdorf, Stig
// Bakken and Zeev Suraski
/*
* CLI code is adapted from
* https://github.com/php/php-src/blob/master/sapi/cli/php_cli.c Copyright (c)
* The PHP Group Licensed under The PHP License Original uthors: Edin Kadribasic
* <edink@php.net>, Marcus Boerger <helly@php.net> and Johannes Schlueter
* <johannes@php.net> Parts based on CGI SAPI Module by Rasmus Lerdorf, Stig
* Bakken and Zeev Suraski
*/
static void cli_register_file_handles(bool no_close) /* {{{ */
{
php_stream *s_in, *s_out, *s_err;
@@ -899,7 +939,7 @@ static void cli_register_file_handles(bool no_close) /* {{{ */
s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE;
}
// s_in_process = s_in;
/*s_in_process = s_in;*/
php_stream_to_zval(s_in, &ic.value);
php_stream_to_zval(s_out, &oc.value);
@@ -924,7 +964,8 @@ static void sapi_cli_register_variables(zval *track_vars_array) /* {{{ */
size_t len;
char *docroot = "";
/* In CGI mode, we consider the environment to be a part of the server
/*
* In CGI mode, we consider the environment to be a part of the server
* variables
*/
php_import_environment_variables(track_vars_array);
@@ -963,7 +1004,9 @@ static void sapi_cli_register_variables(zval *track_vars_array) /* {{{ */
static void *execute_script_cli(void *arg) {
void *exit_status;
// The SAPI name "cli" is hardcoded into too many programs... let's usurp it.
/*
* The SAPI name "cli" is hardcoded into too many programs... let's usurp it.
*/
php_embed_module.name = "cli";
php_embed_module.pretty_name = "PHP CLI embedded in FrankenPHP";
php_embed_module.register_server_variables = sapi_cli_register_variables;
@@ -996,8 +1039,10 @@ int frankenphp_execute_script_cli(char *script, int argc, char **argv) {
cli_argc = argc;
cli_argv = argv;
// Start the script in a dedicated thread to prevent conflicts between Go and
// PHP signal handlers
/*
* Start the script in a dedicated thread to prevent conflicts between Go and
* PHP signal handlers
*/
err = pthread_create(&thread, NULL, execute_script_cli, NULL);
if (err != 0) {
return err;

View File

@@ -5,10 +5,6 @@
// [FrankenPHP app server]: https://frankenphp.dev
package frankenphp
//go:generate rm -Rf C-Thread-Pool/
//go:generate git clone --depth=1 git@github.com:Pithikos/C-Thread-Pool.git
//go:generate rm -Rf C-Thread-Pool/.git C-Thread-Pool/.github C-Thread-Pool/docs C-Thread-Pool/tests C-Thread-Pool/example.c
// Use PHP includes corresponding to your PHP installation by running:
//
// export CGO_CFLAGS=$(php-config --includes)
@@ -17,14 +13,12 @@ package frankenphp
// We also set these flags for hardening: https://github.com/docker-library/php/blob/master/8.2/bookworm/zts/Dockerfile#L57-L59
// #cgo darwin pkg-config: libxml-2.0
// #cgo CFLAGS: -Wall -Werror -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
// #cgo CFLAGS: -Wall -Werror
// #cgo CFLAGS: -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib
// #cgo CFLAGS: -DTHREAD_NAME=frankenphp
// #cgo linux CFLAGS: -D_GNU_SOURCE
// #cgo CPPFLAGS: -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
// #cgo darwin LDFLAGS: -L/opt/homebrew/opt/libiconv/lib -liconv
// #cgo linux LDFLAGS: -Wl,-O1 -lresolv
// #cgo LDFLAGS: -pie -L/usr/local/lib -L/usr/lib -lphp -ldl -lm -lutil
// #cgo linux LDFLAGS: -lresolv
// #cgo LDFLAGS: -L/usr/local/lib -L/usr/lib -lphp -ldl -lm -lutil
// #include <stdlib.h>
// #include <stdint.h>
// #include <php_variables.h>
@@ -49,6 +43,7 @@ import (
"github.com/maypok86/otter"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
// debug on Linux
//_ "github.com/ianlancetaylor/cgosymbolizer"
)
@@ -325,9 +320,13 @@ func Init(options ...Option) error {
return err
}
logger.Info("FrankenPHP started 🐘", zap.String("php_version", Version().Version))
if c := logger.Check(zapcore.InfoLevel, "FrankenPHP started 🐘"); c != nil {
c.Write(zap.String("php_version", Version().Version), zap.Int("num_threads", opt.numThreads))
}
if EmbeddedAppPath != "" {
logger.Info("embedded PHP app 📦", zap.String("path", EmbeddedAppPath))
if c := logger.Check(zapcore.InfoLevel, "embedded PHP app 📦"); c != nil {
c.Write(zap.String("path", EmbeddedAppPath))
}
}
return nil
@@ -468,16 +467,36 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error
return nil
}
//export go_fetch_request
func go_fetch_request() C.uintptr_t {
//export go_handle_request
func go_handle_request() bool {
select {
case <-done:
return 0
return false
case r := <-requestChan:
h := cgo.NewHandle(r)
r.Context().Value(handleKey).(*handleList).AddHandle(h)
return C.uintptr_t(h)
fc, ok := FromContext(r.Context())
if !ok {
panic(InvalidRequestError)
}
defer func() {
maybeCloseContext(fc)
r.Context().Value(handleKey).(*handleList).FreeAll()
}()
if err := updateServerContext(r, true, 0); err != nil {
panic(err)
}
// scriptFilename is freed in frankenphp_execute_script()
fc.exitStatus = C.frankenphp_execute_script(C.CString(fc.scriptFilename))
if fc.exitStatus < 0 {
panic(ScriptExecutionError)
}
return true
}
}
@@ -487,33 +506,6 @@ func maybeCloseContext(fc *FrankenPHPContext) {
})
}
// go_execute_script Note: only called in cgi-mode
//
//export go_execute_script
func go_execute_script(rh unsafe.Pointer) {
handle := cgo.Handle(rh)
request := handle.Value().(*http.Request)
fc, ok := FromContext(request.Context())
if !ok {
panic(InvalidRequestError)
}
defer func() {
maybeCloseContext(fc)
request.Context().Value(handleKey).(*handleList).FreeAll()
}()
if err := updateServerContext(request, true, 0); err != nil {
panic(err)
}
// scriptFilename is freed in frankenphp_execute_script()
fc.exitStatus = C.frankenphp_execute_script(C.CString(fc.scriptFilename))
if fc.exitStatus < 0 {
panic(ScriptExecutionError)
}
}
//export go_ub_write
func go_ub_write(rh C.uintptr_t, cBuf *C.char, length C.int) (C.size_t, C.bool) {
r := cgo.Handle(rh).Value().(*http.Request)
@@ -530,7 +522,9 @@ func go_ub_write(rh C.uintptr_t, cBuf *C.char, length C.int) (C.size_t, C.bool)
i, e := writer.Write(unsafe.Slice((*byte)(unsafe.Pointer(cBuf)), length))
if e != nil {
fc.logger.Error("write error", zap.Error(e))
if c := fc.logger.Check(zapcore.ErrorLevel, "write error"); c != nil {
c.Write(zap.Error(e))
}
}
if fc.responseWriter == nil {
@@ -626,7 +620,7 @@ func go_apache_request_headers(rh, mrh C.uintptr_t) (*C.go_string, C.size_t, C.u
mr := cgo.Handle(mrh).Value().(*http.Request)
mfc := mr.Context().Value(contextKey).(*FrankenPHPContext)
if c := mfc.logger.Check(zap.DebugLevel, "apache_request_headers() called in non-HTTP context"); c != nil {
if c := mfc.logger.Check(zapcore.DebugLevel, "apache_request_headers() called in non-HTTP context"); c != nil {
c.Write(zap.String("worker", mfc.scriptFilename))
}
@@ -675,7 +669,9 @@ func go_apache_request_cleanup(rh C.uintptr_t) {
func addHeader(fc *FrankenPHPContext, cString *C.char, length C.int) {
parts := strings.SplitN(C.GoStringN(cString, length), ": ", 2)
if len(parts) != 2 {
fc.logger.Debug("invalid header", zap.String("header", parts[0]))
if c := fc.logger.Check(zapcore.DebugLevel, "invalid header"); c != nil {
c.Write(zap.String("header", parts[0]))
}
return
}
@@ -720,15 +716,10 @@ func go_sapi_flush(rh C.uintptr_t) bool {
return true
}
if r.ProtoMajor == 1 {
if _, err := r.Body.Read(nil); err != nil {
// Don't flush until the whole body has been read to prevent https://github.com/golang/go/issues/15527
return false
}
}
if err := http.NewResponseController(fc.responseWriter).Flush(); err != nil {
fc.logger.Error("the current responseWriter is not a flusher", zap.Error(err))
if c := fc.logger.Check(zapcore.ErrorLevel, "the current responseWriter is not a flusher"); c != nil {
c.Write(zap.Error(err))
}
}
return false
@@ -762,7 +753,7 @@ func go_read_cookies(rh C.uintptr_t) *C.char {
cookieStrings[i] = cookie.String()
}
// freed in frankenphp_request_shutdown()
// freed in frankenphp_free_request_context()
return C.CString(strings.Join(cookieStrings, "; "))
}
@@ -780,16 +771,24 @@ func go_log(message *C.char, level C.int) {
switch le {
case emerg, alert, crit, err:
l.Error(m, zap.Stringer("syslog_level", syslogLevel(level)))
if c := l.Check(zapcore.ErrorLevel, m); c != nil {
c.Write(zap.Stringer("syslog_level", syslogLevel(level)))
}
case warning:
l.Warn(m, zap.Stringer("syslog_level", syslogLevel(level)))
if c := l.Check(zapcore.WarnLevel, m); c != nil {
c.Write(zap.Stringer("syslog_level", syslogLevel(level)))
}
case debug:
l.Debug(m, zap.Stringer("syslog_level", syslogLevel(level)))
if c := l.Check(zapcore.DebugLevel, m); c != nil {
c.Write(zap.Stringer("syslog_level", syslogLevel(level)))
}
default:
l.Info(m, zap.Stringer("syslog_level", syslogLevel(level)))
if c := l.Check(zapcore.InfoLevel, m); c != nil {
c.Write(zap.Stringer("syslog_level", syslogLevel(level)))
}
}
}

View File

@@ -21,7 +21,7 @@ function frankenphp_request_headers(): array {}
function apache_request_headers(): array {}
/**
* @alias frankenphp_response_headers
* @alias frankenphp_request_headers
*/
function getallheaders(): array {}

View File

@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 467f1406e17d3b8ca67bba5ea367194e60d8dd27 */
* Stub hash: 05ebde17137c559e891362fba6524fad1e0a2dfe */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_frankenphp_handle_request, 0, 1,
_IS_BOOL, 0)
@@ -47,7 +47,7 @@ static const zend_function_entry ext_functions[] = {
ZEND_FALIAS(apache_request_headers,
frankenphp_request_headers,
arginfo_apache_request_headers)
ZEND_FALIAS(getallheaders, frankenphp_response_headers,
ZEND_FALIAS(getallheaders, frankenphp_request_headers,
arginfo_getallheaders)
ZEND_FE(frankenphp_response_headers,
arginfo_frankenphp_response_headers)

View File

@@ -5,10 +5,12 @@
package frankenphp_test
import (
"bytes"
"context"
"fmt"
"io"
"log"
"mime/multipart"
"net/http"
"net/http/cookiejar"
"net/http/httptest"
@@ -26,6 +28,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"go.uber.org/zap/zaptest"
"go.uber.org/zap/zaptest/observer"
)
@@ -244,6 +247,12 @@ func testResponseHeaders(t *testing.T, opts *testOptions) {
resp := w.Result()
body, _ := io.ReadAll(resp.Body)
if i%3 != 0 {
assert.Equal(t, i+100, resp.StatusCode)
} else {
assert.Equal(t, 200, resp.StatusCode)
}
assert.Contains(t, string(body), "'X-Powered-By' => 'PH")
assert.Contains(t, string(body), "'Foo' => 'bar',")
assert.Contains(t, string(body), "'Foo2' => 'bar2',")
@@ -402,7 +411,7 @@ func TestLog_worker(t *testing.T) {
testLog(t, &testOptions{workerScript: "log.php"})
}
func testLog(t *testing.T, opts *testOptions) {
logger, logs := observer.New(zap.InfoLevel)
logger, logs := observer.New(zapcore.InfoLevel)
opts.logger = zap.New(logger)
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
@@ -422,7 +431,7 @@ func TestConnectionAbort_worker(t *testing.T) {
func testConnectionAbort(t *testing.T, opts *testOptions) {
testFinish := func(finish string) {
t.Run(fmt.Sprintf("finish=%s", finish), func(t *testing.T) {
logger, logs := observer.New(zap.InfoLevel)
logger, logs := observer.New(zapcore.InfoLevel)
opts.logger = zap.New(logger)
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
@@ -600,6 +609,33 @@ func testRequestHeaders(t *testing.T, opts *testOptions) {
}, opts)
}
func TestFileUpload_module(t *testing.T) { testFileUpload(t, &testOptions{}) }
func TestFileUpload_worker(t *testing.T) {
testFileUpload(t, &testOptions{workerScript: "file-upload.php"})
}
func testFileUpload(t *testing.T, opts *testOptions) {
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
requestBody := &bytes.Buffer{}
writer := multipart.NewWriter(requestBody)
part, _ := writer.CreateFormFile("file", "foo.txt")
_, err := part.Write([]byte("bar"))
require.NoError(t, err)
writer.Close()
req := httptest.NewRequest("POST", "http://example.com/file-upload.php", requestBody)
req.Header.Add("Content-Type", writer.FormDataContentType())
w := httptest.NewRecorder()
handler(w, req)
resp := w.Result()
body, _ := io.ReadAll(resp.Body)
assert.Contains(t, string(body), "Upload OK")
}, opts)
}
func TestExecuteScriptCLI(t *testing.T) {
if _, err := os.Stat("internal/testcli/testcli"); err != nil {
t.Skip("internal/testcli/testcli has not been compiled, run `cd internal/testcli/ && go build`")

6
go.mod
View File

@@ -7,10 +7,10 @@ toolchain go1.22.0
retract v1.0.0-rc.1 // Human error
require (
github.com/maypok86/otter v1.2.0
github.com/maypok86/otter v1.2.2
github.com/stretchr/testify v1.9.0
go.uber.org/zap v1.27.0
golang.org/x/net v0.22.0
golang.org/x/net v0.27.0
)
require (
@@ -21,7 +21,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/text v0.16.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

12
go.sum
View File

@@ -12,8 +12,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/maypok86/otter v1.2.0 h1:djwBBNpp9+dyzBTY0zscIG+pyAQVXRRRMbzztf8iJ4U=
github.com/maypok86/otter v1.2.0/go.mod h1:mKLfoI7v1HOmQMwFgX4QkRk23mX6ge3RDvjdHOWG4R4=
github.com/maypok86/otter v1.2.2 h1:jJi0y8ruR/ZcKmJ4FbQj3QQTqKwV+LNrSOo2S1zbF5M=
github.com/maypok86/otter v1.2.2/go.mod h1:mKLfoI7v1HOmQMwFgX4QkRk23mX6ge3RDvjdHOWG4R4=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -28,10 +28,10 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@@ -9,25 +9,25 @@ set -o errtrace
set -o pipefail
set -o xtrace
if ! type "git" > /dev/null; then
echo "The \"git\" command must be installed."
exit 1
if ! type "git" >/dev/null; then
echo "The \"git\" command must be installed."
exit 1
fi
if ! type "gh" > /dev/null; then
echo "The \"gh\" command must be installed."
exit 1
if ! type "gh" >/dev/null; then
echo "The \"gh\" command must be installed."
exit 1
fi
if [[ $# -ne 1 ]]; then
echo "Usage: ./release.sh version" >&2
exit 1
echo "Usage: ./release.sh version" >&2
exit 1
fi
# Adapted from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
if [[ ! $1 =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\+([0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*))?$ ]]; then
echo "Invalid version number: $1" >&2
exit 1
echo "Invalid version number: $1" >&2
exit 1
fi
git checkout main
@@ -44,6 +44,6 @@ git tag -s -m "Version $1" "caddy/v$1"
git push --follow-tags
tags=$(git tag --list --sort=-version:refname 'v*')
previous_tag=$(awk 'NR==2 {print;exit}' <<< "${tags}")
previous_tag=$(awk 'NR==2 {print;exit}' <<<"${tags}")
gh release create --draft --generate-notes --latest --notes-start-tag "${previous_tag}" --verify-tag "v$1"

View File

@@ -1,4 +1,4 @@
#!/bin/bash
for ((i = 0 ; i < 100 ; i++)); do
curl --no-progress-meter -o /dev/null http://localhost:2019/config/apps/frankenphp -: --no-progress-meter -o /dev/null -H 'Cache-Control: must-revalidate' -H 'Content-Type: application/json' --data-binary '{"workers":[{"file_name":"./index.php"}]}' -X PATCH http://localhost:2019/config/apps/frankenphp
for ((i = 0; i < 100; i++)); do
curl --no-progress-meter -o /dev/null http://localhost:2019/config/apps/frankenphp -: --no-progress-meter -o /dev/null -H 'Cache-Control: must-revalidate' -H 'Content-Type: application/json' --data-binary '{"workers":[{"file_name":"./index.php"}]}' -X PATCH http://localhost:2019/config/apps/frankenphp
done

View File

@@ -36,6 +36,16 @@ func WithRequestDocumentRoot(documentRoot string, resolveSymlink bool) RequestOp
}
}
// WithRequestResolvedDocumentRoot is similar to WithRequestDocumentRoot
// but doesn't does any checks or resolving on the path to improve performance.
func WithRequestResolvedDocumentRoot(documentRoot string) RequestOption {
return func(o *FrankenPHPContext) error {
o.documentRoot = documentRoot
return nil
}
}
// The path in the URL will be split into two, with the first piece ending
// with the value of SplitPath. The first piece will be assumed as the
// actual resource (CGI script) name, and the second piece will be set to

View File

@@ -1,13 +1,24 @@
# syntax=docker/dockerfile:1
#checkov:skip=CKV_DOCKER_2
#checkov:skip=CKV_DOCKER_3
#checkov:skip=CKV_DOCKER_7
FROM golang-base
ARG TARGETARCH
ARG FRANKENPHP_VERSION=''
ENV FRANKENPHP_VERSION=${FRANKENPHP_VERSION}
ARG PHP_VERSION=''
ENV PHP_VERSION=${PHP_VERSION}
ARG PHP_EXTENSIONS=''
ARG PHP_EXTENSION_LIBS=''
ARG CLEAN=''
ARG EMBED=''
ARG DEBUG_SYMBOLS=''
ARG MIMALLOC=''
ARG NO_COMPRESS=''
SHELL ["/bin/ash", "-eo", "pipefail", "-c"]
@@ -20,6 +31,7 @@ LABEL org.opencontainers.image.vendor="Kévin Dunglas"
RUN apk update; \
apk add --no-cache \
alpine-sdk \
autoconf \
automake \
bash \
@@ -27,7 +39,6 @@ RUN apk update; \
bison \
build-base \
cmake \
composer \
curl \
file \
flex \
@@ -62,8 +73,24 @@ RUN apk update; \
xz ; \
ln -sf /usr/bin/php83 /usr/bin/php
# FIXME: temporary workaround for https://github.com/golang/go/issues/68285
WORKDIR /
RUN git clone https://go.googlesource.com/go goroot
WORKDIR /goroot
# Revert https://github.com/golang/go/commit/3560cf0afb3c29300a6c88ccd98256949ca7a6f6 to prevent the crash with musl
RUN git config --global user.email "build@example.com" && \
git config --global user.name "Build" && \
git checkout "$(go env GOVERSION)" && \
git revert 3560cf0afb3c29300a6c88ccd98256949ca7a6f6
WORKDIR /goroot/src
ENV GOHOSTARCH="$TARGETARCH"
RUN ./make.bash
ENV PATH="/goroot/bin:$PATH"
RUN go version
# https://getcomposer.org/doc/03-cli.md#composer-allow-superuser
ENV COMPOSER_ALLOW_SUPERUSER=1
COPY --from=composer/composer:2-bin /composer /usr/bin/composer
WORKDIR /go/src/app
COPY go.mod go.sum ./
@@ -76,6 +103,6 @@ RUN go mod graph | awk '{if ($1 !~ "@") print $2}' | xargs go get
WORKDIR /go/src/app
COPY *.* ./
COPY caddy caddy
COPY C-Thread-Pool C-Thread-Pool
RUN --mount=type=secret,id=github-token GITHUB_TOKEN=$(cat /run/secrets/github-token) ./build-static.sh
RUN --mount=type=secret,id=github-token GITHUB_TOKEN=$(cat /run/secrets/github-token) ./build-static.sh && \
rm -Rf dist/static-php-cli/source/*

View File

@@ -1,7 +1,7 @@
<?php
$fn = require $_SERVER['SCRIPT_FILENAME'];
if (!isset($_SERVER['FRANKENPHP_WORKER'])) {
if ('1' !== ($_SERVER['FRANKENPHP_WORKER'] ?? null)) {
$fn();
exit(0);
}

View File

@@ -7,6 +7,9 @@ http:// {
root * .
encode zstd br gzip
php_server
php_server {
file_server off
resolve_root_symlink false
}
}
}

18
testdata/file-upload.php vendored Normal file
View File

@@ -0,0 +1,18 @@
<?php
require_once __DIR__.'/_executor.php';
return function()
{
$uploaded = ($_FILES['file']['tmp_name'] ?? null) ? file_get_contents($_FILES['file']['tmp_name']) : null;
if ($uploaded) {
echo 'Upload OK';
return;
}
echo <<<'HTML'
<form method="POST" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit">
</form>
HTML;
};

View File

@@ -7,7 +7,9 @@ return function () {
header('Foo2: bar2');
header('Invalid');
header('I: ' . ($_GET['i'] ?? 'i not set'));
http_response_code(201);
if ($_GET['i'] % 3) {
http_response_code($_GET['i'] + 100);
}
var_export(apache_response_headers());
};

19
testdata/worker-getopt.php vendored Normal file
View File

@@ -0,0 +1,19 @@
<?php
do {
$ok = frankenphp_handle_request(function (): void {
print_r($_SERVER);
});
getopt('abc');
if (!isset($_SERVER['HTTP_REQUEST'])) {
exit(1);
}
if (isset($_SERVER['FRANKENPHP_WORKER'])) {
exit(2);
}
if (isset($_SERVER['FOO'])) {
exit(3);
}
} while ($ok);

View File

@@ -12,6 +12,7 @@ import (
"sync"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var (
@@ -53,7 +54,7 @@ func startWorkers(fileName string, nbWorkers int, env PreparedEnv) error {
env = make(PreparedEnv, 1)
}
env["FRANKENPHP_WORKER\x00"] = "1\x00"
env["FRANKENPHP_WORKER\x00"] = "1"
l := getLogger()
for i := 0; i < nbWorkers; i++ {
@@ -74,7 +75,10 @@ func startWorkers(fileName string, nbWorkers int, env PreparedEnv) error {
panic(err)
}
l.Debug("starting", zap.String("worker", absFileName))
if c := l.Check(zapcore.DebugLevel, "starting"); c != nil {
c.Write(zap.String("worker", absFileName), zap.Int("num", nbWorkers))
}
if err := ServeHTTP(nil, r); err != nil {
panic(err)
}
@@ -91,9 +95,13 @@ func startWorkers(fileName string, nbWorkers int, env PreparedEnv) error {
if _, ok := workersRequestChans.Load(absFileName); ok {
workersReadyWG.Add(1)
if fc.exitStatus == 0 {
l.Info("restarting", zap.String("worker", absFileName))
if c := l.Check(zapcore.InfoLevel, "restarting"); c != nil {
c.Write(zap.String("worker", absFileName))
}
} else {
l.Error("unexpected termination, restarting", zap.String("worker", absFileName), zap.Int("exit_status", int(fc.exitStatus)))
if c := l.Check(zapcore.ErrorLevel, "unexpected termination, restarting"); c != nil {
c.Write(zap.String("worker", absFileName), zap.Int("exit_status", int(fc.exitStatus)))
}
}
} else {
break
@@ -101,7 +109,9 @@ func startWorkers(fileName string, nbWorkers int, env PreparedEnv) error {
}
// TODO: check if the termination is expected
l.Debug("terminated", zap.String("worker", absFileName))
if c := l.Check(zapcore.DebugLevel, "terminated"); c != nil {
c.Write(zap.String("worker", absFileName))
}
}()
}
@@ -141,15 +151,18 @@ func go_frankenphp_worker_handle_request_start(mrh C.uintptr_t) C.uintptr_t {
}
rc := v.(chan *http.Request)
l := getLogger()
l.Debug("waiting for request", zap.String("worker", fc.scriptFilename))
if c := l.Check(zapcore.DebugLevel, "waiting for request"); c != nil {
c.Write(zap.String("worker", fc.scriptFilename))
}
var r *http.Request
select {
case <-done:
l.Debug("shutting down", zap.String("worker", fc.scriptFilename))
if c := l.Check(zapcore.DebugLevel, "shutting down"); c != nil {
c.Write(zap.String("worker", fc.scriptFilename))
}
return 0
case r = <-rc:
@@ -158,10 +171,15 @@ func go_frankenphp_worker_handle_request_start(mrh C.uintptr_t) C.uintptr_t {
fc.currentWorkerRequest = cgo.NewHandle(r)
r.Context().Value(handleKey).(*handleList).AddHandle(fc.currentWorkerRequest)
l.Debug("request handling started", zap.String("worker", fc.scriptFilename), zap.String("url", r.RequestURI))
if c := l.Check(zapcore.DebugLevel, "request handling started"); c != nil {
c.Write(zap.String("worker", fc.scriptFilename), zap.String("url", r.RequestURI))
}
if err := updateServerContext(r, false, mrh); err != nil {
// Unexpected error
l.Debug("unexpected error", zap.String("worker", fc.scriptFilename), zap.String("url", r.RequestURI), zap.Error(err))
if c := l.Check(zapcore.DebugLevel, "unexpected error"); c != nil {
c.Write(zap.String("worker", fc.scriptFilename), zap.String("url", r.RequestURI), zap.Error(err))
}
return 0
}
@@ -182,12 +200,14 @@ func go_frankenphp_finish_request(mrh, rh C.uintptr_t, deleteHandle bool) {
maybeCloseContext(fc)
var fields []zap.Field
if mrh == 0 {
fields = append(fields, zap.String("worker", fc.scriptFilename), zap.String("url", r.RequestURI))
} else {
fields = append(fields, zap.String("url", r.RequestURI))
}
if c := fc.logger.Check(zapcore.DebugLevel, "request handling finished"); c != nil {
var fields []zap.Field
if mrh == 0 {
fields = append(fields, zap.String("worker", fc.scriptFilename), zap.String("url", r.RequestURI))
} else {
fields = append(fields, zap.String("url", r.RequestURI))
}
fc.logger.Debug("request handling finished", fields...)
c.Write(fields...)
}
}

View File

@@ -7,11 +7,15 @@ import (
"net/http"
"net/http/httptest"
"net/url"
"strconv"
"strings"
"testing"
"github.com/dunglas/frankenphp"
"github.com/stretchr/testify/assert"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"go.uber.org/zap/zaptest/observer"
)
func TestWorker(t *testing.T) {
@@ -77,7 +81,7 @@ func TestCannotCallHandleRequestInNonWorkerMode(t *testing.T) {
func TestWorkerEnv(t *testing.T) {
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/env.php?i=%d", i), nil)
req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/worker-env.php?i=%d", i), nil)
w := httptest.NewRecorder()
handler(w, req)
@@ -85,7 +89,30 @@ func TestWorkerEnv(t *testing.T) {
body, _ := io.ReadAll(resp.Body)
assert.Equal(t, fmt.Sprintf("bar%d", i), string(body))
}, &testOptions{workerScript: "env.php", nbWorkers: 1, env: map[string]string{"FOO": "bar"}, nbParrallelRequests: 10})
}, &testOptions{workerScript: "worker-env.php", nbWorkers: 1, env: map[string]string{"FOO": "bar"}, nbParrallelRequests: 10})
}
func TestWorkerGetOpt(t *testing.T) {
observer, logs := observer.New(zapcore.InfoLevel)
logger := zap.New(observer)
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/worker-getopt.php?i=%d", i), nil)
req.Header.Add("Request", strconv.Itoa(i))
w := httptest.NewRecorder()
handler(w, req)
resp := w.Result()
body, _ := io.ReadAll(resp.Body)
assert.Contains(t, string(body), fmt.Sprintf("[HTTP_REQUEST] => %d", i))
assert.Contains(t, string(body), fmt.Sprintf("[REQUEST_URI] => /worker-getopt.php?i=%d", i))
}, &testOptions{logger: logger, workerScript: "worker-getopt.php", env: map[string]string{"FOO": "bar"}})
for _, log := range logs.FilterFieldKey("exit_status").All() {
assert.Failf(t, "unexpected exit status", "exit status: %d", log.ContextMap()["exit_status"])
}
}
func ExampleServeHTTP_workers() {