Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions .github/scripts/windows/find-target-branch.bat
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
@echo off

for /f "usebackq tokens=3" %%i in (`findstr PHP_MAJOR_VERSION main\php_version.h`) do set BRANCH=%%i
for /f "usebackq tokens=3" %%i in (`findstr PHP_MINOR_VERSION main\php_version.h`) do set BRANCH=%BRANCH%.%%i

if /i "%BRANCH%" equ "8.5" (
set BRANCH=master
)
rem Pin the PHP SDK dependency series to 8.5 (vs17).
rem
rem We build php-src's dev tip (true-async == 8.6-dev) on the windows-2022
rem runner, i.e. the vs17 / VS 2022 toolchain. php.net's deps server only
rem publishes the bleeding edge (branches "8.6" and "master") for the vs18 /
rem VS 2026 toolchain -- there is no vs17 build of those. The newest series
rem that ships vs17 dependencies is 8.5, and those libs (openssl, libxml2,
rem ...) build the 8.6 tip fine: the series tracks the toolchain, not the PHP
rem minor. Asking for "8.6"/"master" under --crt vs17 fails with
rem "CRT 'vs17' doesn't match any available for branch ...".
rem
rem Bump this to 8.6 once php.net publishes packages-8.6-vs17-*, or switch the
rem runner+PHP_BUILD_CRT to vs18 to follow the dev-tip deps directly.
rem (Old logic derived "8.<minor>" and remapped a hardcoded 8.5 -> master;
rem it broke when php-src went 8.6 and the dev deps moved to vs18.)
set BRANCH=8.5
3 changes: 2 additions & 1 deletion tests/phpt/server/compression/010-h1-buffered-gzip.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ true_async
--SKIPIF--
<?php
if (!class_exists('TrueAsync\HttpServerConfig')) die('skip http_server not loaded');
if (trim((string)shell_exec('command -v gunzip')) === '') die('skip gunzip(1) not in PATH');
if (PHP_OS_FAMILY === 'Windows') die('skip requires a POSIX gzip/gunzip CLI for the proc_open round-trip');
if (trim((string)shell_exec('command -v gunzip 2>/dev/null')) === '') die('skip gunzip(1) not in PATH');
?>
--FILE--
<?php
Expand Down
3 changes: 2 additions & 1 deletion tests/phpt/server/compression/012-h1-streaming-gzip.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ true_async
--SKIPIF--
<?php
if (!class_exists('TrueAsync\HttpServerConfig')) die('skip http_server not loaded');
if (trim((string)shell_exec('command -v gunzip')) === '') die('skip gunzip(1) not in PATH');
if (PHP_OS_FAMILY === 'Windows') die('skip requires a POSIX gzip/gunzip CLI for the proc_open round-trip');
if (trim((string)shell_exec('command -v gunzip 2>/dev/null')) === '') die('skip gunzip(1) not in PATH');
?>
--FILE--
<?php
Expand Down
3 changes: 2 additions & 1 deletion tests/phpt/server/compression/030-h1-request-gzip-in.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ true_async
--SKIPIF--
<?php
if (!class_exists('TrueAsync\HttpServerConfig')) die('skip http_server not loaded');
if (trim((string)shell_exec('command -v gzip')) === '') die('skip gzip(1) not in PATH');
if (PHP_OS_FAMILY === 'Windows') die('skip requires a POSIX gzip/gunzip CLI for the proc_open round-trip');
if (trim((string)shell_exec('command -v gzip 2>/dev/null')) === '') die('skip gzip(1) not in PATH');
?>
--FILE--
<?php
Expand Down
3 changes: 2 additions & 1 deletion tests/phpt/server/compression/070-encoder-pool-reuse.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ true_async
--SKIPIF--
<?php
if (!class_exists('TrueAsync\HttpServerConfig')) die('skip http_server not loaded');
if (trim((string)shell_exec('command -v gunzip')) === '') die('skip gunzip(1) not in PATH');
if (PHP_OS_FAMILY === 'Windows') die('skip requires a POSIX gzip/gunzip CLI for the proc_open round-trip');
if (trim((string)shell_exec('command -v gunzip 2>/dev/null')) === '') die('skip gunzip(1) not in PATH');
?>
--FILE--
<?php
Expand Down
50 changes: 50 additions & 0 deletions tests/phpt/server/static/016-static-handler-validation-posix.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
--TEST--
StaticHandler: POSIX-only root-path validation (filesystem-root semantics)
--EXTENSIONS--
true_async_server
--SKIPIF--
<?php
if (PHP_OS_FAMILY === 'Windows') {
die("skip POSIX-only: '/'-rooted filesystem semantics; on Windows "
. "IS_ABSOLUTE_PATH requires a drive letter, so these inputs fail "
. "earlier with \"must be an absolute path\" — covered by 016 with "
. "OS-appropriate inputs");
}
?>
--FILE--
<?php
/* POSIX-only companion to 016-static-handler-validation. These assert
* root semantics that only exist on *nix:
* - a bare "/" is absolute, exists and is a directory, so it reaches
* the explicit "must not be '/'" guard (last check, on the resolved
* path);
* - a leading-slash path is absolute, so a missing one passes the
* absolute-path gate and fails at the existence check.
* On Windows both inputs are non-absolute (no drive letter) and fail at
* the absolute-path gate instead — see 016 for the cross-platform arms. */

