Skip to content

Commit 5a9fea0

Browse files
committed
chore: add httpserver
1 parent cc7f5d8 commit 5a9fea0

16 files changed

Lines changed: 872 additions & 487 deletions

File tree

composer.json

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@
1010
],
1111
"license": "MIT",
1212
"minimum-stability": "stable",
13-
"autoload": {
13+
"autoload": {
14+
"psr-4": {
15+
"Utopia\\": "src/"
16+
}
17+
},
18+
"autoload-dev": {
1419
"psr-4": {
15-
"Utopia\\": "src/",
16-
"Tests\\E2E\\": "tests/e2e"
17-
}
18-
},
19-
"autoload-dev": {
20-
"psr-4": {
21-
"Utopia\\Http\\Tests\\": "tests/"
22-
}
23-
},
20+
"Utopia\\Http\\Tests\\": "tests/",
21+
"Tests\\E2E\\": "tests/e2e"
22+
}
23+
},
2424
"scripts": {
2525
"lint": "vendor/bin/pint --test",
2626
"format": "vendor/bin/pint",
@@ -30,9 +30,11 @@
3030
},
3131
"require": {
3232
"php": ">=8.2",
33+
"ext-swoole": "*",
3334
"utopia-php/di": "0.3.*",
34-
"utopia-php/validators": "0.2.*",
35-
"ext-swoole": "*"
35+
"utopia-php/servers": "0.3.*",
36+
"utopia-php/compression": "0.1.*",
37+
"utopia-php/validators": "0.2.*"
3638
},
3739
"config": {
3840
"allow-plugins": {

composer.lock

Lines changed: 102 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Http/Adapter/FPM/Request.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,26 @@ public function setServer(string $key, string $value): static
6868
*/
6969
public function getIP(): string
7070
{
71-
$ips = explode(',', $this->getHeader('HTTP_X_FORWARDED_FOR', $this->getServer('REMOTE_ADDR') ?? '0.0.0.0'));
71+
$remoteAddr = $this->getServer('REMOTE_ADDR') ?? '0.0.0.0';
7272

73-
return trim($ips[0] ?? '');
73+
foreach ($this->trustedIpHeaders as $header) {
74+
$headerValue = $this->getHeader($header);
75+
76+
if (empty($headerValue)) {
77+
continue;
78+
}
79+
80+
// Leftmost IP address is the address of the originating client
81+
$ips = \explode(',', $headerValue);
82+
$ip = \trim($ips[0]);
83+
84+
// Validate IP format (supports both IPv4 and IPv6)
85+
if (\filter_var($ip, FILTER_VALIDATE_IP)) {
86+
return $ip;
87+
}
88+
}
89+
90+
return $remoteAddr;
7491
}
7592

7693
/**

src/Http/Adapter/Swoole/Request.php

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,26 @@ public function setServer(string $key, string $value): static
7373
*/
7474
public function getIP(): string
7575
{
76-
$ips = explode(',', $this->getHeader('x-forwarded-for', $this->getServer('remote_addr') ?? '0.0.0.0'));
76+
$remoteAddr = $this->getServer('remote_addr') ?? '0.0.0.0';
7777

78-
return trim($ips[0] ?? '');
78+
foreach ($this->trustedIpHeaders as $header) {
79+
$headerValue = $this->getHeader($header);
80+
81+
if (empty($headerValue)) {
82+
continue;
83+
}
84+
85+
// Leftmost IP address is the address of the originating client
86+
$ips = explode(',', $headerValue);
87+
$ip = trim($ips[0]);
88+
89+
// Validate IP format (supports both IPv4 and IPv6)
90+
if (filter_var($ip, FILTER_VALIDATE_IP)) {
91+
return $ip;
92+
}
93+
}
94+
95+
return $remoteAddr;
7996
}
8097

8198
/**
@@ -259,9 +276,12 @@ public function getCookie(string $key, string $default = ''): string
259276
$cookies = \explode(';', $this->getHeader('cookie', ''));
260277
foreach ($cookies as $cookie) {
261278
$cookie = \trim($cookie);
262-
[$cookieKey, $cookieValue] = \explode('=', $cookie, 2);
263-
$cookieKey = \trim($cookieKey);
264-
$cookieValue = \trim($cookieValue);
279+
if ($cookie === '') {
280+
continue;
281+
}
282+
$parts = \explode('=', $cookie, 2);
283+
$cookieKey = \trim($parts[0]);
284+
$cookieValue = isset($parts[1]) ? \trim($parts[1]) : '';
265285
if ($cookieKey === $key) {
266286
return $cookieValue;
267287
}

src/Http/Adapter/Swoole/Response.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,14 @@ public function sendHeader(string $key, mixed $value): void
8686
protected function sendCookie(string $name, string $value, array $options): void
8787
{
8888
$this->swoole->cookie(
89-
name: $name,
90-
value: $value,
91-
expires: $options['expire'] ?? 0,
92-
path: $options['path'] ?? '',
93-
domain: $options['domain'] ?? '',
94-
secure: $options['secure'] ?? false,
95-
httponly: $options['httponly'] ?? false,
96-
samesite: $options['samesite'] ?? false,
89+
$name,
90+
$value,
91+
$options['expire'] ?? 0,
92+
$options['path'] ?? '',
93+
$options['domain'] ?? '',
94+
$options['secure'] ?? false,
95+
$options['httponly'] ?? false,
96+
$options['samesite'] ?? false,
9797
);
9898
}
9999
}

src/Http/Adapter/Swoole/Server.php

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,73 +2,64 @@
22

33
namespace Utopia\Http\Adapter\Swoole;
44

5-
use Swoole\Coroutine;
65
use Utopia\Http\Adapter;
76
use Utopia\DI\Container;
8-
use Swoole\Coroutine\Http\Server as SwooleServer;
7+
use Swoole\Http\Server as SwooleServer;
98
use Swoole\Http\Request as SwooleRequest;
109
use Swoole\Http\Response as SwooleResponse;
1110

12-
use function Swoole\Coroutine\run;
13-
1411
class Server extends Adapter
1512
{
1613
protected SwooleServer $server;
17-
protected const REQUEST_CONTAINER_CONTEXT_KEY = '__utopia_http_request_container';
1814
protected Container $container;
1915
protected ?Container $requestContainer = null;
2016

2117
public function __construct(string $host, ?string $port = null, array $settings = [], ?Container $container = null)
2218
{
23-
$this->server = new SwooleServer($host, $port);
24-
$this->server->set(\array_merge([
25-
'enable_coroutine' => true,
26-
'http_parse_cookie' => false,
27-
], $settings));
19+
$this->server = new SwooleServer($host, (int) $port);
20+
$this->server->set(\array_merge($settings, [
21+
'open_http2_protocol' => true,
22+
'dispatch_mode' => 2,
23+
]));
2824
$this->container = $container ?? new Container();
2925
}
3026

3127
public function onRequest(callable $callback)
3228
{
33-
$this->server->handle('/', function (SwooleRequest $request, SwooleResponse $response) use ($callback) {
34-
$requestContainer = new Container($this->container);
35-
$requestContainer->set('swooleRequest', fn () => $request);
36-
$requestContainer->set('swooleResponse', fn () => $response);
29+
$this->server->on('request', function (SwooleRequest $request, SwooleResponse $response) use ($callback) {
30+
go(function () use ($request, $response, $callback) {
31+
$requestContainer = new Container($this->container);
32+
$requestContainer->set('swooleRequest', fn () => $request);
33+
$requestContainer->set('swooleResponse', fn () => $response);
3734

38-
if (Coroutine::getCid() !== -1) {
39-
Coroutine::getContext()[self::REQUEST_CONTAINER_CONTEXT_KEY] = $requestContainer;
40-
} else {
4135
$this->requestContainer = $requestContainer;
42-
}
43-
44-
$utopiaRequest = new Request($request);
45-
$utopiaResponse = new Response($response);
4636

47-
\call_user_func($callback, $utopiaRequest, $utopiaResponse);
37+
\call_user_func($callback, new Request($request), new Response($response));
38+
});
4839
});
4940
}
5041

5142
public function getContainer(): Container
5243
{
53-
if (Coroutine::getCid() !== -1) {
54-
return Coroutine::getContext()[self::REQUEST_CONTAINER_CONTEXT_KEY] ?? $this->container;
55-
}
56-
5744
return $this->requestContainer ?? $this->container;
5845
}
5946

60-
public function onStart(callable $callback)
47+
public function getServer(): SwooleServer
6148
{
49+
return $this->server;
50+
}
6251

63-
\call_user_func($callback, $this);
52+
public function onStart(callable $callback)
53+
{
54+
$this->server->on('start', function () use ($callback) {
55+
go(function () use ($callback) {
56+
\call_user_func($callback, $this);
57+
});
58+
});
6459
}
6560

6661
public function start()
6762
{
68-
if (Coroutine::getCid() === -1) {
69-
run(fn () => $this->server->start());
70-
} else {
71-
$this->server->start();
72-
}
63+
return $this->server->start();
7364
}
7465
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Utopia\Http\Adapter\SwooleCoroutine;
4+
5+
use Utopia\Http\Adapter\Swoole\Request as SwooleAdapterRequest;
6+
7+
class Request extends SwooleAdapterRequest
8+
{
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Utopia\Http\Adapter\SwooleCoroutine;
4+
5+
use Utopia\Http\Adapter\Swoole\Response as SwooleAdapterResponse;
6+
7+
class Response extends SwooleAdapterResponse
8+
{
9+
}

0 commit comments

Comments
 (0)