Skip to content

Commit 662dd55

Browse files
committed
opz: (http) Make the behavior of formdata consistent with that of fpm.
1 parent 0e97dfc commit 662dd55

6 files changed

Lines changed: 168 additions & 135 deletions

File tree

src/Net/Http/Client.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,13 @@ public function request(string $method, string $uri, array $options = []): Respo
210210
}
211211

212212
$request = new Request(
213-
conn: null,
214213
GET: [],
215214
POST: [],
216215
COOKIE: [],
217216
FILES: [],
218217
SERVER: $serverArray,
219-
CONTENT: $content
218+
CONTENT: $content,
219+
conn:null,
220220
);
221221

222222
$stream = $this->newConn($scheme, $host, $port, $fullOptions);

src/Net/Http/Request.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ class Request
4444
* @param mixed|null $CONTENT
4545
*/
4646
public function __construct(
47-
public readonly ?Connection $conn = null,
4847
public readonly array $GET = [],
4948
public readonly array $POST = [],
5049
public readonly array $COOKIE = [],
5150
public readonly array $FILES = [],
5251
public readonly array $SERVER = [],
5352
public readonly mixed $CONTENT = null,
53+
public readonly ?Connection $conn = null,
5454
) {
5555
$this->REQUEST = array_merge($this->GET, $this->POST);
5656
}

src/Net/Http/Server/Connection.php

Lines changed: 112 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use Ripple\Net\Http\Enum\Method;
1919
use Ripple\Net\Http\Server;
2020
use Ripple\Net\Exception\FormatException;
21-
use Ripple\Net\Http\Server\Upload\Multipart;
21+
use Ripple\Net\Http\Server\Upload\FormData;
2222
use Ripple\Runtime\Support\Stdin;
2323
use Ripple\Stream;
2424
use Ripple\Stream\Exception\ConnectionException;
@@ -27,8 +27,6 @@
2727
use function array_merge;
2828
use function count;
2929
use function explode;
30-
use function is_array;
31-
use function is_string;
3230
use function json_decode;
3331
use function max;
3432
use function parse_str;
@@ -47,6 +45,7 @@
4745
use function intval;
4846
use function rawurldecode;
4947
use function trim;
48+
use function str_ends_with;
5049

5150
use const PHP_URL_PATH;
5251

@@ -84,13 +83,13 @@ class Connection
8483
* Query 查询参数数组
8584
* @var array
8685
*/
87-
private array $query;
86+
private array $get;
8887

8988
/**
9089
* 请求体参数数组
9190
* @var array
9291
*/
93-
private array $request;
92+
private array $post;
9493

9594
/**
9695
* 请求属性数组
@@ -124,9 +123,9 @@ class Connection
124123

125124
/**
126125
* Multipart数据处理器
127-
* @var Multipart|null
126+
* @var FormData|null
128127
*/
129-
private Multipart|null $multipart;
128+
private FormData|null $multipart;
130129

