From b21b8d977c05eef37b1f4c5f2e05d8581524de1d Mon Sep 17 00:00:00 2001 From: "Tianfeng.Han" Date: Wed, 24 Jul 2024 11:33:16 +0800 Subject: [PATCH] New cookie API (#5420) * new cookie * optimize set cookie method * fix error * optimize code * optimize code * refactor * optimize code * optimize code [2] --------- Co-authored-by: NathanFreeman <1056159381@qq.com> Co-authored-by: MARiA so cute <33935209+NathanFreeman@users.noreply.github.com> --- ext-src/php_swoole.cc | 1 + ext-src/php_swoole_http.h | 39 ++ ext-src/php_swoole_private.h | 1 + ext-src/stubs/php_swoole_http_cookie.stub.php | 19 + .../stubs/php_swoole_http_cookie_arginfo.h | 55 +++ .../stubs/php_swoole_http_response.stub.php | 4 +- .../stubs/php_swoole_http_response_arginfo.h | 18 +- ext-src/swoole_http_cookie.cc | 440 ++++++++++++++++++ ext-src/swoole_http_response.cc | 225 +++------ include/swoole_error.h | 1 + tests/start.sh | 4 + tests/swoole_http_client_coro/issue_2664.phpt | 4 +- tests/swoole_http_server/cookieAlias.phpt | 56 +++ tests/swoole_http_server/cookie_samesite.phpt | 2 +- .../cookie_vs_rawcookie.phpt | 21 +- tests/swoole_http_server/max-age.phpt | 4 +- tests/swoole_http_server/new_cookie.phpt | 74 +++ tests/swoole_http_server/objectCookie.phpt | 49 ++ .../objectCookieMemory.phpt | 77 +++ tests/swoole_http_server/rawCookie.phpt | 2 +- .../check_cookie_crlf.phpt | 2 +- 21 files changed, 924 insertions(+), 174 deletions(-) create mode 100644 ext-src/stubs/php_swoole_http_cookie.stub.php create mode 100644 ext-src/stubs/php_swoole_http_cookie_arginfo.h create mode 100644 ext-src/swoole_http_cookie.cc create mode 100644 tests/swoole_http_server/cookieAlias.phpt create mode 100644 tests/swoole_http_server/new_cookie.phpt create mode 100644 tests/swoole_http_server/objectCookie.phpt create mode 100644 tests/swoole_http_server/objectCookieMemory.phpt diff --git a/ext-src/php_swoole.cc b/ext-src/php_swoole.cc index cc82067679b..bb369301d14 100644 --- a/ext-src/php_swoole.cc +++ b/ext-src/php_swoole.cc @@ -745,6 +745,7 @@ PHP_MINIT_FUNCTION(swoole) { php_swoole_server_port_minit(module_number); php_swoole_http_request_minit(module_number); php_swoole_http_response_minit(module_number); + php_swoole_http_cookie_minit(module_number); php_swoole_http_server_minit(module_number); php_swoole_http_server_coro_minit(module_number); php_swoole_websocket_server_minit(module_number); diff --git a/ext-src/php_swoole_http.h b/ext-src/php_swoole_http.h index 71a7613fcf0..83d4f44144a 100644 --- a/ext-src/php_swoole_http.h +++ b/ext-src/php_swoole_http.h @@ -213,6 +213,43 @@ struct Context { void free(); }; +class Cookie { + private: + bool encode_; + smart_str buffer_ = {0}; + + protected: + zend_string *name = nullptr; + zend_string *value = nullptr; + zend_string *path = nullptr; + zend_string *domain = nullptr; + zend_string *sameSite = nullptr; + zend_string *priority = nullptr; + zend_long expires = 0; + zend_bool secure = false; + zend_bool httpOnly = false; + zend_bool partitioned = false; + + public: + Cookie(bool _encode = true) { + encode_ = _encode; + } + Cookie *withName(zend_string *); + Cookie *withExpires(zend_long); + Cookie *withSecure(zend_bool); + Cookie *withHttpOnly(zend_bool); + Cookie *withPartitioned(zend_bool); + Cookie *withValue(zend_string *); + Cookie *withPath(zend_string *); + Cookie *withDomain(zend_string *); + Cookie *withSameSite(zend_string *); + Cookie *withPriority(zend_string *); + void reset(); + void toArray(zval *return_value); + zend_string *toString(); + ~Cookie(); +}; + } // namespace http namespace http2 { @@ -270,10 +307,12 @@ class Session { extern zend_class_entry *swoole_http_server_ce; extern zend_class_entry *swoole_http_request_ce; extern zend_class_entry *swoole_http_response_ce; +extern zend_class_entry *swoole_http_cookie_ce; swoole::http::Context *swoole_http_context_new(swoole::SessionId fd); swoole::http::Context *php_swoole_http_request_get_and_check_context(zval *zobject); swoole::http::Context *php_swoole_http_response_get_and_check_context(zval *zobject); +swoole::http::Cookie *php_swoole_http_get_cooke_safety(zval *zobject); /** * These class properties cannot be modified by the user before assignment, such as Swoole\\Http\\Request. diff --git a/ext-src/php_swoole_private.h b/ext-src/php_swoole_private.h index 7e84edffedd..3245ce877e8 100644 --- a/ext-src/php_swoole_private.h +++ b/ext-src/php_swoole_private.h @@ -262,6 +262,7 @@ void php_swoole_server_minit(int module_number); void php_swoole_server_port_minit(int module_number); void php_swoole_http_request_minit(int module_number); void php_swoole_http_response_minit(int module_number); +void php_swoole_http_cookie_minit(int module_number); void php_swoole_http_server_minit(int module_number); void php_swoole_http_server_coro_minit(int module_number); void php_swoole_websocket_server_minit(int module_number); diff --git a/ext-src/stubs/php_swoole_http_cookie.stub.php b/ext-src/stubs/php_swoole_http_cookie.stub.php new file mode 100644 index 00000000000..88fbb4d2b33 --- /dev/null +++ b/ext-src/stubs/php_swoole_http_cookie.stub.php @@ -0,0 +1,19 @@ + | + +----------------------------------------------------------------------+ + */ +#include "php_swoole_http_server.h" + +BEGIN_EXTERN_C() +#include "stubs/php_swoole_http_cookie_arginfo.h" +END_EXTERN_C() + +using HttpCookie = swoole::http::Cookie; + +#define ILLEGAL_COOKIE_CHARACTER_PRINT "\",\", \";\", \" \", \"\\t\", \"\\r\", \"\\n\", \"\\013\", or \"\\014\"" +#define ILLEGAL_COOKIE_CHARACTER ",; \t\r\n\013\014" + +static const zend_long maxValidSeconds = 253402300800; + +zend_class_entry *swoole_http_cookie_ce; +static zend_object_handlers swoole_http_cookie_handlers; + +struct HttpCookieObject { + HttpCookie *cookie; + zend_object std; +}; + +static sw_inline HttpCookieObject *php_swoole_http_cookie_fetch_object(zend_object *obj) { + return (HttpCookieObject *) ((char *) obj - swoole_http_cookie_handlers.offset); +} + +static HttpCookie *php_swoole_http_get_cookie(zval *zobject) { + return php_swoole_http_cookie_fetch_object(Z_OBJ_P(zobject))->cookie; +} + +HttpCookie *php_swoole_http_get_cooke_safety(zval *zobject) { + HttpCookie *cookie = php_swoole_http_get_cookie(zobject); + if (!cookie) { + swoole_set_last_error(SW_ERROR_HTTP_COOKIE_UNAVAILABLE); + return nullptr; + } + return cookie; +} + +void php_swoole_http_response_set_cookie(zval *zobject, HttpCookie *cookie) { + php_swoole_http_cookie_fetch_object(Z_OBJ_P(zobject))->cookie = cookie; +} + +static zend_object *php_swoole_http_cookie_create_object(zend_class_entry *ce) { + HttpCookieObject *httpCookieObject = (HttpCookieObject *) zend_object_alloc(sizeof(HttpCookieObject), ce); + zend_object_std_init(&httpCookieObject->std, ce); + object_properties_init(&httpCookieObject->std, ce); + httpCookieObject->std.handlers = &swoole_http_cookie_handlers; + return &httpCookieObject->std; +} + +static void php_swoole_http_cookie_free_object(zend_object *object) { + HttpCookieObject *httpCookieObject = php_swoole_http_cookie_fetch_object(object); + delete httpCookieObject->cookie; +} + +SW_EXTERN_C_BEGIN +static PHP_METHOD(swoole_http_cookie, __construct); +static PHP_METHOD(swoole_http_cookie, withName); +static PHP_METHOD(swoole_http_cookie, withValue); +static PHP_METHOD(swoole_http_cookie, withExpires); +static PHP_METHOD(swoole_http_cookie, withPath); +static PHP_METHOD(swoole_http_cookie, withDomain); +static PHP_METHOD(swoole_http_cookie, withSecure); +static PHP_METHOD(swoole_http_cookie, withHttpOnly); +static PHP_METHOD(swoole_http_cookie, withSameSite); +static PHP_METHOD(swoole_http_cookie, withPriority); +static PHP_METHOD(swoole_http_cookie, withPartitioned); +static PHP_METHOD(swoole_http_cookie, toArray); +static PHP_METHOD(swoole_http_cookie, toString); +static PHP_METHOD(swoole_http_cookie, reset); +SW_EXTERN_C_END + +// clang-format off +const zend_function_entry swoole_http_cookie_methods[] = +{ + PHP_ME(swoole_http_cookie, __construct, arginfo_class_Swoole_Http_Cookie___construct, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, withName, arginfo_class_Swoole_Http_Cookie_withName, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, withValue, arginfo_class_Swoole_Http_Cookie_withValue, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, withExpires, arginfo_class_Swoole_Http_Cookie_withExpires, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, withPath, arginfo_class_Swoole_Http_Cookie_withPath, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, withDomain, arginfo_class_Swoole_Http_Cookie_withDomain, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, withSecure, arginfo_class_Swoole_Http_Cookie_withSecure, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, withHttpOnly, arginfo_class_Swoole_Http_Cookie_withHttpOnly, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, withSameSite, arginfo_class_Swoole_Http_Cookie_withSameSite, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, withPriority, arginfo_class_Swoole_Http_Cookie_withPriority, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, withPartitioned, arginfo_class_Swoole_Http_Cookie_withPartitioned, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, toString, arginfo_class_Swoole_Http_Cookie_toString, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, toArray, arginfo_class_Swoole_Http_Cookie_toArray, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, reset, arginfo_class_Swoole_Http_Cookie_reset, ZEND_ACC_PUBLIC) + PHP_FE_END +}; +// clang-format on + +void php_swoole_http_cookie_minit(int module_number) { + SW_INIT_CLASS_ENTRY(swoole_http_cookie, "Swoole\\Http\\Cookie", nullptr, swoole_http_cookie_methods); + SW_SET_CLASS_NOT_SERIALIZABLE(swoole_http_cookie); + SW_SET_CLASS_CLONEABLE(swoole_http_cookie, sw_zend_class_clone_deny); + SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_http_cookie, sw_zend_class_unset_property_deny); + SW_SET_CLASS_CUSTOM_OBJECT(swoole_http_cookie, + php_swoole_http_cookie_create_object, + php_swoole_http_cookie_free_object, + HttpCookieObject, + std); +} + +#define HTTP_COOKIE_WITH_STR(field) \ + if (field) { \ + zend_string_release(field); \ + } \ + if (_##field && ZSTR_LEN(_##field) > 0) { \ + zend_string_addref(_##field); \ + field = _##field; \ + } else { \ + field = nullptr; \ + } \ + return this; + +HttpCookie *HttpCookie::withName(zend_string *_name) { + HTTP_COOKIE_WITH_STR(name); +} + +HttpCookie *HttpCookie::withValue(zend_string *_value) { + HTTP_COOKIE_WITH_STR(value); +} + +HttpCookie *HttpCookie::withDomain(zend_string *_domain) { + HTTP_COOKIE_WITH_STR(domain); +} + +HttpCookie *HttpCookie::withPath(zend_string *_path) { + HTTP_COOKIE_WITH_STR(path); +} + +HttpCookie *HttpCookie::withSameSite(zend_string *_sameSite) { + HTTP_COOKIE_WITH_STR(sameSite); +} + +HttpCookie *HttpCookie::withPriority(zend_string *_priority) { + HTTP_COOKIE_WITH_STR(priority); +} + +HttpCookie *HttpCookie::withExpires(zend_long _expires) { + expires = _expires; + return this; +} + +HttpCookie *HttpCookie::withSecure(zend_bool _secure) { + secure = _secure; + return this; +} + +HttpCookie *HttpCookie::withHttpOnly(zend_bool _httpOnly) { + httpOnly = _httpOnly; + return this; +} + +HttpCookie *HttpCookie::withPartitioned(zend_bool _partitioned) { + partitioned = _partitioned; + return this; +} + +zend_string *HttpCookie::toString() { + zend_string *date = nullptr; + if (name == nullptr || ZSTR_LEN(name) == 0) { + php_swoole_error(E_WARNING, "The name cannot be empty"); + return nullptr; + } + + if (strpbrk(ZSTR_VAL(name), "=" ILLEGAL_COOKIE_CHARACTER) != nullptr) { + php_swoole_error(E_WARNING, "The name cannot contain \"=\", " ILLEGAL_COOKIE_CHARACTER_PRINT); + return nullptr; + } + + smart_str_append(&buffer_, name); + + if (!value) { + smart_str_appends(&buffer_, "=deleted; expires="); + + date = php_format_date((char *) ZEND_STRL("D, d-M-Y H:i:s T"), 1, 0); + smart_str_append(&buffer_, date); + smart_str_appends(&buffer_, "; Max-Age=0"); + zend_string_free(date); + } else { + if (!encode_ && strpbrk(ZSTR_VAL(value), ILLEGAL_COOKIE_CHARACTER) != nullptr) { + php_swoole_error(E_WARNING, "The value cannot contain " ILLEGAL_COOKIE_CHARACTER_PRINT); + return nullptr; + } + + smart_str_appendc(&buffer_, '='); + + if (encode_) { + zend_string *encoded_value = php_url_encode(ZSTR_VAL(value), ZSTR_LEN(value)); + smart_str_append(&buffer_, encoded_value); + zend_string_free(encoded_value); + } else { + smart_str_append(&buffer_, value); + } + + if (expires > 0) { + if (expires >= maxValidSeconds) { + php_swoole_error(E_WARNING, "The expires cannot have a year greater than 9999"); + return nullptr; + } + smart_str_appends(&buffer_, "; expires="); + date = php_format_date((char *) ZEND_STRL("D, d-M-Y H:i:s T"), expires, 0); + smart_str_append(&buffer_, date); + smart_str_appends(&buffer_, "; Max-Age="); + + double diff = difftime(expires, php_time()); + smart_str_append_long(&buffer_, (zend_long) (diff >= 0 ? diff : 0)); + zend_string_free(date); + } + + if (path && ZSTR_LEN(path) > 0) { + if (strpbrk(ZSTR_VAL(path), ILLEGAL_COOKIE_CHARACTER) != NULL) { + php_swoole_error(E_WARNING, "The path option cannot contain " ILLEGAL_COOKIE_CHARACTER_PRINT); + return nullptr; + } + smart_str_appends(&buffer_, "; path="); + smart_str_append(&buffer_, path); + } + + if (domain && ZSTR_LEN(domain) > 0) { + if (strpbrk(ZSTR_VAL(domain), ILLEGAL_COOKIE_CHARACTER) != NULL) { + php_swoole_error(E_WARNING, "The domain option cannot contain " ILLEGAL_COOKIE_CHARACTER_PRINT); + return nullptr; + } + smart_str_appends(&buffer_, "; domain="); + smart_str_append(&buffer_, domain); + } + + if (secure) { + smart_str_appends(&buffer_, "; secure"); + } + + if (httpOnly) { + smart_str_appends(&buffer_, "; HttpOnly"); + } + + if (sameSite && ZSTR_LEN(sameSite) > 0) { + smart_str_appends(&buffer_, "; SameSite="); + smart_str_append(&buffer_, sameSite); + } + + if (priority && ZSTR_LEN(priority) > 0) { + smart_str_appends(&buffer_, "; Priority="); + smart_str_append(&buffer_, priority); + } + + if (partitioned) { + smart_str_appends(&buffer_, "; Partitioned"); + } + } + + return smart_str_extract(&buffer_); +} + +void HttpCookie::reset() { + expires = 0; + secure = false; + httpOnly = false; + partitioned = false; + encode_ = true; + + if (name) { + zend_string_release(name); + name = nullptr; + } + + if (value) { + zend_string_release(value); + value = nullptr; + } + + if (path) { + zend_string_release(path); + path = nullptr; + } + + if (domain) { + zend_string_release(domain); + domain = nullptr; + } + + if (sameSite) { + zend_string_release(sameSite); + sameSite = nullptr; + } + + if (priority) { + zend_string_release(priority); + priority = nullptr; + } + + smart_str_free_ex(&buffer_, false); +} + +#define HTTP_COOKIE_ADD_STR_TO_ARRAY(field) \ + if (field) { \ + add_assoc_str(return_value, #field, field); \ + } else { \ + add_assoc_string(return_value, #field, ""); \ + } + +void HttpCookie::toArray(zval *return_value) { + array_init(return_value); + + HTTP_COOKIE_ADD_STR_TO_ARRAY(name); + HTTP_COOKIE_ADD_STR_TO_ARRAY(value); + HTTP_COOKIE_ADD_STR_TO_ARRAY(path); + HTTP_COOKIE_ADD_STR_TO_ARRAY(domain); + HTTP_COOKIE_ADD_STR_TO_ARRAY(sameSite); + HTTP_COOKIE_ADD_STR_TO_ARRAY(priority); + + add_assoc_bool(return_value, "encode", encode_); + add_assoc_long(return_value, "expires", expires); + add_assoc_bool(return_value, "secure", secure); + add_assoc_bool(return_value, "httpOnly", httpOnly); + add_assoc_bool(return_value, "partitioned", partitioned); +} + +HttpCookie::~Cookie() { + reset(); +} + +static PHP_METHOD(swoole_http_cookie, __construct) { + zend_bool encode = true; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(encode) + ZEND_PARSE_PARAMETERS_END(); + + php_swoole_http_response_set_cookie(ZEND_THIS, new HttpCookie(encode)); +} + +#define PHP_METHOD_HTTP_COOKIE_WITH_STR(field) \ + zend_string *field; \ + HttpCookie *cookie = php_swoole_http_get_cooke_safety(ZEND_THIS); \ + \ + ZEND_PARSE_PARAMETERS_START(1, 1) \ + Z_PARAM_STR(field) \ + ZEND_PARSE_PARAMETERS_END(); \ + \ + cookie->with##field(field); \ + RETURN_ZVAL(ZEND_THIS, 1, 0); + +#define PHP_METHOD_HTTP_COOKIE_WITH_BOOL(field) \ + zend_bool field = false; \ + HttpCookie *cookie = php_swoole_http_get_cooke_safety(ZEND_THIS); \ + \ + ZEND_PARSE_PARAMETERS_START(0, 1) \ + Z_PARAM_OPTIONAL \ + Z_PARAM_BOOL(field) \ + ZEND_PARSE_PARAMETERS_END(); \ + \ + cookie->with##field(field); \ + RETURN_ZVAL(ZEND_THIS, 1, 0); + +static PHP_METHOD(swoole_http_cookie, withName) { + PHP_METHOD_HTTP_COOKIE_WITH_STR(Name); +} + +static PHP_METHOD(swoole_http_cookie, withValue) { + PHP_METHOD_HTTP_COOKIE_WITH_STR(Value); +} + +static PHP_METHOD(swoole_http_cookie, withExpires) { + zend_long expires = 0; + HttpCookie *cookie = php_swoole_http_get_cooke_safety(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(expires) + ZEND_PARSE_PARAMETERS_END(); + + cookie->withExpires(expires); + RETURN_ZVAL(ZEND_THIS, 1, 0); +} + +static PHP_METHOD(swoole_http_cookie, withPath) { + PHP_METHOD_HTTP_COOKIE_WITH_STR(Path); +} + +static PHP_METHOD(swoole_http_cookie, withDomain) { + PHP_METHOD_HTTP_COOKIE_WITH_STR(Domain); +} + +static PHP_METHOD(swoole_http_cookie, withSecure) { + PHP_METHOD_HTTP_COOKIE_WITH_BOOL(Secure); +} + +static PHP_METHOD(swoole_http_cookie, withHttpOnly) { + PHP_METHOD_HTTP_COOKIE_WITH_BOOL(HttpOnly); +} + +static PHP_METHOD(swoole_http_cookie, withSameSite) { + PHP_METHOD_HTTP_COOKIE_WITH_STR(SameSite); +} + +static PHP_METHOD(swoole_http_cookie, withPriority) { + PHP_METHOD_HTTP_COOKIE_WITH_STR(Priority); +} + +static PHP_METHOD(swoole_http_cookie, withPartitioned) { + PHP_METHOD_HTTP_COOKIE_WITH_BOOL(Partitioned); +} + +static PHP_METHOD(swoole_http_cookie, toString) { + auto cookie = php_swoole_http_get_cooke_safety(ZEND_THIS); + auto cookie_str = cookie->toString(); + if (!cookie_str) { + cookie->reset(); + RETURN_FALSE; + } + ZVAL_STR(return_value, cookie_str); +} + +static PHP_METHOD(swoole_http_cookie, toArray) { + php_swoole_http_get_cooke_safety(ZEND_THIS)->toArray(return_value); +} + +static PHP_METHOD(swoole_http_cookie, reset) { + php_swoole_http_get_cooke_safety(ZEND_THIS)->reset(); +} diff --git a/ext-src/swoole_http_response.cc b/ext-src/swoole_http_response.cc index fdfe0c2b613..5f412d98edd 100644 --- a/ext-src/swoole_http_response.cc +++ b/ext-src/swoole_http_response.cc @@ -38,6 +38,7 @@ using swoole::coroutine::Socket; using HttpResponse = swoole::http::Response; using HttpContext = swoole::http::Context; +using HttpCookie = swoole::http::Cookie; namespace WebSocket = swoole::websocket; namespace HttpServer = swoole::http_server; @@ -157,24 +158,25 @@ SW_EXTERN_C_END // clang-format off const zend_function_entry swoole_http_response_methods[] = { - PHP_ME(swoole_http_response, initHeader, arginfo_class_Swoole_Http_Response_initHeader, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, isWritable, arginfo_class_Swoole_Http_Response_isWritable, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, cookie, arginfo_class_Swoole_Http_Response_cookie, ZEND_ACC_PUBLIC) - PHP_MALIAS(swoole_http_response, setCookie, cookie, arginfo_class_Swoole_Http_Response_cookie, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, rawcookie, arginfo_class_Swoole_Http_Response_cookie, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, status, arginfo_class_Swoole_Http_Response_status, ZEND_ACC_PUBLIC) - PHP_MALIAS(swoole_http_response, setStatusCode, status, arginfo_class_Swoole_Http_Response_status, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, header, arginfo_class_Swoole_Http_Response_header, ZEND_ACC_PUBLIC) - PHP_MALIAS(swoole_http_response, setHeader, header, arginfo_class_Swoole_Http_Response_header, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, trailer, arginfo_class_Swoole_Http_Response_trailer, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, ping, arginfo_class_Swoole_Http_Response_ping, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, goaway, arginfo_class_Swoole_Http_Response_goaway, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, write, arginfo_class_Swoole_Http_Response_write, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, end, arginfo_class_Swoole_Http_Response_end, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, sendfile, arginfo_class_Swoole_Http_Response_sendfile, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, redirect, arginfo_class_Swoole_Http_Response_redirect, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, detach, arginfo_class_Swoole_Http_Response_detach, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_response, create, arginfo_class_Swoole_Http_Response_create, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) + PHP_ME(swoole_http_response, initHeader, arginfo_class_Swoole_Http_Response_initHeader, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, isWritable, arginfo_class_Swoole_Http_Response_isWritable, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, cookie, arginfo_class_Swoole_Http_Response_cookie, ZEND_ACC_PUBLIC) + PHP_MALIAS(swoole_http_response, setCookie, cookie, arginfo_class_Swoole_Http_Response_cookie, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, rawcookie, arginfo_class_Swoole_Http_Response_cookie, ZEND_ACC_PUBLIC) + PHP_MALIAS(swoole_http_response, setRawCookie, rawcookie, arginfo_class_Swoole_Http_Response_cookie, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, status, arginfo_class_Swoole_Http_Response_status, ZEND_ACC_PUBLIC) + PHP_MALIAS(swoole_http_response, setStatusCode, status, arginfo_class_Swoole_Http_Response_status, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, header, arginfo_class_Swoole_Http_Response_header, ZEND_ACC_PUBLIC) + PHP_MALIAS(swoole_http_response, setHeader, header, arginfo_class_Swoole_Http_Response_header, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, trailer, arginfo_class_Swoole_Http_Response_trailer, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, ping, arginfo_class_Swoole_Http_Response_ping, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, goaway, arginfo_class_Swoole_Http_Response_goaway, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, write, arginfo_class_Swoole_Http_Response_write, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, end, arginfo_class_Swoole_Http_Response_end, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, sendfile, arginfo_class_Swoole_Http_Response_sendfile, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, redirect, arginfo_class_Swoole_Http_Response_redirect, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, detach, arginfo_class_Swoole_Http_Response_detach, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_response, create, arginfo_class_Swoole_Http_Response_create, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) /** * WebSocket */ @@ -962,154 +964,75 @@ static PHP_METHOD(swoole_http_response, sendfile) { } } -static void php_swoole_http_response_cookie(INTERNAL_FUNCTION_PARAMETERS, const bool url_encode) { - char *name = nullptr, *value = nullptr, *path = nullptr, *domain = nullptr, *samesite = nullptr, - *priority = nullptr; +static bool inline php_swoole_http_response_create_cookie(HttpCookie *cookie, zval *zobject) { + HttpContext *ctx = php_swoole_http_response_get_and_check_context(zobject); + + zend_string *cookie_str = cookie->toString(); + if (!cookie_str) { + cookie->reset(); + return false; + } + + add_next_index_str( + swoole_http_init_and_read_property( + swoole_http_response_ce, ctx->response.zobject, &ctx->response.zcookie, SW_ZSTR_KNOWN(SW_ZEND_STR_COOKIE)), + cookie_str); + + return true; +} + +static void php_swoole_http_response_set_cookie(INTERNAL_FUNCTION_PARAMETERS, const bool encode) { + zval *name_or_object; + zend_string *value = nullptr, *path = nullptr, *domain = nullptr, *sameSite = nullptr, *priority = nullptr; zend_long expires = 0; - size_t name_len, value_len = 0, path_len = 0, domain_len = 0, samesite_len = 0, priority_len = 0; - zend_bool secure = 0, httponly = 0; + zend_bool secure = false, httpOnly = false, partitioned = false; + bool result; - ZEND_PARSE_PARAMETERS_START(1, 9) - Z_PARAM_STRING(name, name_len) + ZEND_PARSE_PARAMETERS_START(1, 10) + Z_PARAM_ZVAL(name_or_object) Z_PARAM_OPTIONAL - Z_PARAM_STRING(value, value_len) + Z_PARAM_STR(value) Z_PARAM_LONG(expires) - Z_PARAM_STRING(path, path_len) - Z_PARAM_STRING(domain, domain_len) + Z_PARAM_STR(path) + Z_PARAM_STR(domain) Z_PARAM_BOOL(secure) - Z_PARAM_BOOL(httponly) - Z_PARAM_STRING(samesite, samesite_len) - Z_PARAM_STRING(priority, priority_len) + Z_PARAM_BOOL(httpOnly) + Z_PARAM_STR(sameSite) + Z_PARAM_STR(priority) + Z_PARAM_BOOL(partitioned) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); - HttpContext *ctx = php_swoole_http_response_get_and_check_context(ZEND_THIS); - if (UNEXPECTED(!ctx)) { - RETURN_FALSE; - } - - if (name_len > 0 && strpbrk(name, "=,; \t\r\n\013\014") != nullptr) { - php_swoole_error(E_WARNING, "Cookie names can't contain any of the following '=,; \\t\\r\\n\\013\\014'"); - RETURN_FALSE; - } - - if (!url_encode && swoole_http_has_crlf(value, value_len)) { - RETURN_FALSE; - } - - char *cookie = nullptr, *date = nullptr; - size_t cookie_size = name_len + 1; // add 1 for null char - cookie_size += 50; // strlen("; expires=Fri, 31-Dec-9999 23:59:59 GMT; Max-Age=0") - if (value_len == 0) { - cookie_size += 8; // strlen("=deleted") - } - if (expires > 0) { - // Max-Age will be no longer than 12 digits since the - // maximum expires is Fri, 31-Dec-9999 23:59:59 GMT. - cookie_size += 11; - } - if (path_len > 0) { - cookie_size += path_len + 7; // strlen("; path=") - } - if (domain_len > 0) { - cookie_size += domain_len + 9; // strlen("; domain=") - } - if (secure) { - cookie_size += 8; // strlen("; secure") - } - if (httponly) { - cookie_size += 10; // strlen("; httponly") - } - if (samesite_len > 0) { - cookie_size += samesite_len + 11; // strlen("; samesite=") - } - if (priority_len > 0) { - cookie_size += priority_len + 11; // strlen("; priority=") - } - - if (value_len == 0) { - cookie = (char *) emalloc(cookie_size); - date = php_swoole_format_date((char *) ZEND_STRL("D, d-M-Y H:i:s T"), 1, 0); - snprintf(cookie, cookie_size, "%s=deleted; expires=%s", name, date); - efree(date); - strlcat(cookie, "; Max-Age=0", cookie_size); + if (ZVAL_IS_STRING(name_or_object)) { + HttpCookie cookie(encode); + (&cookie) + ->withName(Z_STR_P(name_or_object)) + ->withValue(value) + ->withExpires(expires) + ->withPath(path) + ->withDomain(domain) + ->withSecure(secure) + ->withHttpOnly(httpOnly) + ->withSameSite(sameSite) + ->withPriority(priority) + ->withPartitioned(partitioned); + result = php_swoole_http_response_create_cookie(&cookie, ZEND_THIS); + } else if (ZVAL_IS_OBJECT(name_or_object)) { + HttpCookie *cookie = php_swoole_http_get_cooke_safety(name_or_object); + result = php_swoole_http_response_create_cookie(cookie, ZEND_THIS); } else { - if (url_encode) { - char *encoded_value; - size_t encoded_value_len; - encoded_value = php_swoole_url_encode(value, value_len, &encoded_value_len); - cookie_size += encoded_value_len; - cookie = (char *) emalloc(cookie_size); - sw_snprintf(cookie, cookie_size, "%s=%s", name, encoded_value); - efree(encoded_value); - } else { - cookie_size += value_len; - cookie = (char *) emalloc(cookie_size); - sw_snprintf(cookie, cookie_size, "%s=%s", name, value); - } - if (expires > 0) { - strlcat(cookie, "; expires=", cookie_size); - date = php_swoole_format_date((char *) ZEND_STRL("D, d-M-Y H:i:s T"), expires, 0); - const char *p = (const char *) zend_memrchr(date, '-', strlen(date)); - if (!p || *(p + 5) != ' ') { - php_swoole_error(E_WARNING, "Expiry date can't be a year greater than 9999"); - efree(date); - efree(cookie); - RETURN_FALSE; - } - strlcat(cookie, date, cookie_size); - efree(date); - - strlcat(cookie, "; Max-Age=", cookie_size); - - double diff = difftime(expires, php_time()); - if (diff < 0) { - diff = 0; - } - - zval max_age; - ZVAL_DOUBLE(&max_age, diff); - convert_to_string(&max_age); - strlcat(cookie, Z_STRVAL_P(&max_age), cookie_size); - zval_ptr_dtor(&max_age); - } - } - if (path_len > 0) { - strlcat(cookie, "; path=", cookie_size); - strlcat(cookie, path, cookie_size); - } - if (domain_len > 0) { - strlcat(cookie, "; domain=", cookie_size); - strlcat(cookie, domain, cookie_size); - } - if (secure) { - strlcat(cookie, "; secure", cookie_size); - } - if (httponly) { - strlcat(cookie, "; httponly", cookie_size); + php_swoole_error(E_WARNING, "The first argument must be a string or an cookie object"); + result = false; } - if (samesite_len > 0) { - strlcat(cookie, "; samesite=", cookie_size); - strlcat(cookie, samesite, cookie_size); - } - if (priority_len > 0) { - strlcat(cookie, "; priority=", cookie_size); - strlcat(cookie, priority, cookie_size); - } - add_next_index_stringl( - swoole_http_init_and_read_property( - swoole_http_response_ce, ctx->response.zobject, &ctx->response.zcookie, ZEND_STRL("cookie")), - cookie, - strlen(cookie)); - efree(cookie); - RETURN_TRUE; + + RETURN_BOOL(result); } static PHP_METHOD(swoole_http_response, cookie) { - php_swoole_http_response_cookie(INTERNAL_FUNCTION_PARAM_PASSTHRU, true); + php_swoole_http_response_set_cookie(INTERNAL_FUNCTION_PARAM_PASSTHRU, true); } static PHP_METHOD(swoole_http_response, rawcookie) { - php_swoole_http_response_cookie(INTERNAL_FUNCTION_PARAM_PASSTHRU, false); + php_swoole_http_response_set_cookie(INTERNAL_FUNCTION_PARAM_PASSTHRU, false); } static PHP_METHOD(swoole_http_response, status) { diff --git a/include/swoole_error.h b/include/swoole_error.h index 0bd69f595c1..d5746534f5a 100644 --- a/include/swoole_error.h +++ b/include/swoole_error.h @@ -132,6 +132,7 @@ enum swErrorCode { SW_ERROR_HTTP_PROXY_BAD_RESPONSE, SW_ERROR_HTTP_CONFLICT_HEADER, SW_ERROR_HTTP_CONTEXT_UNAVAILABLE, + SW_ERROR_HTTP_COOKIE_UNAVAILABLE, SW_ERROR_WEBSOCKET_BAD_CLIENT = 8501, SW_ERROR_WEBSOCKET_BAD_OPCODE, diff --git a/tests/start.sh b/tests/start.sh index 43cdac2e73a..bd636afda4c 100755 --- a/tests/start.sh +++ b/tests/start.sh @@ -47,6 +47,10 @@ else fi else glob="$@" + if [ $(expr substr "$glob" 1 6) = "tests/" ]; then + # 去掉 tests/ 前缀 + glob="${glob#tests/}" + fi fi fi diff --git a/tests/swoole_http_client_coro/issue_2664.phpt b/tests/swoole_http_client_coro/issue_2664.phpt index 804a55609f5..4c9f902889e 100644 --- a/tests/swoole_http_client_coro/issue_2664.phpt +++ b/tests/swoole_http_client_coro/issue_2664.phpt @@ -36,9 +36,9 @@ array(4) { [0]=> string(91) "key1=val1; expires=%s; Max-Age=84600; path=/; domain=id.test.com" [1]=> - string(87) "key1=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=test.com" + string(62) "key1=deleted; expires=%s; Max-Age=0" [2]=> string(91) "key2=val2; expires=%s; Max-Age=84600; path=/; domain=id.test.com" [3]=> - string(87) "key2=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; domain=test.com" + string(62) "key2=deleted; expires=%s; Max-Age=0" } diff --git a/tests/swoole_http_server/cookieAlias.phpt b/tests/swoole_http_server/cookieAlias.phpt new file mode 100644 index 00000000000..57946ffa6aa --- /dev/null +++ b/tests/swoole_http_server/cookieAlias.phpt @@ -0,0 +1,56 @@ +--TEST-- +swoole_http_cookie: cookie alias +--SKIPIF-- + +--FILE-- +parentFunc = function () use ($pm) { + Co\Run(function () use ($pm) { + var_dump(httpRequest("http://127.0.0.1:{$pm->getFreePort()}")['set_cookie_headers']); + }); + $pm->kill(); +}; +$pm->childFunc = function () use ($pm) { + $server = new Swoole\Http\Server('0.0.0.0', $pm->getFreePort(), SWOOLE_BASE); + $server->set(['log_file' => '/dev/null']); + $server->on('workerStart', function () use ($pm) { + $pm->wakeup(); + }); + $server->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) use ($pm) { + $cookie = new Swoole\Http\Cookie(); + $cookie->withName('key1') + ->withValue('val1') + ->withExpires(time() + 84600) + ->withPath('/') + ->withDomain('id.test.com') + ->withSecure(true) + ->withHttpOnly(true) + ->withSameSite('None') + ->withPriority('High') + ->withPartitioned(true); + $response->setCookie($cookie); + $response->setCookie('key1', 'val1', time() + 84600, '/', 'id.test.com', true, true, 'None', 'High', true); + $response->setRawCookie('key1', 'val1', time() + 84600, '/', 'id.test.com', true, true, 'None', 'High', true); + + $cookie->withValue(''); + $response->setCookie($cookie); + $response->end("

Hello Swoole. #" . rand(1000, 9999) . "

"); + }); + $server->start(); +}; +$pm->childFirst(); +$pm->run(); +?> +--EXPECTF-- +array(4) { + [0]=> + string(152) "key1=val1; expires=%s; Max-Age=84600; path=/; domain=id.test.com; secure; HttpOnly; SameSite=None; Priority=High; Partitioned" + [1]=> + string(152) "key1=val1; expires=%s; path=/; domain=id.test.com; secure; HttpOnly; SameSite=None; Priority=High; Partitioned" + [2]=> + string(152) "key1=val1; expires=%s; Max-Age=84600; path=/; domain=id.test.com; secure; HttpOnly; SameSite=None; Priority=High; Partitioned" + [3]=> + string(62) "key1=deleted; expires=%s; Max-Age=0" +} diff --git a/tests/swoole_http_server/cookie_samesite.phpt b/tests/swoole_http_server/cookie_samesite.phpt index 939ec2cf9a4..17b6707ee09 100644 --- a/tests/swoole_http_server/cookie_samesite.phpt +++ b/tests/swoole_http_server/cookie_samesite.phpt @@ -12,7 +12,7 @@ $pm->parentFunc = function () use ($pm) { $cli->get('/'); Assert::assert($cli->set_cookie_headers === [ - 'a=123; samesite=Lax', + 'a=123; SameSite=Lax', ] ); }); diff --git a/tests/swoole_http_server/cookie_vs_rawcookie.phpt b/tests/swoole_http_server/cookie_vs_rawcookie.phpt index 172f32815e1..3767d198460 100644 --- a/tests/swoole_http_server/cookie_vs_rawcookie.phpt +++ b/tests/swoole_http_server/cookie_vs_rawcookie.phpt @@ -10,14 +10,13 @@ $pm->parentFunc = function () use ($pm) { go(function () use ($pm) { $cli = new Swoole\Coroutine\Http\Client('127.0.0.1', $pm->getFreePort()); $cookie = '123_,; abc'; - Assert::assert($cli->get('/?cookie=' . urlencode($cookie))); + $cookie_encoded = urlencode($cookie); + Assert::assert($cli->get('/?cookie=' . $cookie_encoded)); Assert::same($cli->statusCode, 200); - Assert::assert($cli->set_cookie_headers === - [ - 'cookie=' . urlencode($cookie), - 'rawcookie=' . $cookie, - ] - ); + Assert::eq($cli->set_cookie_headers, [ + 'cookie=' . $cookie_encoded, + 'rawcookie=' . $cookie_encoded, + ]); }); for ($i = MAX_CONCURRENCY_LOW; $i--;) { go(function () use ($pm) { @@ -41,9 +40,9 @@ $pm->childFunc = function () use ($pm) { $http = new Swoole\Http\Server('0.0.0.0', $pm->getFreePort(), SWOOLE_BASE); $http->set(['worker_num' => 1, 'log_file' => '/dev/null']); $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) { - $request->get['cookie'] = urldecode($request->get['cookie']); - $response->cookie('cookie', $request->get['cookie']); - $response->rawcookie('rawcookie', $request->get['cookie']); + $cookie = $request->get['cookie']; + $response->cookie('cookie', $cookie); + $response->rawcookie('rawcookie', urlencode($cookie)); $response->end(); }); $http->start(); @@ -51,5 +50,5 @@ $pm->childFunc = function () use ($pm) { $pm->childFirst(); $pm->run(); ?> ---EXPECT-- +--EXPECTF-- SUCCESS diff --git a/tests/swoole_http_server/max-age.phpt b/tests/swoole_http_server/max-age.phpt index fef9744979a..610f1faa2da 100644 --- a/tests/swoole_http_server/max-age.phpt +++ b/tests/swoole_http_server/max-age.phpt @@ -18,8 +18,8 @@ $pm->parentFunc = function () use ($pm) { var_dump(strpos($cookies[0], 'path=/') !== false); var_dump(strpos($cookies[0], 'domain=example.com') !== false); var_dump(strpos($cookies[0], 'secure') !== false); - var_dump(strpos($cookies[0], 'httponly') !== false); - var_dump(strpos($cookies[0], 'samesite=None') !== false); + var_dump(strpos($cookies[0], 'HttpOnly') !== false); + var_dump(strpos($cookies[0], 'SameSite=None') !== false); var_dump(strpos($cookies[1], 'test=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT') !== false); var_dump(strpos($cookies[1], 'Max-Age=0') !== false); }); diff --git a/tests/swoole_http_server/new_cookie.phpt b/tests/swoole_http_server/new_cookie.phpt new file mode 100644 index 00000000000..17fc34117ce --- /dev/null +++ b/tests/swoole_http_server/new_cookie.phpt @@ -0,0 +1,74 @@ +--TEST-- +swoole_http_server: new cookie +--SKIPIF-- + +--FILE-- +withName('test') + ->withValue('123456789') + ->withExpires(time() + 3600) + ->withPath('/path') + ->withDomain('example.com') + ->withSecure(true) + ->withHttpOnly(true) + ->withSameSite('None'); + +var_dump($cookie->toArray()); +$cookie->reset(); +var_dump($cookie->toArray()); +?> +--EXPECTF-- +array(11) { + ["name"]=> + string(4) "test" + ["value"]=> + string(9) "123456789" + ["path"]=> + string(5) "/path" + ["domain"]=> + string(11) "example.com" + ["sameSite"]=> + string(4) "None" + ["priority"]=> + string(0) "" + ["encode"]=> + bool(true) + ["expires"]=> + int(%d) + ["secure"]=> + bool(true) + ["httpOnly"]=> + bool(true) + ["partitioned"]=> + bool(false) +} +array(11) { + ["name"]=> + string(0) "" + ["value"]=> + string(0) "" + ["path"]=> + string(0) "" + ["domain"]=> + string(0) "" + ["sameSite"]=> + string(0) "" + ["priority"]=> + string(0) "" + ["encode"]=> + bool(true) + ["expires"]=> + int(0) + ["secure"]=> + bool(false) + ["httpOnly"]=> + bool(false) + ["partitioned"]=> + bool(false) +} diff --git a/tests/swoole_http_server/objectCookie.phpt b/tests/swoole_http_server/objectCookie.phpt new file mode 100644 index 00000000000..3626a6e047e --- /dev/null +++ b/tests/swoole_http_server/objectCookie.phpt @@ -0,0 +1,49 @@ +--TEST-- +swoole_http_cookie: new cookie +--SKIPIF-- + +--FILE-- +parentFunc = function () use ($pm) { + Co\Run(function () use ($pm) { + var_dump(httpRequest("http://127.0.0.1:{$pm->getFreePort()}")['set_cookie_headers']); + }); + $pm->kill(); +}; +$pm->childFunc = function () use ($pm) { + $server = new Swoole\Http\Server('0.0.0.0', $pm->getFreePort(), SWOOLE_BASE); + $server->set(['log_file' => '/dev/null']); + $server->on('workerStart', function () use ($pm) { + $pm->wakeup(); + }); + $server->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) use ($pm) { + $cookie = new Swoole\Http\Cookie(); + $cookie->withName('key1') + ->withValue('val1') + ->withExpires(time() + 84600) + ->withPath('/') + ->withDomain('id.test.com') + ->withSecure(true) + ->withHttpOnly(true) + ->withSameSite('None') + ->withPriority('High') + ->withPartitioned(true); + $response->setCookie($cookie); + $cookie->withValue(''); + $response->setCookie($cookie); + $response->end("

Hello Swoole. #" . rand(1000, 9999) . "

"); + }); + $server->start(); +}; +$pm->childFirst(); +$pm->run(); +?> +--EXPECTF-- +array(2) { + [0]=> + string(152) "key1=val1; expires=%s; Max-Age=84600; path=/; domain=id.test.com; secure; HttpOnly; SameSite=None; Priority=High; Partitioned" + [1]=> + string(62) "key1=deleted; expires=%s; Max-Age=0" +} diff --git a/tests/swoole_http_server/objectCookieMemory.phpt b/tests/swoole_http_server/objectCookieMemory.phpt new file mode 100644 index 00000000000..884306bf050 --- /dev/null +++ b/tests/swoole_http_server/objectCookieMemory.phpt @@ -0,0 +1,77 @@ +--TEST-- +swoole_http_cookie: new cookie memory +--SKIPIF-- + +--FILE-- +parentFunc = function () use ($pm) { + Swoole\Coroutine\run(function () use ($pm) { + httpRequest("http://127.0.0.1:{$pm->getFreePort()}"); + httpRequest("http://127.0.0.1:{$pm->getFreePort()}"); + httpRequest("http://127.0.0.1:{$pm->getFreePort()}"); + httpRequest("http://127.0.0.1:{$pm->getFreePort()}"); + httpRequest("http://127.0.0.1:{$pm->getFreePort()}"); + }); + echo "DONE\n"; + $pm->kill(); +}; + +$pm->childFunc = function () use ($pm) { + $http = new Server('127.0.0.1', $pm->getFreePort(), SWOOLE_BASE); + $http->set([ + 'log_file' => '/dev/null', + ]); + $http->on('workerStart', function () use ($pm) { + $pm->wakeup(); + }); + $http->on('request', function (Request $request, Response $response) use ($http) { + $previous = memory_get_usage(); + $cookie = new Swoole\Http\Cookie(); + $i = 10000; + while($i--) { + $cookie->withName('key1') + ->withValue('val1') + ->withExpires(time() + 84600) + ->withPath('/') + ->withDomain('id.test.com') + ->withSecure(true) + ->withHttpOnly(true) + ->withSameSite('None') + ->withPriority('High') + ->withPartitioned(true); + } + + global $previous; + global $item; + $current = memory_get_usage(); + $stats = [ + 'id' => $http->getWorkerId(), + 'item' => $item++, + 'prev_mem' => $previous, + 'curr_mem' => $current, + 'diff_mem' => $current - $previous, + ]; + $previous = $current; + + echo json_encode($stats), PHP_EOL; + $response->end('test response'); + }); + $http->start(); +}; +$pm->childFirst(); +$pm->run(); +?> +--EXPECTF-- +{"id":%d,"item":null,"prev_mem":null,"curr_mem":%d,"diff_mem":%d} +{"id":%d,"item":%d,"prev_mem":%d,"curr_mem":%d,"diff_mem":%d} +{"id":%d,"item":%d,"prev_mem":%d,"curr_mem":%d,"diff_mem":0} +{"id":%d,"item":%d,"prev_mem":%d,"curr_mem":%d,"diff_mem":0} +{"id":%d,"item":%d,"prev_mem":%d,"curr_mem":%d,"diff_mem":0} +DONE diff --git a/tests/swoole_http_server/rawCookie.phpt b/tests/swoole_http_server/rawCookie.phpt index ed2be373e86..59a0e2e33b9 100644 --- a/tests/swoole_http_server/rawCookie.phpt +++ b/tests/swoole_http_server/rawCookie.phpt @@ -43,7 +43,7 @@ $pm->childFunc = function () use ($pm, $simple_http_server) { $httpOnly = true; // string $name [, string $value = "" [, int $expire = 0 [, string $path = "" [, string $domain = "" [, bool $secure = false [, bool $httponly = false ]]]]]] $response->cookie($name, $value, $expire, $path, $domain, $secure, $httpOnly); - $expect = "name=value; path=/; httponly"; + $expect = "name=value; path=/; HttpOnly"; Assert::assert(in_array($expect, $response->cookie, true)); $response->cookie($name, $value, $expire, $path, $domain, $secure, $httpOnly); $response->rawcookie("rawcontent", $request->rawcontent()); diff --git a/tests/swoole_http_server_coro/check_cookie_crlf.phpt b/tests/swoole_http_server_coro/check_cookie_crlf.phpt index c114a4632ec..5a6a7d26404 100644 --- a/tests/swoole_http_server_coro/check_cookie_crlf.phpt +++ b/tests/swoole_http_server_coro/check_cookie_crlf.phpt @@ -54,5 +54,5 @@ $pm->childFirst(); $pm->run(); ?> --EXPECTF-- -Warning: Swoole\Http\Response::rawcookie(): Header may not contain more than a single header, new line detected in %s +Warning: Swoole\Http\Response::rawcookie(): The value cannot contain ",", ";", " ", "\t", "\r", "\n", "\013", or "\014" in %s DONE