use TrueAsync\StaticHandler;

function check(string $label, callable $fn): void
{
try {
$fn();
echo "$label: OK\n";
} catch (\Throwable $e) {
echo "$label: ", $e::class, ": ", $e->getMessage(), "\n";
}
}

/* "/" resolves to the filesystem root → explicit guard. */
check('ctor:root-slash', fn() => new StaticHandler('/x/', '/'));

/* Leading slash is absolute on POSIX → a missing one reaches not-found
* (proving it cleared the absolute-path gate, unlike on Windows). */
check('ctor:root-missing-abs', fn() => new StaticHandler('/x/', '/nonexistent-' . bin2hex(random_bytes(8))));

echo "done\n";
?>
--EXPECTF--
ctor:root-slash: TrueAsync\HttpServerInvalidArgumentException: StaticHandler root directory must not be '/'
ctor:root-missing-abs: TrueAsync\HttpServerInvalidArgumentException: StaticHandler root directory not found: %s
done
15 changes: 11 additions & 4 deletions tests/phpt/server/static/016-static-handler-validation.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,23 @@ check('ctor:prefix-double-slash', fn() => new StaticHandler('/a//b/', $root));
check('ctor:prefix-too-short', fn() => new StaticHandler('/', $root)); // len < 2

/* ---- Constructor: root-directory validation -------------------- */
/* Cross-platform: feed an absolute-but-missing path under the system
* temp dir so it clears the absolute-path gate and hits the not-found
* branch on every OS (a bare "/..." path is NOT absolute on Windows).
* The POSIX-only root cases ("/" itself) live in 016-...-posix. */
$absent_root = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'sh-absent-' . bin2hex(random_bytes(8));
check('ctor:root-empty', fn() => new StaticHandler('/x/', ''));
check('ctor:root-relative', fn() => new StaticHandler('/x/', 'relative'));
check('ctor:root-missing', fn() => new StaticHandler('/x/', '/nonexistent-' . bin2hex(random_bytes(8))));
check('ctor:root-missing', fn() => new StaticHandler('/x/', $absent_root));
check('ctor:root-not-a-dir', fn() => new StaticHandler('/x/', __FILE__));
check('ctor:root-slash', fn() => new StaticHandler('/x/', '/'));

/* ---- Happy path ------------------------------------------------ */
$sh = new StaticHandler('/static/', $root);
echo "happy-path: prefix=", $sh->getUrlPrefix(), " root-ok=", str_starts_with($sh->getRootDirectory(), '/') ? 'yes' : 'no', "\n";
$gr = $sh->getRootDirectory();
/* "absolute for this OS": leading slash on *nix, drive-letter / UNC on Windows. */
$root_abs = $gr !== '' && (str_starts_with($gr, '/') || str_starts_with($gr, '\\')
|| (strlen($gr) >= 2 && ctype_alpha($gr[0]) && $gr[1] === ':'));
echo "happy-path: prefix=", $sh->getUrlPrefix(), " root-ok=", $root_abs ? 'yes' : 'no', "\n";
echo "isLocked: ", $sh->isLocked() ? 'yes' : 'no', "\n";

/* ---- setIndexFiles: validation arms --------------------------- */
Expand Down Expand Up @@ -136,7 +144,6 @@ ctor:root-empty: TrueAsync\HttpServerInvalidArgumentException: StaticHandler roo
ctor:root-relative: TrueAsync\HttpServerInvalidArgumentException: StaticHandler root directory must be an absolute path
ctor:root-missing: TrueAsync\HttpServerInvalidArgumentException: StaticHandler root directory not found: %s
ctor:root-not-a-dir: TrueAsync\HttpServerInvalidArgumentException: StaticHandler root directory is not a directory: %s
ctor:root-slash: TrueAsync\HttpServerInvalidArgumentException: StaticHandler root directory must not be '/'
happy-path: prefix=/static/ root-ok=yes
isLocked: no
idx:non-string: TrueAsync\HttpServerInvalidArgumentException: StaticHandler index files must be strings
Expand Down
Loading