diff --git a/ext-src/stubs/php_swoole_http_request.stub.php b/ext-src/stubs/php_swoole_http_request.stub.php index 1e6efbd4b76..57bd4d3d7d4 100644 --- a/ext-src/stubs/php_swoole_http_request.stub.php +++ b/ext-src/stubs/php_swoole_http_request.stub.php @@ -8,5 +8,7 @@ public function parse(string $data): int|false {} public function isCompleted(): bool {} public function getMethod(): string|false {} public function getContent(): string|false {} + /** @return resource|false */ + public function getBodyStream() {} } } diff --git a/ext-src/stubs/php_swoole_http_request_arginfo.h b/ext-src/stubs/php_swoole_http_request_arginfo.h index 312a699af4f..ac8b90f9c15 100644 --- a/ext-src/stubs/php_swoole_http_request_arginfo.h +++ b/ext-src/stubs/php_swoole_http_request_arginfo.h @@ -21,3 +21,6 @@ ZEND_END_ARG_INFO() #define arginfo_class_Swoole_Http_Request_getMethod arginfo_class_Swoole_Http_Request_getData #define arginfo_class_Swoole_Http_Request_getContent arginfo_class_Swoole_Http_Request_getData + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Swoole_Http_Request_getBodyStream, 0, 0, MAY_BE_RESOURCE|MAY_BE_FALSE) +ZEND_END_ARG_INFO() diff --git a/ext-src/swoole_http_request.cc b/ext-src/swoole_http_request.cc index 946df7f88a9..44b4ec3694c 100644 --- a/ext-src/swoole_http_request.cc +++ b/ext-src/swoole_http_request.cc @@ -209,6 +209,7 @@ static PHP_METHOD(swoole_http_request, parse); static PHP_METHOD(swoole_http_request, isCompleted); static PHP_METHOD(swoole_http_request, getMethod); static PHP_METHOD(swoole_http_request, getContent); +static PHP_METHOD(swoole_http_request, getBodyStream); SW_EXTERN_C_END // clang-format off @@ -221,6 +222,7 @@ const zend_function_entry swoole_http_request_methods[] = PHP_ME(swoole_http_request, parse, arginfo_class_Swoole_Http_Request_parse, ZEND_ACC_PUBLIC) PHP_ME(swoole_http_request, isCompleted, arginfo_class_Swoole_Http_Request_isCompleted, ZEND_ACC_PUBLIC) PHP_ME(swoole_http_request, getMethod, arginfo_class_Swoole_Http_Request_getMethod, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_request, getBodyStream, arginfo_class_Swoole_Http_Request_getBodyStream, ZEND_ACC_PUBLIC) PHP_FE_END }; // clang-format on @@ -910,6 +912,45 @@ static PHP_METHOD(swoole_http_request, getContent) { RETURN_EMPTY_STRING(); } +static PHP_METHOD(swoole_http_request, getBodyStream) { + HttpContext *ctx = php_swoole_http_request_get_and_check_context(ZEND_THIS); + if (UNEXPECTED(!ctx)) { + RETURN_FALSE; + } + + HttpRequest *req = &ctx->request; + const char *data = nullptr; + size_t length = 0; + + if (req->body_length > 0) { + zval *zdata = &req->zdata; + data = Z_STRVAL_P(zdata) + Z_STRLEN_P(zdata) - req->body_length; + length = req->body_length; + } else if (req->chunked_body && req->chunked_body->length != 0) { + data = req->chunked_body->str; + length = req->chunked_body->length; + } else if (req->h2_data_buffer && req->h2_data_buffer->length != 0) { + data = req->h2_data_buffer->str; + length = req->h2_data_buffer->length; + } + + zend_string *buf = nullptr; + if (data && length > 0) { + buf = zend_string_init(data, length, 0); + } + php_stream *stream = php_stream_memory_open(TEMP_STREAM_READONLY, buf); + if (!stream) { + if (buf) { + zend_string_release(buf); + } + RETURN_FALSE; + } + php_stream_to_zval(stream, return_value); + if (buf) { + zend_string_release(buf); + } +} + static PHP_METHOD(swoole_http_request, getData) { HttpContext *ctx = php_swoole_http_request_get_and_check_context(ZEND_THIS); if (UNEXPECTED(!ctx)) { diff --git a/tests/swoole_http_server/getBodyStream.phpt b/tests/swoole_http_server/getBodyStream.phpt new file mode 100644 index 00000000000..332b5f98158 --- /dev/null +++ b/tests/swoole_http_server/getBodyStream.phpt @@ -0,0 +1,46 @@ +--TEST-- +swoole_http_server: getBodyStream +--SKIPIF-- + +--FILE-- +parentFunc = function ($pid) use ($pm) { + run(function () use ($pm) { + $randomData = get_safe_random(); + $cli = new Co\http\Client(HTTP_SERVER_HOST, $pm->getFreePort(), false); + $cli->setMethod('POST'); + $cli->setData($randomData); + $ok = $cli->execute('/getBodyStream'); + Assert::assert($ok); + Assert::same($cli->statusCode, 200); + Assert::same($cli->errCode, 0); + Assert::same($cli->body, $randomData); + $pm->kill(); + echo "DONE\n"; + }); +}; +$pm->childFunc = function () use ($pm) { + $http = new Swoole\Http\Server('127.0.0.1', $pm->getFreePort(), SWOOLE_BASE); + $http->set(['worker_num' => 1]); + $http->on('workerStart', function () use ($pm) { + $pm->wakeup(); + }); + $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) { + $stream = $request->getBodyStream(); + $response->end(stream_get_contents($stream)); + }); + $http->start(); +}; +$pm->childFirst(); +$pm->run(); +?> +--EXPECT-- +DONE diff --git a/tests/swoole_server/close_reset.phpt b/tests/swoole_server/close_reset.phpt index 4dcfdd3338c..82f5b491dc9 100644 --- a/tests/swoole_server/close_reset.phpt +++ b/tests/swoole_server/close_reset.phpt @@ -34,11 +34,11 @@ $pm->parentFunc = function ($pid) use ($pm) { break; } $data .= $ret; - if (substr($ret, -2, 2) == "\r\n") { + if (substr($ret, -2, 2) === "\r\n") { break; } } - Assert::lessThan(strlen($data), N); + Assert::lessThanEq(strlen($data), N + 2); echo "DONE\n"; }); Swoole\Event::wait();