131130
/**
132131
* 已接收的请求体长度
@@ -169,6 +168,25 @@ public function __construct(
169168
$this->reset();
170169
}
171170

171+
/**
172+
* 重置连接状态
173+
* @return void
174+
*/
175+
private function reset(): void
176+
{
177+
$this->step = self::STEP_INITIAL;
178+
$this->get = [];
179+
$this->post = [];
180+
$this->attributes = [];
181+
$this->cookies = [];
182+
$this->files = [];
183+
$this->meta = $this->alwaysMeta;
184+
$this->content = '';
185+
$this->multipart = null;
186+
$this->bodySize = 0;
187+
$this->contentLength = 0;
188+
}
189+
172190
/**
173191
* 启动连接处理
174192
* @return void
@@ -199,66 +217,6 @@ public function start(): void
199217
}
200218
}
201219

202-
/**
203-
* @return bool
204-
*/
205-
public function isClosed(): bool
206-
{
207-
return $this->stream->isClosed();
208-
}
209-
210-
/**
211-
* 处理 HTTP 请求
212-
* @param Request $req 请求信息
213-
* @return void
214-
* @throws ConnectionException
215-
*/
216-
private function onRequest(Request $req): void
217-
{
218-
$response = $req->response();
219-
$response->withHeader('Server', 'ripple');
220-
221-
// 半关闭检测
222-
$connHeader = $reqInfo['server']['HTTP_CONNECTION'] ?? '';
223-
$upgradeHeader = $reqInfo['server']['HTTP_UPGRADE'] ?? '';
224-
$keepAlive = strtolower($connHeader) !== 'close';
225-
$isWebSocketUpgrade = strtolower($upgradeHeader) === 'websocket' && str_contains(strtolower($connHeader), 'upgrade');
226-
227-
if ($keepAlive || $isWebSocketUpgrade) {
228-
$response->withHeader('Connection', $keepAlive ? 'keep-alive' : 'Upgrade');
229-
} else {
230-
$response->withHeader('Connection', 'close');
231-
}
232-
233-
try {
234-
Scheduler::resume($this->server->acquireCoroutine(), $req)->rethrow();
235-
} catch (ConnectionException $exception) {
236-
throw $exception;
237-
} catch (Throwable $exception) {
238-
$req->respond($exception->getMessage(), [], 500);
239-
$this->reset();
240-
}
241-
}
242-
243-
/**
244-
* 重置连接状态
245-
* @return void
246-
*/
247-
private function reset(): void
248-
{
249-
$this->step = self::STEP_INITIAL;
250-
$this->query = [];
251-
$this->request = [];
252-
$this->attributes = [];
253-
$this->cookies = [];
254-
$this->files = [];
255-
$this->meta = $this->alwaysMeta;
256-
$this->content = '';
257-
$this->multipart = null;
258-
$this->bodySize = 0;
259-
$this->contentLength = 0;
260-
}
261-
262220
/**
263221
* 处理接收到的数据
264222
* @param string $content 接收的数据
@@ -281,19 +239,19 @@ private function fill(string $content): array
281239
}
282240

283241
if ($this->step === self::STEP_FILE_TRANSFER) {
284-
$this->processFileUpload();
242+
$this->processFormData();
285243
}
286244

287245
if ($this->step === self::STEP_COMPLETE) {
288246
$reqInfo = $this->completeRequest();
289247
$reqs[] = new Request(
290-
$this,
291-
$reqInfo['query'],
292-
$reqInfo['request'],
248+
$reqInfo['get'],
249+
$reqInfo['post'],
293250
$reqInfo['cookies'],
294251
$reqInfo['files'],
295252
$reqInfo['server'],
296-
$reqInfo['content']
253+
$reqInfo['content'],
254+
$this,
297255
);
298256

299257
if ($this->buf !== '') {
@@ -315,6 +273,7 @@ private function fill(string $content): array
315273
private function initialStep(): void
316274
{
317275
if ($headerEnd = strpos($this->buf, "\r\n\r\n")) {
276+
318277
$buffer = $this->readBuffer();
319278

320279
$this->step = self::STEP_CONTINUOUS;
@@ -357,7 +316,7 @@ private function initialStep(): void
357316
$boundary = $matches[1];
358317
$this->step = self::STEP_FILE_TRANSFER;
359318
if (!isset($this->multipart)) {
360-
$this->multipart = new Multipart($boundary);
319+
$this->multipart = new FormData($boundary);
361320
}
362321
} else {
363322
$this->step = self::STEP_CONTINUOUS;
@@ -409,7 +368,7 @@ private function initParams(array $base): void
409368
*/
410369
private function parseQuery(string $queryStr): void
411370
{
412-
parse_str($queryStr, $this->query);
371+
parse_str($queryStr, $this->get);
413372
}
414373

