-
-
Notifications
You must be signed in to change notification settings - Fork 8
Added GlobalState #28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d7da623
a65e90d
bd6ad41
06729f9
740c24a
4452b37
8cdf0b5
6ac9a9c
3ececb8
b439591
a734671
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Spiral\RoadRunner\Http; | ||
|
|
||
| use function time; | ||
| use function microtime; | ||
| use function strtoupper; | ||
| use function str_replace; | ||
| use function implode; | ||
|
|
||
| final class GlobalState | ||
| { | ||
| /** | ||
| * @var array<array-key, mixed> Cached state of the $_SERVER superglobal. | ||
| */ | ||
| private static array $cachedServer = []; | ||
|
|
||
| /** | ||
| * Cache superglobal $_SERVER to avoid state leaks between requests. | ||
| */ | ||
| public static function cacheServerVars(): void | ||
| { | ||
| self::$cachedServer = $_SERVER; | ||
| } | ||
|
|
||
| /** | ||
| * Enrich cached $_SERVER with data from the request. | ||
| * | ||
| * @return non-empty-array<array-key, mixed> Cached $_SERVER data enriched with request data. | ||
| */ | ||
| public static function enrichServerVars(Request $request): array | ||
| { | ||
| $server = self::$cachedServer; | ||
|
|
||
| $server['REQUEST_URI'] = $request->uri; | ||
| $server['REQUEST_TIME'] = time(); | ||
| $server['REQUEST_TIME_FLOAT'] = microtime(true); | ||
| $server['REMOTE_ADDR'] = $request->getRemoteAddr(); | ||
| $server['REQUEST_METHOD'] = $request->method; | ||
| $server['HTTP_USER_AGENT'] = ''; | ||
|
|
||
| foreach ($request->headers as $key => $value) { | ||
| $key = strtoupper(str_replace('-', '_', $key)); | ||
|
|
||
| if ($key == 'CONTENT_TYPE' || $key == 'CONTENT_LENGTH') { | ||
| $server[$key] = implode(', ', $value); | ||
|
|
||
| continue; | ||
| } | ||
|
|
||
| $server['HTTP_' . $key] = implode(', ', $value); | ||
| } | ||
|
|
||
| return $server; | ||
| } | ||
| } | ||
|
|
||
| GlobalState::cacheServerVars(); |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,27 +5,89 @@ | |||||||||
| namespace Spiral\RoadRunner\Tests\Http\Unit; | ||||||||||
|
|
||||||||||
| use Nyholm\Psr7\Factory\Psr17Factory; | ||||||||||
| use PHPUnit\Framework\Attributes\CoversClass; | ||||||||||
| use PHPUnit\Framework\Attributes\RunClassInSeparateProcess; | ||||||||||
| use PHPUnit\Framework\TestCase; | ||||||||||
| use Spiral\RoadRunner\Http\HttpWorker; | ||||||||||
| use Spiral\Goridge\Frame; | ||||||||||
| use Spiral\RoadRunner\Http\GlobalState; | ||||||||||
| use Spiral\RoadRunner\Http\PSR7Worker; | ||||||||||
| use Spiral\RoadRunner\Tests\Http\Unit\Stub\TestRelay; | ||||||||||
| use Spiral\RoadRunner\Worker; | ||||||||||
|
|
||||||||||
|
|
||||||||||
| #[CoversClass(PSR7Worker::class)] | ||||||||||
| #[CoversClass(GlobalState::class)] | ||||||||||
| #[RunClassInSeparateProcess] | ||||||||||
| final class PSR7WorkerTest extends TestCase | ||||||||||
| { | ||||||||||
| public function testHttpWorkerIsAvailable(): void | ||||||||||
| public function testStateServerLeak(): void | ||||||||||
| { | ||||||||||
| $psrFactory = new Psr17Factory(); | ||||||||||
|
|
||||||||||
| $psrWorker = new PSR7Worker( | ||||||||||
| Worker::create(), | ||||||||||
| $relay = new TestRelay(); | ||||||||||
| $psrWorker = new PSR7Worker( | ||||||||||
| new Worker($relay), | ||||||||||
| $psrFactory, | ||||||||||
| $psrFactory, | ||||||||||
| $psrFactory, | ||||||||||
| ); | ||||||||||
|
|
||||||||||
| self::assertInstanceOf(HttpWorker::class, $psrWorker->getHttpWorker()); | ||||||||||
| //dataProvider is always random and we need to keep the order | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainClarify the comment about DataProviders order PHPUnit preserves the order of items provided by a data provider (unless a randomizer plugin is in use). If order is important, it’s fine to keep inline fixtures; otherwise consider a data provider for better test reporting. Would you like to switch to a data provider? If you want to confirm ordering guarantees, run this web query: 🌐 Web query: 💡 Result: PHPUnit does not explicitly guarantee the iteration order of items returned by a data provider. However, in practice, the data provider method returns an array or an iterable, and PHPUnit runs the test with each dataset in the order they are returned from the data provider. Since the data provider returns a PHP array or iterable, and PHP arrays preserve insertion order (since PHP 5.4), PHPUnit will run the tests in the order the items are provided by the data provider. So while not explicitly documented as a guarantee by PHPUnit, in typical usage and by PHP's own behavior regarding arrays, the iteration order of data provider items can be considered stable and predictable. If you rely on a specific order, it's a good practice to:
If you want to be absolutely certain about order, it is best to check against the PHPUnit documentation or source code to ensure no changes in future versions. Would you like me to check for any recent documentation or discussions on this topic? Update misleading comment about DataProvider ordering The inline comment in tests/Unit/PSR7WorkerTest.php (line 33) is incorrect: PHPUnit runs data‐provider datasets in the order they’re returned (PHP arrays preserve insertion order). To improve clarity and test reporting, either adjust the comment or extract these cases into a named data provider. Locations to update:
Suggested diff: - //dataProvider is always random and we need to keep the order
+ // PHPUnit executes dataProvider items in the order they’re returned
+ // (PHP arrays preserve insertion order). Consider using a named data provider
+ // for clearer test reporting.📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| $fixtures = [ | ||||||||||
| [ | ||||||||||
| [ | ||||||||||
| 'Content-Type' => ['application/html'], | ||||||||||
| 'Connection' => ['keep-alive'] | ||||||||||
| ], | ||||||||||
| [ | ||||||||||
| 'REQUEST_URI' => 'http://localhost', | ||||||||||
| 'REMOTE_ADDR' => '127.0.0.1', | ||||||||||
| 'REQUEST_METHOD' => 'GET', | ||||||||||
| 'HTTP_USER_AGENT' => '', | ||||||||||
| 'CONTENT_TYPE' => 'application/html', | ||||||||||
| 'HTTP_CONNECTION' => 'keep-alive', | ||||||||||
| ], | ||||||||||
| ], | ||||||||||
| [ | ||||||||||
| [ | ||||||||||
| 'Content-Type' => ['application/json'] | ||||||||||
| ], | ||||||||||
| [ | ||||||||||
| 'REQUEST_URI' => 'http://localhost', | ||||||||||
| 'REMOTE_ADDR' => '127.0.0.1', | ||||||||||
| 'REQUEST_METHOD' => 'GET', | ||||||||||
| 'HTTP_USER_AGENT' => '', | ||||||||||
| 'CONTENT_TYPE' => 'application/json' | ||||||||||
| ], | ||||||||||
| ], | ||||||||||
| ]; | ||||||||||
|
|
||||||||||
| $_SERVER = []; | ||||||||||
| foreach ($fixtures as [$headers, $expectedServer]) { | ||||||||||
| $body = [ | ||||||||||
| 'headers' => $headers, | ||||||||||
| 'rawQuery' => '', | ||||||||||
| 'remoteAddr' => '127.0.0.1', | ||||||||||
| 'protocol' => 'HTTP/1.1', | ||||||||||
| 'method' => 'GET', | ||||||||||
| 'uri' => 'http://localhost', | ||||||||||
| 'parsed' => false, | ||||||||||
| ]; | ||||||||||
|
|
||||||||||
| $head = (string)\json_encode($body, \JSON_THROW_ON_ERROR); | ||||||||||
| $frame = new Frame($head .'test', [\strlen($head)]); | ||||||||||
|
|
||||||||||
| $relay->addFrames($frame); | ||||||||||
|
|
||||||||||
| $psrWorker->waitRequest(); | ||||||||||
|
|
||||||||||
| unset($_SERVER['REQUEST_TIME']); | ||||||||||
| unset($_SERVER['REQUEST_TIME_FLOAT']); | ||||||||||
|
|
||||||||||
| self::assertEquals($expectedServer, $_SERVER); | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
|
|
||||||||||
| protected function tearDown(): void | ||||||||||
| { | ||||||||||
| // Clean all extra output buffers | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Confirm interface compatibility for waitRequest signature.
PSR7Worker implements PSR7WorkerInterface; adding a parameter may break signature compatibility if the interface wasn’t updated.
If the interface still declares waitRequest(): ?ServerRequestInterface, either:
🏁 Script executed:
Length of output: 1158
Align
waitRequestsignature between PSR7WorkerInterface and PSR7Worker.PSR7WorkerInterface declares
but PSR7Worker implements
— update the interface to include the
bool $populateServer = trueparameter or remove it from the implementation to restore compatibility.🤖 Prompt for AI Agents