Skip to content

Commit 4452b37

Browse files
committed
Fixed leak state server
1 parent 740c24a commit 4452b37

File tree

3 files changed

+52
-45
lines changed

3 files changed

+52
-45
lines changed

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,11 @@
4141
"ext-json": "*",
4242
"psr/http-factory": "^1.0.1",
4343
"psr/http-message": "^1.0.1 || ^2.0",
44+
"roadrunner-php/roadrunner-api-dto": "^1.6",
4445
"spiral/roadrunner": "^2023.3 || ^2024.1 || ^2025.1",
4546
"spiral/roadrunner-worker": "^3.5",
46-
"roadrunner-php/roadrunner-api-dto": "^1.6",
47-
"symfony/polyfill-php83": "^1.29"
47+
"symfony/polyfill-php83": "^1.29",
48+
"symfony/var-dumper": "^6.4"
4849
},
4950
"require-dev": {
5051
"jetbrains/phpstorm-attributes": "^1.0",

src/GlobalState.php

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,33 @@ final class GlobalState
1919
*/
2020
public static function populateServer(Request $request): array
2121
{
22-
static $server = [];
22+
static $originalServer = null;
2323

24-
if ([] == $server) {
25-
$server = $_SERVER;
24+
if ($originalServer == null) {
25+
$originalServer = $_SERVER;
2626
}
2727

28-
$server['REQUEST_URI'] = $request->uri;
29-
$server['REQUEST_TIME'] = time();
30-
$server['REQUEST_TIME_FLOAT'] = microtime(true);
31-
$server['REMOTE_ADDR'] = $request->getRemoteAddr();
32-
$server['REQUEST_METHOD'] = $request->method;
33-
$server['HTTP_USER_AGENT'] = '';
28+
$newServer = $originalServer;
29+
30+
$newServer['REQUEST_URI'] = $request->uri;
31+
$newServer['REQUEST_TIME'] = time();
32+
$newServer['REQUEST_TIME_FLOAT'] = microtime(true);
33+
$newServer['REMOTE_ADDR'] = $request->getRemoteAddr();
34+
$newServer['REQUEST_METHOD'] = $request->method;
35+
$newServer['HTTP_USER_AGENT'] = '';
3436

3537
foreach ($request->headers as $key => $value) {
3638
$key = strtoupper(str_replace('-', '_', $key));
3739

3840
if ($key == 'CONTENT_TYPE' || $key == 'CONTENT_LENGTH') {
39-
$server[$key] = implode(', ', $value);
41+
$newServer[$key] = implode(', ', $value);
4042

4143
continue;
4244
}
4345

44-
$server['HTTP_' . $key] = implode(', ', $value);
46+
$newServer['HTTP_' . $key] = implode(', ', $value);
4547
}
4648

47-
return $server;
49+
return $newServer;
4850
}
4951
}

tests/Unit/PSR7WorkerTest.php

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,65 @@
22

33
declare(strict_types=1);
44

5-
namespace Spiral\RoadRunner\Tests\Http\Unit;
6-
75
use Nyholm\Psr7\Factory\Psr17Factory;
6+
use PHPUnit\Framework\Attributes\CoversClass;
87
use PHPUnit\Framework\TestCase;
98
use Spiral\Goridge\Frame;
10-
use Spiral\RoadRunner\Http\HttpWorker;
9+
use Spiral\RoadRunner\Http\GlobalState;
1110
use Spiral\RoadRunner\Http\PSR7Worker;
1211
use Spiral\RoadRunner\Tests\Http\Unit\Stub\TestRelay;
1312
use Spiral\RoadRunner\Worker;
1413

14+
15+
#[CoversClass(PSR7Worker::class)]
16+
#[CoversClass(GlobalState::class)]
1517
final class PSR7WorkerTest extends TestCase
1618
{
17-
/**
19+
/***
1820
* @param array $headers
19-
*
20-
* @dataProvider testStateLeakDataProvider
2121
*/
22-
public function testStateLeak(array $headers): void
22+
public function testStateServerLeak(): void
2323
{
2424
$psrFactory = new Psr17Factory();
2525
$relay = new TestRelay();
26-
27-
$body = [
28-
'headers' => $headers,
29-
'rawQuery' => '',
30-
'remoteAddr' => '127.0.0.1',
31-
'protocol' => 'HTTP/1.1',
32-
'method' => 'GET',
33-
'uri' => 'http://localhost',
34-
'parsed' => false,
35-
];
36-
37-
$head = (string)\json_encode($body, \JSON_THROW_ON_ERROR);
38-
$frame = new Frame($head .'test', [\strlen($head)]);
39-
40-
$relay->addFrames($frame);
41-
42-
$psrWorker = new PSR7Worker(
26+
$psrWorker = new PSR7Worker(
4327
new Worker($relay),
4428
$psrFactory,
4529
$psrFactory,
4630
$psrFactory,
4731
);
4832

49-
$psrWorker->waitRequest();
33+
//dataProvider is always random and we need to keep the order
34+
$fixtures = [
35+
[['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',]],
36+
[['Content-Type' => ['application/json']], ['REQUEST_URI' => 'http://localhost', 'REMOTE_ADDR' => '127.0.0.1', 'REQUEST_METHOD' => 'GET', 'HTTP_USER_AGENT' => '', 'CONTENT_TYPE' => 'application/json']],
37+
];
5038

39+
foreach ($fixtures as [$headers, $expectedServer]) {
40+
$body = [
41+
'headers' => $headers,
42+
'rawQuery' => '',
43+
'remoteAddr' => '127.0.0.1',
44+
'protocol' => 'HTTP/1.1',
45+
'method' => 'GET',
46+
'uri' => 'http://localhost',
47+
'parsed' => false,
48+
];
5149

52-
var_dump($_SERVER);
53-
}
50+
$head = (string)\json_encode($body, \JSON_THROW_ON_ERROR);
51+
$frame = new Frame($head .'test', [\strlen($head)]);
5452

53+
$relay->addFrames($frame);
5554

56-
public static function testStateLeakDataProvider(): iterable
57-
{
58-
yield [['Content-Type' => ['application/json'], 'Accept' => ['application/html']]];
59-
yield [['Content-Type' => ['application/json']]];
55+
$_SERVER = [];
56+
57+
$psrWorker->waitRequest();
58+
59+
unset($_SERVER['REQUEST_TIME']);
60+
unset($_SERVER['REQUEST_TIME_FLOAT']);
61+
62+
self::assertEquals($expectedServer, $_SERVER);
63+
}
6064
}
6165

6266

0 commit comments

Comments
 (0)