1818use Ripple \Net \Http \Enum \Method ;
1919use Ripple \Net \Http \Server ;
2020use Ripple \Net \Exception \FormatException ;
21- use Ripple \Net \Http \Server \Upload \Multipart ;
21+ use Ripple \Net \Http \Server \Upload \FormData ;
2222use Ripple \Runtime \Support \Stdin ;
2323use Ripple \Stream ;
2424use Ripple \Stream \Exception \ConnectionException ;
2727use function array_merge ;
2828use function count ;
2929use function explode ;
30- use function is_array ;
31- use function is_string ;
3230use function json_decode ;
3331use function max ;
3432use function parse_str ;
4745use function intval ;
4846use function rawurldecode ;
4947use function trim ;
48+ use function str_ends_with ;
5049
5150use 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