Skip to content

Commit fbcf5a3

Browse files
committed
chore: add httpserver
1 parent cc7f5d8 commit fbcf5a3

File tree

14 files changed

+856
-465
lines changed

14 files changed

+856
-465
lines changed

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
/**
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
namespace Utopia\Http\Adapter\Swoole;
4+
5+
use Swoole\Coroutine;
6+
use Utopia\Http\Adapter;
7+
use Utopia\DI\Container;
8+
use Swoole\Http\Server as SwooleServer;
9+
use Swoole\Http\Request as SwooleRequest;
10+
use Swoole\Http\Response as SwooleResponse;
11+
12+
class HttpServer extends Adapter
13+
{
14+
protected SwooleServer $server;
15+
protected const REQUEST_CONTAINER_CONTEXT_KEY = '__utopia_http_request_container';
16+
protected Container $container;
17+
protected ?Container $requestContainer = null;
18+
protected bool $coroutines;
19+
20+
public function __construct(string $host, ?string $port = null, array $settings = [], ?Container $container = null, bool $coroutines = false)
21+
{
22+
$this->coroutines = $coroutines;
23+
$this->server = new SwooleServer($host, (int) $port);
24+
$this->server->set(\array_merge([
25+
'enable_coroutine' => $coroutines,
26+
], $settings));
27+
$this->container = $container ?? new Container();
28+
}
29+
30+
public function onRequest(callable $callback)
31+
{
32+
$this->server->on('request', function (SwooleRequest $request, SwooleResponse $response) use ($callback) {
33+
$handler = function () use ($request, $response, $callback) {
34+
$requestContainer = new Container($this->container);
35+
$requestContainer->set('swooleRequest', fn () => $request);
36+
$requestContainer->set('swooleResponse', fn () => $response);
37+
38+
if ($this->coroutines && Coroutine::getCid() !== -1) {
39+
Coroutine::getContext()[self::REQUEST_CONTAINER_CONTEXT_KEY] = $requestContainer;
40+
} else {
41+
$this->requestContainer = $requestContainer;
42+
}
43+
44+
\call_user_func($callback, new Request($request), new Response($response));
45+
};
46+
47+
if ($this->coroutines) {
48+
go($handler);
49+
} else {
50+
$handler();
51+
}
52+
});
53+
}
54+
55+
public function getContainer(): Container
56+
{
57+
if ($this->coroutines && Coroutine::getCid() !== -1) {
58+
return Coroutine::getContext()[self::REQUEST_CONTAINER_CONTEXT_KEY] ?? $this->container;
59+
}
60+
61+
return $this->requestContainer ?? $this->container;
62+
}
63+
64+
public function getServer(): SwooleServer
65+
{
66+
return $this->server;
67+
}
68+
69+
public function onStart(callable $callback)
70+
{
71+
$this->server->on('start', function () use ($callback) {
72+
if ($this->coroutines) {
73+
go(function () use ($callback) {
74+
\call_user_func($callback, $this);
75+
});
76+
} else {
77+
\call_user_func($callback, $this);
78+
}
79+
});
80+
}
81+
82+
public function start()
83+
{
84+
return $this->server->start();
85+
}
86+
}

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
}

0 commit comments

Comments
 (0)