415374
/**
@@ -434,32 +393,32 @@ private function parseHeaders(): void
434393
}
435394

436395
/**
437-
* 验证内容长度
396+
* 处理连续传输
438397
* @return void
439398
* @throws RuntimeException 运行时异常
440399
*/
441-
private function checkContentLength(): void
400+
private function receiveBody(): void
442401
{
443-
if ($this->bodySize === $this->contentLength) {
444-
$this->step = self::STEP_COMPLETE;
445-
} elseif ($this->bodySize > $this->contentLength) {
446-
throw new RuntimeException('Content-Length is not match');
402+
if ($buffer = $this->readBuffer(max(0, $this->contentLength - $this->bodySize))) {
403+
$this->content .= $buffer;
404+
$this->bodySize += strlen($buffer);
447405
}
406+
407+
$this->checkContentLength();
448408
}
449409

450410
/**
451-
* 处理连续传输
411+
* 验证内容长度
452412
* @return void
453413
* @throws RuntimeException 运行时异常
454414
*/
455-
private function receiveBody(): void
415+
private function checkContentLength(): void
456416
{
457-
if ($buffer = $this->readBuffer(max(0, $this->contentLength - $this->bodySize))) {
458-
$this->content .= $buffer;
459-
$this->bodySize += strlen($buffer);
417+
if ($this->bodySize === $this->contentLength) {
418+
$this->step = self::STEP_COMPLETE;
419+
} elseif ($this->bodySize > $this->contentLength) {
420+
throw new RuntimeException('Content-Length is not match');
460421
}
461-
462-
$this->checkContentLength();
463422
}
464423

465424
/**
@@ -468,16 +427,29 @@ private function receiveBody(): void
468427
* @throws FormatException 格式异常
469428
* @throws RuntimeException 运行时异常
470429
*/
471-
private function processFileUpload(): void
430+
private function processFormData(): void
472431
{
473432
if ($buffer = $this->readBuffer(max(0, $this->contentLength - $this->bodySize))) {
474433
$this->bodySize += strlen($buffer);
475-
foreach ($this->multipart->fill($buffer) as $name => $multipartResult) {
476-
if (is_string($multipartResult)) {
477-
$this->request[$name] = $multipartResult;
478-
} elseif (is_array($multipartResult)) {
479-
foreach ($multipartResult as $file) {
480-
$this->files[$name][] = $file;
434+
foreach ($this->multipart->fill($buffer) as $multipartResult) {
435+
foreach ($multipartResult as $formItem) {
436+
$name = $formItem['name'];
437+
$isArray = str_ends_with($name, '[]');
438+
$isFile = $formItem['isFile'];
439+
440+
if ($isArray) {
441+
$name = substr($name, 0, -2);
442+
if ($isFile) {
443+
$this->files[$name][] = $formItem;
444+
} else {
445+
$this->post[$name][] = $formItem['value'];
446+
}
447+
} else {
448+
if ($isFile) {
449+
$this->files[$name] = $formItem;
450+
} else {
451+
$this->post[$name] = $formItem['value'];
452+
}
481453
}
482454
}
483455
}
@@ -497,8 +469,8 @@ private function completeRequest(): array
497469
$this->parseXfp();
498470

499471
$result = [
500-
'query' => $this->query,
501-
'request' => $this->request,
472+
'get' => $this->get,
473+
'post' => $this->post,
502474
'attributes' => $this->attributes,
503475
'cookies' => $this->cookies,
504476
'files' => $this->files,
@@ -549,10 +521,9 @@ private function parseRequestBody(): void
549521
{
550522
if ($this->method->value === 'POST') {
551523
if (str_contains($this->contentType, 'application/json')) {
552-
$this->request = array_merge($this->request, json_decode($this->content, true) ?? []);
553-
} else {
554-
parse_str($this->content, $reqParams);
555-
$this->request = array_merge($this->request, $reqParams);
524+
$this->post = array_merge($this->post, json_decode($this->content, true) ?? []);
525+
} elseif ($this->contentType === 'application/x-www-form-urlencoded') {
526+
parse_str($this->content, $this->post);
556527
}
557528
}
558529
}
@@ -568,4 +539,45 @@ private function parseXfp(): void
568539
$this->meta['HTTPS'] = $xfw === 'https' ? 'on' : 'off';
569540
}
570541
}
542+
543+
/**
544+
* 处理 HTTP 请求
545+
* @param Request $req 请求信息
546+
* @return void
547+
* @throws ConnectionException
548+
*/
549+
private function onRequest(Request $req): void
550+
{
551+
$response = $req->response();
552+
$response->withHeader('Server', 'ripple');
553+
554+
// 半关闭检测
555+
$connHeader = $reqInfo['server']['HTTP_CONNECTION'] ?? '';
556+
$upgradeHeader = $reqInfo['server']['HTTP_UPGRADE'] ?? '';
557+
$keepAlive = strtolower($connHeader) !== 'close';
558+
$isWebSocketUpgrade = strtolower($upgradeHeader) === 'websocket' && str_contains(strtolower($connHeader), 'upgrade');
559+
560+
if ($keepAlive || $isWebSocketUpgrade) {
561+
$response->withHeader('Connection', $keepAlive ? 'keep-alive' : 'Upgrade');
562+
} else {
563+
$response->withHeader('Connection', 'close');
564+
}
565+
566+
try {
567+
Scheduler::resume($this->server->acquireCoroutine(), $req)->rethrow();
568+
} catch (ConnectionException $exception) {
569+
throw $exception;
570+
} catch (Throwable $exception) {
571+
$req->respond($exception->getMessage(), [], 500);
572+
$this->reset();
573+
}
574+
}
575+
576+
/**
577+
* @return bool
578+
*/
579+
public function isClosed(): bool
580+
{
581+
return $this->stream->isClosed();
582+
}
571583
}

0 commit comments

Comments
 (0)