From 5568707acac8cf0d694ae89f89831605197f2086 Mon Sep 17 00:00:00 2001 From: NathanFreeman <1056159381@qq.com> Date: Tue, 9 Jul 2024 23:53:49 +0800 Subject: [PATCH 1/8] new cookie --- ext-src/php_swoole.cc | 1 + ext-src/php_swoole_http.h | 108 ++++++ ext-src/php_swoole_private.h | 1 + ext-src/stubs/php_swoole_http_cookie.stub.php | 18 + .../stubs/php_swoole_http_cookie_arginfo.h | 51 +++ .../stubs/php_swoole_http_response.stub.php | 4 +- .../stubs/php_swoole_http_response_arginfo.h | 12 +- ext-src/swoole_http_cookie.cc | 335 ++++++++++++++++++ ext-src/swoole_http_response.cc | 164 +++------ include/swoole_error.h | 1 + tests/swoole_http2_client_coro/cookies.phpt | 5 +- tests/swoole_http2_server_coro/cookies.phpt | 5 +- tests/swoole_http_client_coro/issue_2664.phpt | 40 ++- tests/swoole_http_server/bug_2368.phpt | 5 +- tests/swoole_http_server/bug_5146.phpt | 11 +- tests/swoole_http_server/cookie_delete.phpt | 53 ++- tests/swoole_http_server/cookie_samesite.phpt | 13 +- .../cookie_vs_rawcookie.phpt | 17 +- tests/swoole_http_server/max-age.phpt | 21 +- tests/swoole_http_server/new_cookie.phpt | 64 ++++ tests/swoole_http_server/rawCookie.phpt | 23 +- .../too_many_special_chars_in_cookie.phpt | 8 +- .../check_cookie_crlf.phpt | 13 +- tests/swoole_http_server_coro/websocket.phpt | 7 +- ...t_cookie_on_before_handshake_response.phpt | 5 +- .../set_cookie_on_handshake.phpt | 7 +- 26 files changed, 817 insertions(+), 175 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/new_cookie.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..9f884b7cbf7 100644 --- a/ext-src/php_swoole_http.h +++ b/ext-src/php_swoole_http.h @@ -213,6 +213,112 @@ struct Context { void free(); }; +struct Cookie { + 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; + smart_str buffer = {0}; + + zend_string *create() { + zend_string *date = nullptr; + if (!value) { + smart_str_append(&buffer, name); + 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); + + smart_str_0(&buffer); + return buffer.s; + } + + smart_str_append(&buffer, name); + smart_str_appendc(&buffer, '='); + smart_str_append(&buffer, value); + + if (expires > 0) { + 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) { + smart_str_appends(&buffer, "; path="); + smart_str_append(&buffer, path); + } + + if (domain && ZSTR_LEN(domain) > 0) { + 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"); + } + + smart_str_0(&buffer); + return buffer.s; + } + + ~Cookie() { + if (name) { + zend_string_release(name); + } + + if (value) { + zend_string_release(value); + } + + if (path) { + zend_string_release(path); + } + + if (domain) { + zend_string_release(domain); + } + + if (sameSite) { + zend_string_release(sameSite); + } + + if (priority) { + zend_string_release(priority); + } + } +}; + } // namespace http namespace http2 { @@ -270,10 +376,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_response_get_and_check_cookie(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..205be4e134a --- /dev/null +++ b/ext-src/stubs/php_swoole_http_cookie.stub.php @@ -0,0 +1,18 @@ + | + +----------------------------------------------------------------------+ + */ +#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; + +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); +} + +HttpCookie *php_swoole_http_get_cookie(zval *zobject) { + return php_swoole_http_cookie_fetch_object(Z_OBJ_P(zobject))->cookie; +} + +HttpCookie *php_swoole_http_response_get_and_check_cookie(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, setName); +static PHP_METHOD(swoole_http_cookie, setValue); +static PHP_METHOD(swoole_http_cookie, setExpires); +static PHP_METHOD(swoole_http_cookie, setPath); +static PHP_METHOD(swoole_http_cookie, setDomain); +static PHP_METHOD(swoole_http_cookie, setSecure); +static PHP_METHOD(swoole_http_cookie, setHttpOnly); +static PHP_METHOD(swoole_http_cookie, setSameSite); +static PHP_METHOD(swoole_http_cookie, setPriority); +static PHP_METHOD(swoole_http_cookie, setPartitioned); +static PHP_METHOD(swoole_http_cookie, getCookie); +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, setName, arginfo_class_Swoole_Http_Cookie_setName, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, setValue, arginfo_class_Swoole_Http_Cookie_setValue, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, setExpires, arginfo_class_Swoole_Http_Cookie_setExpires, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, setPath, arginfo_class_Swoole_Http_Cookie_setPath, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, setDomain, arginfo_class_Swoole_Http_Cookie_setDomain, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, setSecure, arginfo_class_Swoole_Http_Cookie_setSecure, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, setHttpOnly, arginfo_class_Swoole_Http_Cookie_setHttpOnly, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, setSameSite, arginfo_class_Swoole_Http_Cookie_setSameSite, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, setPriority, arginfo_class_Swoole_Http_Cookie_setPriority, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, setPartitioned, arginfo_class_Swoole_Http_Cookie_setPartitioned, ZEND_ACC_PUBLIC) + PHP_ME(swoole_http_cookie, getCookie, arginfo_class_Swoole_Http_Cookie_getCookie, 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); +} + +static PHP_METHOD(swoole_http_cookie, __construct) { + php_swoole_http_response_set_cookie(ZEND_THIS, new HttpCookie()); + RETURN_TRUE; +} + +static PHP_METHOD(swoole_http_cookie, setName) { + zend_string *name = nullptr; + HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(name) + ZEND_PARSE_PARAMETERS_END(); + + if (cookie->name) { + zend_string_release(cookie->name); + cookie->name = nullptr; + } + + zend_string_addref(name); + cookie->name = name; +} + +static PHP_METHOD(swoole_http_cookie, setValue) { + zend_string *value = nullptr; + HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_STR(value) + ZEND_PARSE_PARAMETERS_END(); + + if (cookie->value) { + zend_string_release(cookie->value); + cookie->value = nullptr; + } + + if (value && ZSTR_LEN(value) > 0) { + zend_string_addref(value); + cookie->value = value; + } +} + +static PHP_METHOD(swoole_http_cookie, setExpires) { + zend_long expires = 0; + HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(expires) + ZEND_PARSE_PARAMETERS_END(); + + cookie->expires = expires; +} + +static PHP_METHOD(swoole_http_cookie, setPath) { + zend_string *path = nullptr; + HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_STR(path) + ZEND_PARSE_PARAMETERS_END(); + + if (cookie->path) { + zend_string_release(cookie->path); + cookie->path = nullptr; + } + + zend_string_addref(path); + cookie->path = path; +} + +static PHP_METHOD(swoole_http_cookie, setDomain) { + zend_string *domain = nullptr; + HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_STR(domain) + ZEND_PARSE_PARAMETERS_END(); + + if (cookie->domain) { + zend_string_release(cookie->domain); + cookie->domain = nullptr; + } + + zend_string_addref(domain); + cookie->domain = domain; +} + +static PHP_METHOD(swoole_http_cookie, setSecure) { + zend_bool secure = false; + HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(secure) + ZEND_PARSE_PARAMETERS_END(); + + cookie->secure = secure; +} + +static PHP_METHOD(swoole_http_cookie, setHttpOnly) { + zend_bool httpOnly = false; + HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(httpOnly) + ZEND_PARSE_PARAMETERS_END(); + + cookie->httpOnly = httpOnly; +} + +static PHP_METHOD(swoole_http_cookie, setSameSite) { + zend_string *sameSite = nullptr; + HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_STR(sameSite) + ZEND_PARSE_PARAMETERS_END(); + + if (cookie->sameSite) { + zend_string_release(cookie->sameSite); + cookie->sameSite = nullptr; + } + + zend_string_addref(sameSite); + cookie->sameSite = sameSite; +} + +static PHP_METHOD(swoole_http_cookie, setPriority) { + zend_string *priority = nullptr; + HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_STR(priority) + ZEND_PARSE_PARAMETERS_END(); + + if (cookie->priority) { + zend_string_release(cookie->priority); + cookie->priority = nullptr; + } + + zend_string_addref(priority); + cookie->priority = priority; +} + +static PHP_METHOD(swoole_http_cookie, setPartitioned) { + zend_bool partitioned = false; + HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(partitioned) + ZEND_PARSE_PARAMETERS_END(); + + cookie->partitioned = partitioned; +} + +static PHP_METHOD(swoole_http_cookie, getCookie) { + HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_NONE(); + + array_init(return_value); + cookie->name ? add_assoc_str(return_value, "name", cookie->name) : add_assoc_string(return_value, "name", ""); + cookie->value ? add_assoc_str(return_value, "value", cookie->value) : add_assoc_string(return_value, "value", ""); + cookie->domain ? add_assoc_str(return_value, "domain", cookie->path) : add_assoc_string(return_value, "domain", ""); + cookie->sameSite ? add_assoc_str(return_value, "sameSite", cookie->name) : add_assoc_string(return_value, "sameSite", ""); + cookie->priority ? add_assoc_str(return_value, "priority", cookie->name) : add_assoc_string(return_value, "priority", ""); + add_assoc_long(return_value, "expires", cookie->expires); + add_assoc_bool(return_value, "secure", cookie->secure); + add_assoc_bool(return_value, "httpOnly", cookie->httpOnly); + add_assoc_bool(return_value, "partitioned", cookie->partitioned); +} + +static PHP_METHOD(swoole_http_cookie, reset) { + HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_NONE(); + + cookie->expires = 0; + cookie->secure = false; + cookie->httpOnly = false; + cookie->partitioned = false; + + if (cookie->name) { + zend_string_release(cookie->name); + cookie->name = nullptr; + } + + if (cookie->value) { + zend_string_release(cookie->value); + cookie->value = nullptr; + } + + if (cookie->path) { + zend_string_release(cookie->path); + cookie->path = nullptr; + } + + if (cookie->domain) { + zend_string_release(cookie->domain); + cookie->domain = nullptr; + } + + if (cookie->sameSite) { + zend_string_release(cookie->sameSite); + cookie->sameSite = nullptr; + } + + if (cookie->priority) { + zend_string_release(cookie->priority); + cookie->priority = nullptr; + } + + RETURN_TRUE; +} diff --git a/ext-src/swoole_http_response.cc b/ext-src/swoole_http_response.cc index fdfe0c2b613..f7fabf3f548 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; @@ -45,6 +46,8 @@ namespace HttpServer = swoole::http_server; zend_class_entry *swoole_http_response_ce; static zend_object_handlers swoole_http_response_handlers; +#define ILLEGAL_COOKIE_CHARACTER "\",\", \";\", \" \", \"\\t\", \"\\r\", \"\\n\", \"\\013\", or \"\\014\"" + static inline void http_header_key_format(char *key, int length) { int i, state = 0; for (i = 0; i < length; i++) { @@ -963,144 +966,69 @@ 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; - 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_PARSE_PARAMETERS_START(1, 9) - Z_PARAM_STRING(name, name_len) - Z_PARAM_OPTIONAL - Z_PARAM_STRING(value, value_len) - Z_PARAM_LONG(expires) - Z_PARAM_STRING(path, path_len) - Z_PARAM_STRING(domain, domain_len) - Z_PARAM_BOOL(secure) - Z_PARAM_BOOL(httponly) - Z_PARAM_STRING(samesite, samesite_len) - Z_PARAM_STRING(priority, priority_len) - ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + zval *zcookie = nullptr; + + ZEND_PARSE_PARAMETERS_START(1,1) + Z_PARAM_ZVAL(zcookie) + ZEND_PARSE_PARAMETERS_END(); 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'"); + HttpCookie *cookie = php_swoole_http_response_get_and_check_cookie(zcookie); + if (UNEXPECTED(!cookie)) { RETURN_FALSE; } - if (!url_encode && swoole_http_has_crlf(value, value_len)) { + if (ZSTR_LEN(cookie->name) == 0) { + php_swoole_error(E_WARNING, "Cookie name cannot be empty"); 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 (strpbrk(ZSTR_VAL(cookie->name), "=,; \t\r\n\013\014") != nullptr) { + php_swoole_error(E_WARNING, "Cookie name cannot contain \"=\", " ILLEGAL_COOKIE_CHARACTER); + RETURN_FALSE; } - 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); - } 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 (!url_encode && cookie->value && strpbrk(ZSTR_VAL(cookie->value), ",; \t\r\n\013\014") != nullptr) { + php_swoole_error(E_WARNING, "Cookie value cannot contain " ILLEGAL_COOKIE_CHARACTER); + RETURN_FALSE; } - if (secure) { - strlcat(cookie, "; secure", cookie_size); + + if (cookie->path && strpbrk(ZSTR_VAL(cookie->path), ",; \t\r\n\013\014") != NULL) { + php_swoole_error(E_WARNING, "Cookie path option cannot contain " ILLEGAL_COOKIE_CHARACTER); + RETURN_FALSE; } - if (httponly) { - strlcat(cookie, "; httponly", cookie_size); + + if (cookie->domain && strpbrk(ZSTR_VAL(cookie->domain), ",; \t\r\n\013\014") != NULL) { + php_swoole_error(E_WARNING, "Cookie domain option cannot contain " ILLEGAL_COOKIE_CHARACTER); + RETURN_FALSE; } - if (samesite_len > 0) { - strlcat(cookie, "; samesite=", cookie_size); - strlcat(cookie, samesite, cookie_size); + +#ifdef ZEND_ENABLE_ZVAL_LONG64 + if (cookie->expires >= 253402300800) { + php_swoole_error(E_WARNING, "Cookie expires option cannot have a year greater than 9999"); + RETURN_FALSE; } - if (priority_len > 0) { - strlcat(cookie, "; priority=", cookie_size); - strlcat(cookie, priority, cookie_size); +#endif + + if (url_encode && cookie->value && ZSTR_LEN(cookie->value) > 0) { + zend_string *encoded_value = php_url_encode(ZSTR_VAL(cookie->value), ZSTR_LEN(cookie->value)); + zend_string_release(cookie->value); + cookie->value = encoded_value; } + + zend_string *data = cookie->create(); 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); + swoole_http_init_and_read_property( + swoole_http_response_ce, ctx->response.zobject, &ctx->response.zcookie, SW_ZSTR_KNOWN(SW_ZEND_STR_COOKIE)), + ZSTR_VAL(data), + ZSTR_LEN(data)); + + smart_str_free(&cookie->buffer); + cookie->buffer = {0}; RETURN_TRUE; } 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/swoole_http2_client_coro/cookies.phpt b/tests/swoole_http2_client_coro/cookies.phpt index 04a4b6cb4e1..b7ad9194c3f 100644 --- a/tests/swoole_http2_client_coro/cookies.phpt +++ b/tests/swoole_http2_client_coro/cookies.phpt @@ -35,8 +35,11 @@ $pm->childFunc = function () use ($pm) { $pm->wakeup(); }); $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) { + $cookie = new Swoole\Http\Cookie(); foreach ($request->cookie as $name => $value) { - $response->cookie($name, $value); + $cookie->setName($name); + $cookie->setValue($value); + $response->cookie($cookie); } $response->end('OK'); }); diff --git a/tests/swoole_http2_server_coro/cookies.phpt b/tests/swoole_http2_server_coro/cookies.phpt index 9dd0dfb6083..eaebd699421 100644 --- a/tests/swoole_http2_server_coro/cookies.phpt +++ b/tests/swoole_http2_server_coro/cookies.phpt @@ -46,8 +46,11 @@ $pm->childFunc = function () use ($pm) { ]); $http->handle('/', function (Swoole\Http\Request $request, Swoole\Http\Response $response) { $response->header('id', $request->header['id']); + $cookie = new Swoole\Http\Cookie(); foreach ($request->cookie as $name => $value) { - $response->cookie($name, $value); + $cookie->setName($name); + $cookie->setValue($value); + $response->cookie($cookie); } $response->end('OK'); }); diff --git a/tests/swoole_http_client_coro/issue_2664.phpt b/tests/swoole_http_client_coro/issue_2664.phpt index 804a55609f5..6d052c6e3d6 100644 --- a/tests/swoole_http_client_coro/issue_2664.phpt +++ b/tests/swoole_http_client_coro/issue_2664.phpt @@ -20,10 +20,36 @@ $pm->childFunc = function () use ($pm) { }); $server->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) use ($pm) { $time_left = time() + 84600; - $response->cookie('key1', 'val1', $time_left, '/', 'id.test.com'); - $response->cookie('key1', '', 0, '/', 'test.com'); - $response->cookie('key2', 'val2', $time_left, '/', 'id.test.com'); - $response->cookie('key2', '', 0, '/', 'test.com'); + + $cookie = new Swoole\Http\Cookie(); + $cookie->setName('key1'); + $cookie->setValue('val1'); + $cookie->setExpires($time_left); + $cookie->setPath('/'); + $cookie->setDomain('id.test.com'); + $response->cookie($cookie); + + $cookie->setName('key1'); + $cookie->setValue(''); + $cookie->setExpires(0); + $cookie->setPath('/'); + $cookie->setDomain('test.com'); + $response->cookie($cookie); + + $cookie->setName('key1'); + $cookie->setValue('val2'); + $cookie->setExpires($time_left); + $cookie->setPath('/'); + $cookie->setDomain('id.test.com'); + $response->cookie($cookie); + + $cookie->setName('key2'); + $cookie->setValue(''); + $cookie->setExpires(0); + $cookie->setPath('/'); + $cookie->setDomain('test.com'); + $response->cookie($cookie); + $response->end("

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

"); }); $server->start(); @@ -36,9 +62,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" + string(91) "key1=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/bug_2368.phpt b/tests/swoole_http_server/bug_2368.phpt index 281aaa43aa5..6bd06febe05 100644 --- a/tests/swoole_http_server/bug_2368.phpt +++ b/tests/swoole_http_server/bug_2368.phpt @@ -28,7 +28,10 @@ $pm->childFunc = function () use ($pm) { 'log_file' => '/dev/null', )); $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) { - $response->cookie('name', COOKIE); + $cookie = new Swoole\Http\Cookie(); + $cookie->setName('name'); + $cookie->setValue(COOKIE); + $response->cookie($cookie); $response->end(); }); $http->start(); diff --git a/tests/swoole_http_server/bug_5146.phpt b/tests/swoole_http_server/bug_5146.phpt index 2efbbc39dc1..06e55c8672d 100644 --- a/tests/swoole_http_server/bug_5146.phpt +++ b/tests/swoole_http_server/bug_5146.phpt @@ -33,11 +33,12 @@ $pm->childFunc = function () use ($pm) { }); $http->on('request', function (Request $request, Response $response) use ($http) { $previous = memory_get_usage(); - $response->cookie( - 'test_cookie', - 'hello', - time() + (24 * 60 * 60) - ); + + $cookie = new Swoole\Http\Cookie(); + $cookie->setName('test_cookie'); + $cookie->setValue('hello'); + $cookie->setExpires(time() + (24 * 60 * 60)); + $response->cookie($cookie); global $previous; global $item; diff --git a/tests/swoole_http_server/cookie_delete.phpt b/tests/swoole_http_server/cookie_delete.phpt index 59421cc3eb6..730635a4b20 100644 --- a/tests/swoole_http_server/cookie_delete.phpt +++ b/tests/swoole_http_server/cookie_delete.phpt @@ -33,14 +33,51 @@ $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) { - $response->cookie('cookie1', null); - $response->cookie('cookie2', ''); - $response->cookie('cookie3', 'cookie3', 0); // must be > 0 - $response->cookie('cookie4', 'cookie4', -1); // must be > 0 - $response->cookie('cookie5', 'cookie5', 1); - $response->cookie('cookie6', null, 0); - $response->cookie('cookie7', null, -1); - $response->cookie('cookie8', null, 1); + $cookie = new Swoole\Http\Cookie(); + $cookie->setName('cookie1'); + $cookie->setValue(null); + $response->cookie($cookie); + + $cookie->reset(); + $cookie->setName('cookie2'); + $cookie->setValue(''); + $response->cookie($cookie); + + $cookie->reset(); + $cookie->setName('cookie3'); + $cookie->setValue('cookie3'); + $cookie->setExpires(0); + $response->cookie($cookie); // must be > 0 + + $cookie->reset(); + $cookie->setName('cookie4'); + $cookie->setValue('cookie4'); + $cookie->setExpires(-1); + $response->cookie($cookie); // must be > 0 + + $cookie->reset(); + $cookie->setName('cookie5'); + $cookie->setValue('cookie5'); + $cookie->setExpires(1); + $response->cookie($cookie); + + $cookie->reset(); + $cookie->setName('cookie6'); + $cookie->setValue(null); + $cookie->setExpires(0); + $response->cookie($cookie); + + $cookie->reset(); + $cookie->setName('cookie7'); + $cookie->setValue(null); + $cookie->setExpires(-1); + $response->cookie($cookie); + + $cookie->reset(); + $cookie->setName('cookie8'); + $cookie->setValue(null); + $cookie->setExpires(1); + $response->cookie($cookie); $response->end(); }); $http->start(); diff --git a/tests/swoole_http_server/cookie_samesite.phpt b/tests/swoole_http_server/cookie_samesite.phpt index 939ec2cf9a4..875c82ea043 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', ] ); }); @@ -24,7 +24,16 @@ $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) { - $response->cookie('a', '123', 0, '', '', false, false, 'Lax'); + $cookie = new Swoole\Http\Cookie(); + $cookie->setName('a'); + $cookie->setValue('123'); + $cookie->setExpires(0); + $cookie->setPath(''); + $cookie->setDomain(''); + $cookie->setSecure(false); + $cookie->setHttpOnly(false); + $cookie->setSameSite('Lax'); + $response->cookie($cookie); $response->end(); }); $http->start(); diff --git a/tests/swoole_http_server/cookie_vs_rawcookie.phpt b/tests/swoole_http_server/cookie_vs_rawcookie.phpt index 172f32815e1..2888b9d391c 100644 --- a/tests/swoole_http_server/cookie_vs_rawcookie.phpt +++ b/tests/swoole_http_server/cookie_vs_rawcookie.phpt @@ -14,8 +14,7 @@ $pm->parentFunc = function () use ($pm) { Assert::same($cli->statusCode, 200); Assert::assert($cli->set_cookie_headers === [ - 'cookie=' . urlencode($cookie), - 'rawcookie=' . $cookie, + 'cookie=' . urlencode($cookie) ] ); }); @@ -42,8 +41,15 @@ $pm->childFunc = function () use ($pm) { $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 = new Swoole\Http\Cookie(); + $cookie->setName('cookie'); + $cookie->setValue($request->get['cookie']); + $response->cookie($cookie); + + $cookie->setName('rawcookie'); + $cookie->setValue($request->get['cookie']); + $response->rawcookie($cookie); $response->end(); }); $http->start(); @@ -51,5 +57,6 @@ $pm->childFunc = function () use ($pm) { $pm->childFirst(); $pm->run(); ?> ---EXPECT-- +--EXPECTF-- +Warning: Swoole\Http\Response::rawcookie(): Cookie value cannot contain ",", ";", " ", "\t", "\r", "\n", "\013", or "\014" in %S SUCCESS diff --git a/tests/swoole_http_server/max-age.phpt b/tests/swoole_http_server/max-age.phpt index fef9744979a..d01efb249d7 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); }); @@ -35,8 +35,21 @@ $pm->childFunc = function () use ($pm) { }); $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) use ($pm) { - $response->cookie('test', '123456789', time() + 3600, '/', 'example.com', true, true, 'None'); - $response->cookie('test', ''); + $cookie = new Swoole\Http\Cookie(); + $cookie->setName('test'); + $cookie->setValue('123456789'); + $cookie->setExpires(time() + 3600); + $cookie->setPath('/'); + $cookie->setDomain('example.com'); + $cookie->setSecure(true); + $cookie->setHttpOnly(true); + $cookie->setSameSite('None'); + $response->cookie($cookie); + + $cookie->reset(); + $cookie->setName('test'); + $cookie->setValue(''); + $response->cookie($cookie); $response->end(); }); $http->start(); diff --git a/tests/swoole_http_server/new_cookie.phpt b/tests/swoole_http_server/new_cookie.phpt new file mode 100644 index 00000000000..79eeabd6fc4 --- /dev/null +++ b/tests/swoole_http_server/new_cookie.phpt @@ -0,0 +1,64 @@ +--TEST-- +swoole_http_server: new cookie +--SKIPIF-- + +--FILE-- +setName('test'); +$cookie->setValue('123456789'); +$cookie->setExpires(time() + 3600); +$cookie->setPath('/'); +$cookie->setDomain('example.com'); +$cookie->setSecure(true); +$cookie->setHttpOnly(true); +$cookie->setSameSite('None'); +var_dump($cookie->getCookie()); +$cookie->reset(); +var_dump($cookie->getCookie()); +?> +--EXPECTF-- +array(9) { + ["name"]=> + string(4) "test" + ["value"]=> + string(9) "123456789" + ["domain"]=> + string(1) "/" + ["sameSite"]=> + string(4) "test" + ["priority"]=> + string(0) "" + ["expires"]=> + int(%d) + ["secure"]=> + bool(true) + ["httpOnly"]=> + bool(true) + ["partitioned"]=> + bool(false) +} +array(9) { + ["name"]=> + string(0) "" + ["value"]=> + string(0) "" + ["domain"]=> + string(0) "" + ["sameSite"]=> + string(0) "" + ["priority"]=> + string(0) "" + ["expires"]=> + int(0) + ["secure"]=> + bool(false) + ["httpOnly"]=> + bool(false) + ["partitioned"]=> + bool(false) +} diff --git a/tests/swoole_http_server/rawCookie.phpt b/tests/swoole_http_server/rawCookie.phpt index ed2be373e86..b96ac145f8e 100644 --- a/tests/swoole_http_server/rawCookie.phpt +++ b/tests/swoole_http_server/rawCookie.phpt @@ -42,11 +42,26 @@ $pm->childFunc = function () use ($pm, $simple_http_server) { $secure = false; $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"; + + $cookie = new Swoole\Http\Cookie(); + $cookie->setName($name); + $cookie->setValue($value); + $cookie->setExpires($expire); + $cookie->setPath($path); + $cookie->setDomain($domain); + $cookie->setSecure($secure); + $cookie->setHttpOnly($httpOnly); + $response->cookie($cookie); + + $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()); + + $response->cookie($cookie); + + $cookie->reset(); + $cookie->setName("rawcontent"); + $cookie->setValue($request->rawcontent()); + $response->rawcookie($cookie); $response->end("Hello World!"); }); $http->start(); diff --git a/tests/swoole_http_server/too_many_special_chars_in_cookie.phpt b/tests/swoole_http_server/too_many_special_chars_in_cookie.phpt index 1f2613472de..587d2f35d9c 100644 --- a/tests/swoole_http_server/too_many_special_chars_in_cookie.phpt +++ b/tests/swoole_http_server/too_many_special_chars_in_cookie.phpt @@ -32,7 +32,13 @@ $pm->childFunc = function () use ($pm) { if ($pre_cookie) { Assert::same($request->cookie['foo'], $pre_cookie); } - $response->cookie('foo', $pre_cookie = $pm->getRandomData(), time() + 60 * 30, '/'); + + $cookie = new Swoole\Http\Cookie(); + $cookie->setName('foo'); + $cookie->setValue($pre_cookie = $pm->getRandomData()); + $cookie->setExpires(time() + 60 * 30); + $cookie->setPath('/'); + $response->cookie($cookie); $response->end(); }); $http->start(); diff --git a/tests/swoole_http_server_coro/check_cookie_crlf.phpt b/tests/swoole_http_server_coro/check_cookie_crlf.phpt index c114a4632ec..878d56d5595 100644 --- a/tests/swoole_http_server_coro/check_cookie_crlf.phpt +++ b/tests/swoole_http_server_coro/check_cookie_crlf.phpt @@ -37,13 +37,20 @@ $pm->childFunc = function () use ($pm) { $server->handle('/rawcookie', function (Request $request, Response $response) { $value = "cn\r\nmalicious-header:injected\r\nContent-Length:27\r\n\r\n

malicious response body"; - $response->rawcookie('lang', $value); + + $cookie = new Swoole\Http\Cookie(); + $cookie->setName('lang'); + $cookie->setValue($value); + $response->rawcookie($cookie); $response->end('hello world'); }); $server->handle('/cookie', function (Request $request, Response $response) { $value = "cn\r\nmalicious-header:injected\r\nContent-Length:27\r\n\r\n

malicious response body"; - $response->cookie('lang', $value); + $cookie = new Swoole\Http\Cookie(); + $cookie->setName('lang'); + $cookie->setValue($value); + $response->cookie($cookie); $response->end('hello world'); }); @@ -54,5 +61,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(): Cookie value cannot contain ",", ";", " ", "\t", "\r", "\n", "\013", or "\014" in %s DONE diff --git a/tests/swoole_http_server_coro/websocket.phpt b/tests/swoole_http_server_coro/websocket.phpt index 4f50b2ed708..624d8f03676 100644 --- a/tests/swoole_http_server_coro/websocket.phpt +++ b/tests/swoole_http_server_coro/websocket.phpt @@ -37,7 +37,12 @@ $pm->childFunc = function () use ($pm) { $server = new Co\Http\Server("127.0.0.1", $pm->getFreePort(), false); $server->handle('/websocket', function ($request, $ws) { $ws->header('x-swoole', 'hello'); - $ws->cookie('test-file', __FILE__); + + $cookie = new Swoole\Http\Cookie(); + $cookie->setName('test-file'); + $cookie->setValue(__FILE__); + $ws->cookie($cookie); + $ws->upgrade(); while (true) { $frame = $ws->recv(); diff --git a/tests/swoole_websocket_server/set_cookie_on_before_handshake_response.phpt b/tests/swoole_websocket_server/set_cookie_on_before_handshake_response.phpt index 182aef947d9..69218a67361 100644 --- a/tests/swoole_websocket_server/set_cookie_on_before_handshake_response.phpt +++ b/tests/swoole_websocket_server/set_cookie_on_before_handshake_response.phpt @@ -30,7 +30,10 @@ $pm->childFunc = function () use ($pm) { $pm->wakeup(); }); $server->on('beforeHandShakeResponse', function (Server $server, Request $request, Response $response) { - $response->cookie('abc', 'def'); + $cookie = new Swoole\Http\Cookie(); + $cookie->setName('abc'); + $cookie->setValue('def'); + $response->cookie($cookie); }); $server->on('message', function () { }); $server->start(); diff --git a/tests/swoole_websocket_server/set_cookie_on_handshake.phpt b/tests/swoole_websocket_server/set_cookie_on_handshake.phpt index bc0b756a212..8496eaa2609 100644 --- a/tests/swoole_websocket_server/set_cookie_on_handshake.phpt +++ b/tests/swoole_websocket_server/set_cookie_on_handshake.phpt @@ -54,7 +54,12 @@ $pm->childFunc = function () use ($pm) { foreach ($headers as $key => $val) { $response->header($key, $val); } - $response->cookie('abc', 'def'); + + $cookie = new Swoole\Http\Cookie(); + $cookie->setName('abc'); + $cookie->setValue('def'); + $response->cookie($cookie); + $response->status(101); $response->end(); return true; From 9bb3530c373b55b9459f56c480983713f3b5cf75 Mon Sep 17 00:00:00 2001 From: MARiA so cute <33935209+NathanFreeman@users.noreply.github.com> Date: Thu, 18 Jul 2024 16:12:03 +0800 Subject: [PATCH 2/8] optimize set cookie method --- ext-src/php_swoole_http.h | 1 + ext-src/stubs/php_swoole_http_cookie.stub.php | 20 +-- .../stubs/php_swoole_http_cookie_arginfo.h | 23 +-- .../stubs/php_swoole_http_response.stub.php | 5 +- .../stubs/php_swoole_http_response_arginfo.h | 17 +- ext-src/swoole_http_cookie.cc | 17 ++ ext-src/swoole_http_response.cc | 146 ++++++++++++------ tests/swoole_http2_client_coro/cookies.phpt | 5 +- tests/swoole_http2_server_coro/cookies.phpt | 5 +- tests/swoole_http_client_coro/issue_2664.phpt | 36 +---- tests/swoole_http_server/bug_2368.phpt | 5 +- tests/swoole_http_server/bug_5146.phpt | 11 +- tests/swoole_http_server/cookieAlias.phpt | 56 +++++++ tests/swoole_http_server/cookie_delete.phpt | 53 +------ tests/swoole_http_server/cookie_samesite.phpt | 11 +- .../cookie_vs_rawcookie.phpt | 13 +- tests/swoole_http_server/max-age.phpt | 17 +- tests/swoole_http_server/new_cookie.phpt | 8 +- tests/swoole_http_server/objectCookie.phpt | 49 ++++++ .../objectCookieMemory.phpt | 77 +++++++++ tests/swoole_http_server/rawCookie.phpt | 21 +-- .../too_many_special_chars_in_cookie.phpt | 8 +- .../check_cookie_crlf.phpt | 11 +- tests/swoole_http_server_coro/websocket.phpt | 7 +- ...t_cookie_on_before_handshake_response.phpt | 5 +- .../set_cookie_on_handshake.phpt | 7 +- 26 files changed, 383 insertions(+), 251 deletions(-) create mode 100644 tests/swoole_http_server/cookieAlias.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_http.h b/ext-src/php_swoole_http.h index 9f884b7cbf7..929d5539a5f 100644 --- a/ext-src/php_swoole_http.h +++ b/ext-src/php_swoole_http.h @@ -224,6 +224,7 @@ struct Cookie { zend_bool secure = false; zend_bool httpOnly = false; zend_bool partitioned = false; + zend_bool encode = true; smart_str buffer = {0}; zend_string *create() { diff --git a/ext-src/stubs/php_swoole_http_cookie.stub.php b/ext-src/stubs/php_swoole_http_cookie.stub.php index 205be4e134a..a6efaee03d3 100644 --- a/ext-src/stubs/php_swoole_http_cookie.stub.php +++ b/ext-src/stubs/php_swoole_http_cookie.stub.php @@ -2,16 +2,16 @@ namespace Swoole\Http { class Cookie { public function __construct() {} - public function setName(string $name): void {} - public function setValue(string $value = ''): void {} - public function setExpires(int $expires = 0): void {} - public function setPath(string $path = '/'): void {} - public function setDomain(string $domain = ''): void {} - public function setSecure(bool $secure = false): void {} - public function setHttpOnly(bool $httpOnly = false): void {} - public function setSameSite(string $sameSite = ''): void {} - public function setPriority(string $priority = ''): void {} - public function setPartitioned(bool $partitioned = false): void {} + public function setName(string $name): \Swoole\Http\Cookie {} + public function setValue(string $value = '', bool $encode = true): \Swoole\Http\Cookie {} + public function setExpires(int $expires = 0): \Swoole\Http\Cookie {} + public function setPath(string $path = '/'): \Swoole\Http\Cookie {} + public function setDomain(string $domain = ''): \Swoole\Http\Cookie {} + public function setSecure(bool $secure = false): \Swoole\Http\Cookie {} + public function setHttpOnly(bool $httpOnly = false): \Swoole\Http\Cookie {} + public function setSameSite(string $sameSite = ''): \Swoole\Http\Cookie {} + public function setPriority(string $priority = ''): \Swoole\Http\Cookie {} + public function setPartitioned(bool $partitioned = false): \Swoole\Http\Cookie {} public function getCookie(): array {} public function reset(): bool {} } diff --git a/ext-src/stubs/php_swoole_http_cookie_arginfo.h b/ext-src/stubs/php_swoole_http_cookie_arginfo.h index 0a654dd5668..ebf74b7cceb 100644 --- a/ext-src/stubs/php_swoole_http_cookie_arginfo.h +++ b/ext-src/stubs/php_swoole_http_cookie_arginfo.h @@ -1,46 +1,47 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a14fec26e023c94118c7074dec7f462f8b3a84f0 */ + * Stub hash: 02aefd39f4852eea3258eea8edb7000fa86af163 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Swoole_Http_Cookie___construct, 0, 0, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_setName, 0, 1, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setName, 0, 1, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_setValue, 0, 0, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setValue, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_STRING, 0, "\'\'") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encode, _IS_BOOL, 0, "true") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_setExpires, 0, 0, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setExpires, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, expires, IS_LONG, 0, "0") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_setPath, 0, 0, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setPath, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, path, IS_STRING, 0, "\'/\'") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_setDomain, 0, 0, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setDomain, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, domain, IS_STRING, 0, "\'\'") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_setSecure, 0, 0, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setSecure, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, secure, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_setHttpOnly, 0, 0, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setHttpOnly, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, httpOnly, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_setSameSite, 0, 0, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setSameSite, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, sameSite, IS_STRING, 0, "\'\'") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_setPriority, 0, 0, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setPriority, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, priority, IS_STRING, 0, "\'\'") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_setPartitioned, 0, 0, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setPartitioned, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, partitioned, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() diff --git a/ext-src/stubs/php_swoole_http_response.stub.php b/ext-src/stubs/php_swoole_http_response.stub.php index 27c02e0e82e..b3d2cc06d29 100644 --- a/ext-src/stubs/php_swoole_http_response.stub.php +++ b/ext-src/stubs/php_swoole_http_response.stub.php @@ -5,8 +5,9 @@ public function write(string $content): bool {} public function end(?string $content = null): bool {} public function sendfile(string $filename, int $offset = 0, int $length = 0): bool {} public function redirect(string $location, int $http_code = 302): bool {} - public function cookie(\Swoole\Http\Cookie $cookie): bool {} - public function rawcookie(\Swoole\Http\Cookie $cookie): bool {} + public function cookie(string $name, string $value = '', int $expires = 0 , string $path = '/', string $domain = '', bool $secure = false , bool $httponly = false, string $samesite = '', string $priority = '', bool $partitioned = false): bool {} + public function rawcookie(string $name, string $value = '', int $expires = 0 , string $path = '/', string $domain = '', bool $secure = false , bool $httponly = false, string $samesite = '', string $priority = '', bool $partitioned = false): bool {} + public function objectCookie(\Swoole\Http\Cookie $cookie): bool {} public function header(string $key, string|array $value, bool $format = true): bool {} public function initHeader(): bool {} public function isWritable(): bool {} diff --git a/ext-src/stubs/php_swoole_http_response_arginfo.h b/ext-src/stubs/php_swoole_http_response_arginfo.h index 1a71d67e7a0..5533abfce79 100644 --- a/ext-src/stubs/php_swoole_http_response_arginfo.h +++ b/ext-src/stubs/php_swoole_http_response_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 8d9d9ceaf03c44dc001ced33ab773ca091ec3996 */ + * Stub hash: f823bb9df8c0deca0edc159f68fce6bcec8291ed */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Response_write, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, content, IS_STRING, 0) @@ -21,11 +21,24 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Response_redir ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Response_cookie, 0, 1, _IS_BOOL, 0) - ZEND_ARG_OBJ_INFO(0, cookie, Swoole\\Http\\Cookie, 0) + ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_STRING, 0, "\'\'") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, expires, IS_LONG, 0, "0") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, path, IS_STRING, 0, "\'/\'") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, domain, IS_STRING, 0, "\'\'") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, secure, _IS_BOOL, 0, "false") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, httponly, _IS_BOOL, 0, "false") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, samesite, IS_STRING, 0, "\'\'") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, priority, IS_STRING, 0, "\'\'") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, partitioned, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() #define arginfo_class_Swoole_Http_Response_rawcookie arginfo_class_Swoole_Http_Response_cookie +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Response_objectCookie, 0, 1, _IS_BOOL, 0) + ZEND_ARG_OBJ_INFO(0, cookie, Swoole\\Http\\Cookie, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Response_header, 0, 2, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_ARG_TYPE_MASK(0, value, MAY_BE_STRING|MAY_BE_ARRAY, NULL) diff --git a/ext-src/swoole_http_cookie.cc b/ext-src/swoole_http_cookie.cc index 884aaca53bf..7c56333a7a4 100644 --- a/ext-src/swoole_http_cookie.cc +++ b/ext-src/swoole_http_cookie.cc @@ -76,6 +76,7 @@ static PHP_METHOD(swoole_http_cookie, setHttpOnly); static PHP_METHOD(swoole_http_cookie, setSameSite); static PHP_METHOD(swoole_http_cookie, setPriority); static PHP_METHOD(swoole_http_cookie, setPartitioned); +static PHP_METHOD(swoole_http_cookie, setUrlEncode); static PHP_METHOD(swoole_http_cookie, getCookie); static PHP_METHOD(swoole_http_cookie, reset); SW_EXTERN_C_END @@ -132,26 +133,32 @@ static PHP_METHOD(swoole_http_cookie, setName) { zend_string_addref(name); cookie->name = name; + RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } static PHP_METHOD(swoole_http_cookie, setValue) { zend_string *value = nullptr; + zend_bool encode = true; HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); ZEND_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_STR(value) + Z_PARAM_BOOL(encode) ZEND_PARSE_PARAMETERS_END(); if (cookie->value) { zend_string_release(cookie->value); cookie->value = nullptr; + cookie->encode = true; } if (value && ZSTR_LEN(value) > 0) { zend_string_addref(value); cookie->value = value; + cookie->encode = encode; } + RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } static PHP_METHOD(swoole_http_cookie, setExpires) { @@ -164,6 +171,7 @@ static PHP_METHOD(swoole_http_cookie, setExpires) { ZEND_PARSE_PARAMETERS_END(); cookie->expires = expires; + RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } static PHP_METHOD(swoole_http_cookie, setPath) { @@ -182,6 +190,7 @@ static PHP_METHOD(swoole_http_cookie, setPath) { zend_string_addref(path); cookie->path = path; + RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } static PHP_METHOD(swoole_http_cookie, setDomain) { @@ -200,6 +209,7 @@ static PHP_METHOD(swoole_http_cookie, setDomain) { zend_string_addref(domain); cookie->domain = domain; + RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } static PHP_METHOD(swoole_http_cookie, setSecure) { @@ -212,6 +222,7 @@ static PHP_METHOD(swoole_http_cookie, setSecure) { ZEND_PARSE_PARAMETERS_END(); cookie->secure = secure; + RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } static PHP_METHOD(swoole_http_cookie, setHttpOnly) { @@ -224,6 +235,7 @@ static PHP_METHOD(swoole_http_cookie, setHttpOnly) { ZEND_PARSE_PARAMETERS_END(); cookie->httpOnly = httpOnly; + RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } static PHP_METHOD(swoole_http_cookie, setSameSite) { @@ -242,6 +254,7 @@ static PHP_METHOD(swoole_http_cookie, setSameSite) { zend_string_addref(sameSite); cookie->sameSite = sameSite; + RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } static PHP_METHOD(swoole_http_cookie, setPriority) { @@ -260,6 +273,7 @@ static PHP_METHOD(swoole_http_cookie, setPriority) { zend_string_addref(priority); cookie->priority = priority; + RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } static PHP_METHOD(swoole_http_cookie, setPartitioned) { @@ -272,6 +286,7 @@ static PHP_METHOD(swoole_http_cookie, setPartitioned) { ZEND_PARSE_PARAMETERS_END(); cookie->partitioned = partitioned; + RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } static PHP_METHOD(swoole_http_cookie, getCookie) { @@ -285,6 +300,7 @@ static PHP_METHOD(swoole_http_cookie, getCookie) { cookie->domain ? add_assoc_str(return_value, "domain", cookie->path) : add_assoc_string(return_value, "domain", ""); cookie->sameSite ? add_assoc_str(return_value, "sameSite", cookie->name) : add_assoc_string(return_value, "sameSite", ""); cookie->priority ? add_assoc_str(return_value, "priority", cookie->name) : add_assoc_string(return_value, "priority", ""); + add_assoc_bool(return_value, "encode", cookie->encode); add_assoc_long(return_value, "expires", cookie->expires); add_assoc_bool(return_value, "secure", cookie->secure); add_assoc_bool(return_value, "httpOnly", cookie->httpOnly); @@ -300,6 +316,7 @@ static PHP_METHOD(swoole_http_cookie, reset) { cookie->secure = false; cookie->httpOnly = false; cookie->partitioned = false; + cookie->encode = true; if (cookie->name) { zend_string_release(cookie->name); diff --git a/ext-src/swoole_http_response.cc b/ext-src/swoole_http_response.cc index f7fabf3f548..9c0f73eead1 100644 --- a/ext-src/swoole_http_response.cc +++ b/ext-src/swoole_http_response.cc @@ -139,6 +139,7 @@ static PHP_METHOD(swoole_http_response, sendfile); static PHP_METHOD(swoole_http_response, redirect); static PHP_METHOD(swoole_http_response, cookie); static PHP_METHOD(swoole_http_response, rawcookie); +static PHP_METHOD(swoole_http_response, objectCookie); static PHP_METHOD(swoole_http_response, header); static PHP_METHOD(swoole_http_response, initHeader); static PHP_METHOD(swoole_http_response, isWritable); @@ -160,24 +161,27 @@ 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, objectCookie, arginfo_class_Swoole_Http_Response_objectCookie, ZEND_ACC_PUBLIC) + PHP_MALIAS(swoole_http_response, setObjectCookie, objectCookie, arginfo_class_Swoole_Http_Response_objectCookie, 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 */ @@ -965,56 +969,45 @@ static PHP_METHOD(swoole_http_response, sendfile) { } } -static void php_swoole_http_response_cookie(INTERNAL_FUNCTION_PARAMETERS, const bool url_encode) { - zval *zcookie = nullptr; - - ZEND_PARSE_PARAMETERS_START(1,1) - Z_PARAM_ZVAL(zcookie) - ZEND_PARSE_PARAMETERS_END(); - - HttpContext *ctx = php_swoole_http_response_get_and_check_context(ZEND_THIS); +static bool inline php_swoole_http_response_create_cookie(HttpCookie *cookie, zval *zobject) { + HttpContext *ctx = php_swoole_http_response_get_and_check_context(zobject); if (UNEXPECTED(!ctx)) { - RETURN_FALSE; - } - - HttpCookie *cookie = php_swoole_http_response_get_and_check_cookie(zcookie); - if (UNEXPECTED(!cookie)) { - RETURN_FALSE; + return false; } if (ZSTR_LEN(cookie->name) == 0) { php_swoole_error(E_WARNING, "Cookie name cannot be empty"); - RETURN_FALSE; + return false; } if (strpbrk(ZSTR_VAL(cookie->name), "=,; \t\r\n\013\014") != nullptr) { php_swoole_error(E_WARNING, "Cookie name cannot contain \"=\", " ILLEGAL_COOKIE_CHARACTER); - RETURN_FALSE; + return false; } - if (!url_encode && cookie->value && strpbrk(ZSTR_VAL(cookie->value), ",; \t\r\n\013\014") != nullptr) { + if (!cookie->encode && cookie->value && strpbrk(ZSTR_VAL(cookie->value), ",; \t\r\n\013\014") != nullptr) { php_swoole_error(E_WARNING, "Cookie value cannot contain " ILLEGAL_COOKIE_CHARACTER); - RETURN_FALSE; + return false; } if (cookie->path && strpbrk(ZSTR_VAL(cookie->path), ",; \t\r\n\013\014") != NULL) { php_swoole_error(E_WARNING, "Cookie path option cannot contain " ILLEGAL_COOKIE_CHARACTER); - RETURN_FALSE; + return false; } if (cookie->domain && strpbrk(ZSTR_VAL(cookie->domain), ",; \t\r\n\013\014") != NULL) { php_swoole_error(E_WARNING, "Cookie domain option cannot contain " ILLEGAL_COOKIE_CHARACTER); - RETURN_FALSE; + return false; } #ifdef ZEND_ENABLE_ZVAL_LONG64 if (cookie->expires >= 253402300800) { php_swoole_error(E_WARNING, "Cookie expires option cannot have a year greater than 9999"); - RETURN_FALSE; + return false; } #endif - if (url_encode && cookie->value && ZSTR_LEN(cookie->value) > 0) { + if (cookie->encode && cookie->value && ZSTR_LEN(cookie->value) > 0) { zend_string *encoded_value = php_url_encode(ZSTR_VAL(cookie->value), ZSTR_LEN(cookie->value)); zend_string_release(cookie->value); cookie->value = encoded_value; @@ -1022,14 +1015,62 @@ static void php_swoole_http_response_cookie(INTERNAL_FUNCTION_PARAMETERS, const zend_string *data = cookie->create(); add_next_index_stringl( - swoole_http_init_and_read_property( - swoole_http_response_ce, ctx->response.zobject, &ctx->response.zcookie, SW_ZSTR_KNOWN(SW_ZEND_STR_COOKIE)), - ZSTR_VAL(data), - ZSTR_LEN(data)); + swoole_http_init_and_read_property( + swoole_http_response_ce, ctx->response.zobject, &ctx->response.zcookie, SW_ZSTR_KNOWN(SW_ZEND_STR_COOKIE)), + ZSTR_VAL(data), + ZSTR_LEN(data)); smart_str_free(&cookie->buffer); cookie->buffer = {0}; - RETURN_TRUE; + return true; +} + +static void php_swoole_http_response_cookie(INTERNAL_FUNCTION_PARAMETERS, const bool encode) { + HttpCookie cookie = {}; + cookie.encode = encode; + + ZEND_PARSE_PARAMETERS_START(1, 10) + Z_PARAM_STR(cookie.name) + Z_PARAM_OPTIONAL + Z_PARAM_STR(cookie.value) + Z_PARAM_LONG(cookie.expires) + Z_PARAM_STR(cookie.path) + Z_PARAM_STR(cookie.domain) + Z_PARAM_BOOL(cookie.secure) + Z_PARAM_BOOL(cookie.httpOnly) + Z_PARAM_STR(cookie.sameSite) + Z_PARAM_STR(cookie.priority) + Z_PARAM_BOOL(cookie.partitioned) + ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); + + if (cookie.name) { + zend_string_addref(cookie.name); + } + + if (cookie.value && ZSTR_LEN(cookie.value) > 0) { + zend_string_addref(cookie.value); + } else { + cookie.value = nullptr; + } + + if (cookie.path) { + zend_string_addref(cookie.path); + } + + if (cookie.domain) { + zend_string_addref(cookie.domain); + } + + if (cookie.sameSite) { + zend_string_addref(cookie.sameSite); + } + + if (cookie.priority) { + zend_string_addref(cookie.priority); + } + + bool result = php_swoole_http_response_create_cookie(&cookie, ZEND_THIS); + RETURN_BOOL(result); } static PHP_METHOD(swoole_http_response, cookie) { @@ -1040,6 +1081,21 @@ static PHP_METHOD(swoole_http_response, rawcookie) { php_swoole_http_response_cookie(INTERNAL_FUNCTION_PARAM_PASSTHRU, false); } +static PHP_METHOD(swoole_http_response, objectCookie) { + zval *zcookie = nullptr; + ZEND_PARSE_PARAMETERS_START(1,1) + Z_PARAM_ZVAL(zcookie) + ZEND_PARSE_PARAMETERS_END(); + + HttpCookie *cookie = php_swoole_http_response_get_and_check_cookie(zcookie); + if (UNEXPECTED(!cookie)) { + RETURN_FALSE; + } + + bool result = php_swoole_http_response_create_cookie(cookie, ZEND_THIS); + RETURN_BOOL(result); +} + static PHP_METHOD(swoole_http_response, status) { zend_long http_status; char *reason = nullptr; diff --git a/tests/swoole_http2_client_coro/cookies.phpt b/tests/swoole_http2_client_coro/cookies.phpt index b7ad9194c3f..04a4b6cb4e1 100644 --- a/tests/swoole_http2_client_coro/cookies.phpt +++ b/tests/swoole_http2_client_coro/cookies.phpt @@ -35,11 +35,8 @@ $pm->childFunc = function () use ($pm) { $pm->wakeup(); }); $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) { - $cookie = new Swoole\Http\Cookie(); foreach ($request->cookie as $name => $value) { - $cookie->setName($name); - $cookie->setValue($value); - $response->cookie($cookie); + $response->cookie($name, $value); } $response->end('OK'); }); diff --git a/tests/swoole_http2_server_coro/cookies.phpt b/tests/swoole_http2_server_coro/cookies.phpt index eaebd699421..9dd0dfb6083 100644 --- a/tests/swoole_http2_server_coro/cookies.phpt +++ b/tests/swoole_http2_server_coro/cookies.phpt @@ -46,11 +46,8 @@ $pm->childFunc = function () use ($pm) { ]); $http->handle('/', function (Swoole\Http\Request $request, Swoole\Http\Response $response) { $response->header('id', $request->header['id']); - $cookie = new Swoole\Http\Cookie(); foreach ($request->cookie as $name => $value) { - $cookie->setName($name); - $cookie->setValue($value); - $response->cookie($cookie); + $response->cookie($name, $value); } $response->end('OK'); }); diff --git a/tests/swoole_http_client_coro/issue_2664.phpt b/tests/swoole_http_client_coro/issue_2664.phpt index 6d052c6e3d6..4c9f902889e 100644 --- a/tests/swoole_http_client_coro/issue_2664.phpt +++ b/tests/swoole_http_client_coro/issue_2664.phpt @@ -20,36 +20,10 @@ $pm->childFunc = function () use ($pm) { }); $server->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) use ($pm) { $time_left = time() + 84600; - - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('key1'); - $cookie->setValue('val1'); - $cookie->setExpires($time_left); - $cookie->setPath('/'); - $cookie->setDomain('id.test.com'); - $response->cookie($cookie); - - $cookie->setName('key1'); - $cookie->setValue(''); - $cookie->setExpires(0); - $cookie->setPath('/'); - $cookie->setDomain('test.com'); - $response->cookie($cookie); - - $cookie->setName('key1'); - $cookie->setValue('val2'); - $cookie->setExpires($time_left); - $cookie->setPath('/'); - $cookie->setDomain('id.test.com'); - $response->cookie($cookie); - - $cookie->setName('key2'); - $cookie->setValue(''); - $cookie->setExpires(0); - $cookie->setPath('/'); - $cookie->setDomain('test.com'); - $response->cookie($cookie); - + $response->cookie('key1', 'val1', $time_left, '/', 'id.test.com'); + $response->cookie('key1', '', 0, '/', 'test.com'); + $response->cookie('key2', 'val2', $time_left, '/', 'id.test.com'); + $response->cookie('key2', '', 0, '/', 'test.com'); $response->end("

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

"); }); $server->start(); @@ -64,7 +38,7 @@ array(4) { [1]=> string(62) "key1=deleted; expires=%s; Max-Age=0" [2]=> - string(91) "key1=val2; expires=%s; Max-Age=84600; path=/; domain=id.test.com" + string(91) "key2=val2; expires=%s; Max-Age=84600; path=/; domain=id.test.com" [3]=> string(62) "key2=deleted; expires=%s; Max-Age=0" } diff --git a/tests/swoole_http_server/bug_2368.phpt b/tests/swoole_http_server/bug_2368.phpt index 6bd06febe05..281aaa43aa5 100644 --- a/tests/swoole_http_server/bug_2368.phpt +++ b/tests/swoole_http_server/bug_2368.phpt @@ -28,10 +28,7 @@ $pm->childFunc = function () use ($pm) { 'log_file' => '/dev/null', )); $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) { - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('name'); - $cookie->setValue(COOKIE); - $response->cookie($cookie); + $response->cookie('name', COOKIE); $response->end(); }); $http->start(); diff --git a/tests/swoole_http_server/bug_5146.phpt b/tests/swoole_http_server/bug_5146.phpt index 06e55c8672d..2efbbc39dc1 100644 --- a/tests/swoole_http_server/bug_5146.phpt +++ b/tests/swoole_http_server/bug_5146.phpt @@ -33,12 +33,11 @@ $pm->childFunc = function () use ($pm) { }); $http->on('request', function (Request $request, Response $response) use ($http) { $previous = memory_get_usage(); - - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('test_cookie'); - $cookie->setValue('hello'); - $cookie->setExpires(time() + (24 * 60 * 60)); - $response->cookie($cookie); + $response->cookie( + 'test_cookie', + 'hello', + time() + (24 * 60 * 60) + ); global $previous; global $item; diff --git a/tests/swoole_http_server/cookieAlias.phpt b/tests/swoole_http_server/cookieAlias.phpt new file mode 100644 index 00000000000..0a7c173beff --- /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->setName('key1') + ->setValue('val1') + ->setExpires(time() + 84600) + ->setPath('/') + ->setDomain('id.test.com') + ->setSecure(true) + ->setHttpOnly(true) + ->setSameSite('None') + ->setPriority('High') + ->setPartitioned(true); + $response->setObjectCookie($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->setValue(''); + $response->setObjectCookie($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_delete.phpt b/tests/swoole_http_server/cookie_delete.phpt index 730635a4b20..59421cc3eb6 100644 --- a/tests/swoole_http_server/cookie_delete.phpt +++ b/tests/swoole_http_server/cookie_delete.phpt @@ -33,51 +33,14 @@ $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) { - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('cookie1'); - $cookie->setValue(null); - $response->cookie($cookie); - - $cookie->reset(); - $cookie->setName('cookie2'); - $cookie->setValue(''); - $response->cookie($cookie); - - $cookie->reset(); - $cookie->setName('cookie3'); - $cookie->setValue('cookie3'); - $cookie->setExpires(0); - $response->cookie($cookie); // must be > 0 - - $cookie->reset(); - $cookie->setName('cookie4'); - $cookie->setValue('cookie4'); - $cookie->setExpires(-1); - $response->cookie($cookie); // must be > 0 - - $cookie->reset(); - $cookie->setName('cookie5'); - $cookie->setValue('cookie5'); - $cookie->setExpires(1); - $response->cookie($cookie); - - $cookie->reset(); - $cookie->setName('cookie6'); - $cookie->setValue(null); - $cookie->setExpires(0); - $response->cookie($cookie); - - $cookie->reset(); - $cookie->setName('cookie7'); - $cookie->setValue(null); - $cookie->setExpires(-1); - $response->cookie($cookie); - - $cookie->reset(); - $cookie->setName('cookie8'); - $cookie->setValue(null); - $cookie->setExpires(1); - $response->cookie($cookie); + $response->cookie('cookie1', null); + $response->cookie('cookie2', ''); + $response->cookie('cookie3', 'cookie3', 0); // must be > 0 + $response->cookie('cookie4', 'cookie4', -1); // must be > 0 + $response->cookie('cookie5', 'cookie5', 1); + $response->cookie('cookie6', null, 0); + $response->cookie('cookie7', null, -1); + $response->cookie('cookie8', null, 1); $response->end(); }); $http->start(); diff --git a/tests/swoole_http_server/cookie_samesite.phpt b/tests/swoole_http_server/cookie_samesite.phpt index 875c82ea043..17b6707ee09 100644 --- a/tests/swoole_http_server/cookie_samesite.phpt +++ b/tests/swoole_http_server/cookie_samesite.phpt @@ -24,16 +24,7 @@ $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) { - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('a'); - $cookie->setValue('123'); - $cookie->setExpires(0); - $cookie->setPath(''); - $cookie->setDomain(''); - $cookie->setSecure(false); - $cookie->setHttpOnly(false); - $cookie->setSameSite('Lax'); - $response->cookie($cookie); + $response->cookie('a', '123', 0, '', '', false, false, 'Lax'); $response->end(); }); $http->start(); diff --git a/tests/swoole_http_server/cookie_vs_rawcookie.phpt b/tests/swoole_http_server/cookie_vs_rawcookie.phpt index 2888b9d391c..53f7e9f9208 100644 --- a/tests/swoole_http_server/cookie_vs_rawcookie.phpt +++ b/tests/swoole_http_server/cookie_vs_rawcookie.phpt @@ -14,7 +14,7 @@ $pm->parentFunc = function () use ($pm) { Assert::same($cli->statusCode, 200); Assert::assert($cli->set_cookie_headers === [ - 'cookie=' . urlencode($cookie) + 'cookie=' . urlencode($cookie), ] ); }); @@ -41,15 +41,8 @@ $pm->childFunc = function () use ($pm) { $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']); - - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('cookie'); - $cookie->setValue($request->get['cookie']); - $response->cookie($cookie); - - $cookie->setName('rawcookie'); - $cookie->setValue($request->get['cookie']); - $response->rawcookie($cookie); + $response->cookie('cookie', $request->get['cookie']); + $response->rawcookie('rawcookie', $request->get['cookie']); $response->end(); }); $http->start(); diff --git a/tests/swoole_http_server/max-age.phpt b/tests/swoole_http_server/max-age.phpt index d01efb249d7..610f1faa2da 100644 --- a/tests/swoole_http_server/max-age.phpt +++ b/tests/swoole_http_server/max-age.phpt @@ -35,21 +35,8 @@ $pm->childFunc = function () use ($pm) { }); $http->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) use ($pm) { - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('test'); - $cookie->setValue('123456789'); - $cookie->setExpires(time() + 3600); - $cookie->setPath('/'); - $cookie->setDomain('example.com'); - $cookie->setSecure(true); - $cookie->setHttpOnly(true); - $cookie->setSameSite('None'); - $response->cookie($cookie); - - $cookie->reset(); - $cookie->setName('test'); - $cookie->setValue(''); - $response->cookie($cookie); + $response->cookie('test', '123456789', time() + 3600, '/', 'example.com', true, true, 'None'); + $response->cookie('test', ''); $response->end(); }); $http->start(); diff --git a/tests/swoole_http_server/new_cookie.phpt b/tests/swoole_http_server/new_cookie.phpt index 79eeabd6fc4..97353f3ca46 100644 --- a/tests/swoole_http_server/new_cookie.phpt +++ b/tests/swoole_http_server/new_cookie.phpt @@ -22,7 +22,7 @@ $cookie->reset(); var_dump($cookie->getCookie()); ?> --EXPECTF-- -array(9) { +array(10) { ["name"]=> string(4) "test" ["value"]=> @@ -33,6 +33,8 @@ array(9) { string(4) "test" ["priority"]=> string(0) "" + ["encode"]=> + bool(true) ["expires"]=> int(%d) ["secure"]=> @@ -42,7 +44,7 @@ array(9) { ["partitioned"]=> bool(false) } -array(9) { +array(10) { ["name"]=> string(0) "" ["value"]=> @@ -53,6 +55,8 @@ array(9) { string(0) "" ["priority"]=> string(0) "" + ["encode"]=> + bool(true) ["expires"]=> int(0) ["secure"]=> diff --git a/tests/swoole_http_server/objectCookie.phpt b/tests/swoole_http_server/objectCookie.phpt new file mode 100644 index 00000000000..7ee5bda12ec --- /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->setName('key1') + ->setValue('val1') + ->setExpires(time() + 84600) + ->setPath('/') + ->setDomain('id.test.com') + ->setSecure(true) + ->setHttpOnly(true) + ->setSameSite('None') + ->setPriority('High') + ->setPartitioned(true); + $response->setObjectCookie($cookie); + $cookie->setValue(''); + $response->setObjectCookie($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..0f9d34268fc --- /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->setName('key1') + ->setValue('val1') + ->setExpires(time() + 84600) + ->setPath('/') + ->setDomain('id.test.com') + ->setSecure(true) + ->setHttpOnly(true) + ->setSameSite('None') + ->setPriority('High') + ->setPartitioned(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 b96ac145f8e..59a0e2e33b9 100644 --- a/tests/swoole_http_server/rawCookie.phpt +++ b/tests/swoole_http_server/rawCookie.phpt @@ -42,26 +42,11 @@ $pm->childFunc = function () use ($pm, $simple_http_server) { $secure = false; $httpOnly = true; // string $name [, string $value = "" [, int $expire = 0 [, string $path = "" [, string $domain = "" [, bool $secure = false [, bool $httponly = false ]]]]]] - - $cookie = new Swoole\Http\Cookie(); - $cookie->setName($name); - $cookie->setValue($value); - $cookie->setExpires($expire); - $cookie->setPath($path); - $cookie->setDomain($domain); - $cookie->setSecure($secure); - $cookie->setHttpOnly($httpOnly); - $response->cookie($cookie); - + $response->cookie($name, $value, $expire, $path, $domain, $secure, $httpOnly); $expect = "name=value; path=/; HttpOnly"; Assert::assert(in_array($expect, $response->cookie, true)); - - $response->cookie($cookie); - - $cookie->reset(); - $cookie->setName("rawcontent"); - $cookie->setValue($request->rawcontent()); - $response->rawcookie($cookie); + $response->cookie($name, $value, $expire, $path, $domain, $secure, $httpOnly); + $response->rawcookie("rawcontent", $request->rawcontent()); $response->end("Hello World!"); }); $http->start(); diff --git a/tests/swoole_http_server/too_many_special_chars_in_cookie.phpt b/tests/swoole_http_server/too_many_special_chars_in_cookie.phpt index 587d2f35d9c..1f2613472de 100644 --- a/tests/swoole_http_server/too_many_special_chars_in_cookie.phpt +++ b/tests/swoole_http_server/too_many_special_chars_in_cookie.phpt @@ -32,13 +32,7 @@ $pm->childFunc = function () use ($pm) { if ($pre_cookie) { Assert::same($request->cookie['foo'], $pre_cookie); } - - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('foo'); - $cookie->setValue($pre_cookie = $pm->getRandomData()); - $cookie->setExpires(time() + 60 * 30); - $cookie->setPath('/'); - $response->cookie($cookie); + $response->cookie('foo', $pre_cookie = $pm->getRandomData(), time() + 60 * 30, '/'); $response->end(); }); $http->start(); diff --git a/tests/swoole_http_server_coro/check_cookie_crlf.phpt b/tests/swoole_http_server_coro/check_cookie_crlf.phpt index 878d56d5595..c81d1119471 100644 --- a/tests/swoole_http_server_coro/check_cookie_crlf.phpt +++ b/tests/swoole_http_server_coro/check_cookie_crlf.phpt @@ -37,20 +37,13 @@ $pm->childFunc = function () use ($pm) { $server->handle('/rawcookie', function (Request $request, Response $response) { $value = "cn\r\nmalicious-header:injected\r\nContent-Length:27\r\n\r\n

malicious response body"; - - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('lang'); - $cookie->setValue($value); - $response->rawcookie($cookie); + $response->rawcookie('lang', $value); $response->end('hello world'); }); $server->handle('/cookie', function (Request $request, Response $response) { $value = "cn\r\nmalicious-header:injected\r\nContent-Length:27\r\n\r\n

malicious response body"; - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('lang'); - $cookie->setValue($value); - $response->cookie($cookie); + $response->cookie('lang', $value); $response->end('hello world'); }); diff --git a/tests/swoole_http_server_coro/websocket.phpt b/tests/swoole_http_server_coro/websocket.phpt index 624d8f03676..4f50b2ed708 100644 --- a/tests/swoole_http_server_coro/websocket.phpt +++ b/tests/swoole_http_server_coro/websocket.phpt @@ -37,12 +37,7 @@ $pm->childFunc = function () use ($pm) { $server = new Co\Http\Server("127.0.0.1", $pm->getFreePort(), false); $server->handle('/websocket', function ($request, $ws) { $ws->header('x-swoole', 'hello'); - - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('test-file'); - $cookie->setValue(__FILE__); - $ws->cookie($cookie); - + $ws->cookie('test-file', __FILE__); $ws->upgrade(); while (true) { $frame = $ws->recv(); diff --git a/tests/swoole_websocket_server/set_cookie_on_before_handshake_response.phpt b/tests/swoole_websocket_server/set_cookie_on_before_handshake_response.phpt index 69218a67361..182aef947d9 100644 --- a/tests/swoole_websocket_server/set_cookie_on_before_handshake_response.phpt +++ b/tests/swoole_websocket_server/set_cookie_on_before_handshake_response.phpt @@ -30,10 +30,7 @@ $pm->childFunc = function () use ($pm) { $pm->wakeup(); }); $server->on('beforeHandShakeResponse', function (Server $server, Request $request, Response $response) { - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('abc'); - $cookie->setValue('def'); - $response->cookie($cookie); + $response->cookie('abc', 'def'); }); $server->on('message', function () { }); $server->start(); diff --git a/tests/swoole_websocket_server/set_cookie_on_handshake.phpt b/tests/swoole_websocket_server/set_cookie_on_handshake.phpt index 8496eaa2609..bc0b756a212 100644 --- a/tests/swoole_websocket_server/set_cookie_on_handshake.phpt +++ b/tests/swoole_websocket_server/set_cookie_on_handshake.phpt @@ -54,12 +54,7 @@ $pm->childFunc = function () use ($pm) { foreach ($headers as $key => $val) { $response->header($key, $val); } - - $cookie = new Swoole\Http\Cookie(); - $cookie->setName('abc'); - $cookie->setValue('def'); - $response->cookie($cookie); - + $response->cookie('abc', 'def'); $response->status(101); $response->end(); return true; From 483ec419c8f4688e38cd209dacae6fe05d3b18f0 Mon Sep 17 00:00:00 2001 From: MARiA so cute <33935209+NathanFreeman@users.noreply.github.com> Date: Thu, 18 Jul 2024 16:22:56 +0800 Subject: [PATCH 3/8] fix error --- ext-src/swoole_http_cookie.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext-src/swoole_http_cookie.cc b/ext-src/swoole_http_cookie.cc index 7c56333a7a4..391ffb34461 100644 --- a/ext-src/swoole_http_cookie.cc +++ b/ext-src/swoole_http_cookie.cc @@ -141,7 +141,7 @@ static PHP_METHOD(swoole_http_cookie, setValue) { zend_bool encode = true; HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); - ZEND_PARSE_PARAMETERS_START(0, 1) + ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL Z_PARAM_STR(value) Z_PARAM_BOOL(encode) From ff1a0c0fdc55450bae5930bd59213bf1570a9730 Mon Sep 17 00:00:00 2001 From: NathanFreeman <1056159381@qq.com> Date: Sat, 20 Jul 2024 18:16:33 +0800 Subject: [PATCH 4/8] optimize code --- ext-src/stubs/php_swoole_http_cookie.stub.php | 20 +++--- .../stubs/php_swoole_http_cookie_arginfo.h | 22 +++---- ext-src/swoole_http_cookie.cc | 62 +++++++++---------- tests/swoole_http_server/cookieAlias.phpt | 22 +++---- tests/swoole_http_server/objectCookie.phpt | 22 +++---- .../objectCookieMemory.phpt | 20 +++--- 6 files changed, 84 insertions(+), 84 deletions(-) diff --git a/ext-src/stubs/php_swoole_http_cookie.stub.php b/ext-src/stubs/php_swoole_http_cookie.stub.php index a6efaee03d3..1499fad6a94 100644 --- a/ext-src/stubs/php_swoole_http_cookie.stub.php +++ b/ext-src/stubs/php_swoole_http_cookie.stub.php @@ -2,16 +2,16 @@ namespace Swoole\Http { class Cookie { public function __construct() {} - public function setName(string $name): \Swoole\Http\Cookie {} - public function setValue(string $value = '', bool $encode = true): \Swoole\Http\Cookie {} - public function setExpires(int $expires = 0): \Swoole\Http\Cookie {} - public function setPath(string $path = '/'): \Swoole\Http\Cookie {} - public function setDomain(string $domain = ''): \Swoole\Http\Cookie {} - public function setSecure(bool $secure = false): \Swoole\Http\Cookie {} - public function setHttpOnly(bool $httpOnly = false): \Swoole\Http\Cookie {} - public function setSameSite(string $sameSite = ''): \Swoole\Http\Cookie {} - public function setPriority(string $priority = ''): \Swoole\Http\Cookie {} - public function setPartitioned(bool $partitioned = false): \Swoole\Http\Cookie {} + public function withName(string $name): \Swoole\Http\Cookie {} + public function withValue(string $value = '', bool $encode = true): \Swoole\Http\Cookie {} + public function withExpires(int $expires = 0): \Swoole\Http\Cookie {} + public function withPath(string $path = '/'): \Swoole\Http\Cookie {} + public function withDomain(string $domain = ''): \Swoole\Http\Cookie {} + public function withSecure(bool $secure = false): \Swoole\Http\Cookie {} + public function withHttpOnly(bool $httpOnly = false): \Swoole\Http\Cookie {} + public function withSameSite(string $sameSite = ''): \Swoole\Http\Cookie {} + public function withPriority(string $priority = ''): \Swoole\Http\Cookie {} + public function withPartitioned(bool $partitioned = false): \Swoole\Http\Cookie {} public function getCookie(): array {} public function reset(): bool {} } diff --git a/ext-src/stubs/php_swoole_http_cookie_arginfo.h b/ext-src/stubs/php_swoole_http_cookie_arginfo.h index ebf74b7cceb..1f113a9d4a5 100644 --- a/ext-src/stubs/php_swoole_http_cookie_arginfo.h +++ b/ext-src/stubs/php_swoole_http_cookie_arginfo.h @@ -1,47 +1,47 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 02aefd39f4852eea3258eea8edb7000fa86af163 */ + * Stub hash: 3a257967f878f1186db07db30ea2caf29bb97fa7 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Swoole_Http_Cookie___construct, 0, 0, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setName, 0, 1, Swoole\\Http\\Cookie, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_withName, 0, 1, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setValue, 0, 0, Swoole\\Http\\Cookie, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_withValue, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_STRING, 0, "\'\'") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encode, _IS_BOOL, 0, "true") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setExpires, 0, 0, Swoole\\Http\\Cookie, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_withExpires, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, expires, IS_LONG, 0, "0") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setPath, 0, 0, Swoole\\Http\\Cookie, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_withPath, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, path, IS_STRING, 0, "\'/\'") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setDomain, 0, 0, Swoole\\Http\\Cookie, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_withDomain, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, domain, IS_STRING, 0, "\'\'") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setSecure, 0, 0, Swoole\\Http\\Cookie, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_withSecure, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, secure, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setHttpOnly, 0, 0, Swoole\\Http\\Cookie, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_withHttpOnly, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, httpOnly, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setSameSite, 0, 0, Swoole\\Http\\Cookie, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_withSameSite, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, sameSite, IS_STRING, 0, "\'\'") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setPriority, 0, 0, Swoole\\Http\\Cookie, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_withPriority, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, priority, IS_STRING, 0, "\'\'") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_setPartitioned, 0, 0, Swoole\\Http\\Cookie, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Swoole_Http_Cookie_withPartitioned, 0, 0, Swoole\\Http\\Cookie, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, partitioned, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() diff --git a/ext-src/swoole_http_cookie.cc b/ext-src/swoole_http_cookie.cc index 391ffb34461..f281bbfacbb 100644 --- a/ext-src/swoole_http_cookie.cc +++ b/ext-src/swoole_http_cookie.cc @@ -66,17 +66,17 @@ static void php_swoole_http_cookie_free_object(zend_object *object) { SW_EXTERN_C_BEGIN static PHP_METHOD(swoole_http_cookie, __construct); -static PHP_METHOD(swoole_http_cookie, setName); -static PHP_METHOD(swoole_http_cookie, setValue); -static PHP_METHOD(swoole_http_cookie, setExpires); -static PHP_METHOD(swoole_http_cookie, setPath); -static PHP_METHOD(swoole_http_cookie, setDomain); -static PHP_METHOD(swoole_http_cookie, setSecure); -static PHP_METHOD(swoole_http_cookie, setHttpOnly); -static PHP_METHOD(swoole_http_cookie, setSameSite); -static PHP_METHOD(swoole_http_cookie, setPriority); -static PHP_METHOD(swoole_http_cookie, setPartitioned); -static PHP_METHOD(swoole_http_cookie, setUrlEncode); +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, withUrlEncode); static PHP_METHOD(swoole_http_cookie, getCookie); static PHP_METHOD(swoole_http_cookie, reset); SW_EXTERN_C_END @@ -85,16 +85,16 @@ SW_EXTERN_C_END 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, setName, arginfo_class_Swoole_Http_Cookie_setName, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_cookie, setValue, arginfo_class_Swoole_Http_Cookie_setValue, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_cookie, setExpires, arginfo_class_Swoole_Http_Cookie_setExpires, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_cookie, setPath, arginfo_class_Swoole_Http_Cookie_setPath, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_cookie, setDomain, arginfo_class_Swoole_Http_Cookie_setDomain, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_cookie, setSecure, arginfo_class_Swoole_Http_Cookie_setSecure, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_cookie, setHttpOnly, arginfo_class_Swoole_Http_Cookie_setHttpOnly, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_cookie, setSameSite, arginfo_class_Swoole_Http_Cookie_setSameSite, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_cookie, setPriority, arginfo_class_Swoole_Http_Cookie_setPriority, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_cookie, setPartitioned, arginfo_class_Swoole_Http_Cookie_setPartitioned, 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, getCookie, arginfo_class_Swoole_Http_Cookie_getCookie, ZEND_ACC_PUBLIC) PHP_ME(swoole_http_cookie, reset, arginfo_class_Swoole_Http_Cookie_reset, ZEND_ACC_PUBLIC) PHP_FE_END @@ -118,7 +118,7 @@ static PHP_METHOD(swoole_http_cookie, __construct) { RETURN_TRUE; } -static PHP_METHOD(swoole_http_cookie, setName) { +static PHP_METHOD(swoole_http_cookie, withName) { zend_string *name = nullptr; HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); @@ -136,7 +136,7 @@ static PHP_METHOD(swoole_http_cookie, setName) { RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } -static PHP_METHOD(swoole_http_cookie, setValue) { +static PHP_METHOD(swoole_http_cookie, withValue) { zend_string *value = nullptr; zend_bool encode = true; HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); @@ -161,7 +161,7 @@ static PHP_METHOD(swoole_http_cookie, setValue) { RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } -static PHP_METHOD(swoole_http_cookie, setExpires) { +static PHP_METHOD(swoole_http_cookie, withExpires) { zend_long expires = 0; HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); @@ -174,7 +174,7 @@ static PHP_METHOD(swoole_http_cookie, setExpires) { RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } -static PHP_METHOD(swoole_http_cookie, setPath) { +static PHP_METHOD(swoole_http_cookie, withPath) { zend_string *path = nullptr; HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); @@ -193,7 +193,7 @@ static PHP_METHOD(swoole_http_cookie, setPath) { RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } -static PHP_METHOD(swoole_http_cookie, setDomain) { +static PHP_METHOD(swoole_http_cookie, withDomain) { zend_string *domain = nullptr; HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); @@ -212,7 +212,7 @@ static PHP_METHOD(swoole_http_cookie, setDomain) { RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } -static PHP_METHOD(swoole_http_cookie, setSecure) { +static PHP_METHOD(swoole_http_cookie, withSecure) { zend_bool secure = false; HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); @@ -225,7 +225,7 @@ static PHP_METHOD(swoole_http_cookie, setSecure) { RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } -static PHP_METHOD(swoole_http_cookie, setHttpOnly) { +static PHP_METHOD(swoole_http_cookie, withHttpOnly) { zend_bool httpOnly = false; HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); @@ -238,7 +238,7 @@ static PHP_METHOD(swoole_http_cookie, setHttpOnly) { RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } -static PHP_METHOD(swoole_http_cookie, setSameSite) { +static PHP_METHOD(swoole_http_cookie, withSameSite) { zend_string *sameSite = nullptr; HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); @@ -257,7 +257,7 @@ static PHP_METHOD(swoole_http_cookie, setSameSite) { RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } -static PHP_METHOD(swoole_http_cookie, setPriority) { +static PHP_METHOD(swoole_http_cookie, withPriority) { zend_string *priority = nullptr; HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); @@ -276,7 +276,7 @@ static PHP_METHOD(swoole_http_cookie, setPriority) { RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); } -static PHP_METHOD(swoole_http_cookie, setPartitioned) { +static PHP_METHOD(swoole_http_cookie, withPartitioned) { zend_bool partitioned = false; HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); diff --git a/tests/swoole_http_server/cookieAlias.phpt b/tests/swoole_http_server/cookieAlias.phpt index 0a7c173beff..ed8aac44247 100644 --- a/tests/swoole_http_server/cookieAlias.phpt +++ b/tests/swoole_http_server/cookieAlias.phpt @@ -20,21 +20,21 @@ $pm->childFunc = function () use ($pm) { }); $server->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) use ($pm) { $cookie = new Swoole\Http\Cookie(); - $cookie->setName('key1') - ->setValue('val1') - ->setExpires(time() + 84600) - ->setPath('/') - ->setDomain('id.test.com') - ->setSecure(true) - ->setHttpOnly(true) - ->setSameSite('None') - ->setPriority('High') - ->setPartitioned(true); + $cookie->withName('key1') + ->withValue('val1') + ->withExpires(time() + 84600) + ->withPath('/') + ->withDomain('id.test.com') + ->withSecure(true) + ->withHttpOnly(true) + ->withSameSite('None') + ->withPriority('High') + ->withPartitioned(true); $response->setObjectCookie($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->setValue(''); + $cookie->withValue(''); $response->setObjectCookie($cookie); $response->end("

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

"); }); diff --git a/tests/swoole_http_server/objectCookie.phpt b/tests/swoole_http_server/objectCookie.phpt index 7ee5bda12ec..7f217368ce1 100644 --- a/tests/swoole_http_server/objectCookie.phpt +++ b/tests/swoole_http_server/objectCookie.phpt @@ -20,18 +20,18 @@ $pm->childFunc = function () use ($pm) { }); $server->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) use ($pm) { $cookie = new Swoole\Http\Cookie(); - $cookie->setName('key1') - ->setValue('val1') - ->setExpires(time() + 84600) - ->setPath('/') - ->setDomain('id.test.com') - ->setSecure(true) - ->setHttpOnly(true) - ->setSameSite('None') - ->setPriority('High') - ->setPartitioned(true); + $cookie->withName('key1') + ->withValue('val1') + ->withExpires(time() + 84600) + ->withPath('/') + ->withDomain('id.test.com') + ->withSecure(true) + ->withHttpOnly(true) + ->withSameSite('None') + ->withPriority('High') + ->withPartitioned(true); $response->setObjectCookie($cookie); - $cookie->setValue(''); + $cookie->withValue(''); $response->setObjectCookie($cookie); $response->end("

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

"); }); diff --git a/tests/swoole_http_server/objectCookieMemory.phpt b/tests/swoole_http_server/objectCookieMemory.phpt index 0f9d34268fc..884306bf050 100644 --- a/tests/swoole_http_server/objectCookieMemory.phpt +++ b/tests/swoole_http_server/objectCookieMemory.phpt @@ -36,16 +36,16 @@ $pm->childFunc = function () use ($pm) { $cookie = new Swoole\Http\Cookie(); $i = 10000; while($i--) { - $cookie->setName('key1') - ->setValue('val1') - ->setExpires(time() + 84600) - ->setPath('/') - ->setDomain('id.test.com') - ->setSecure(true) - ->setHttpOnly(true) - ->setSameSite('None') - ->setPriority('High') - ->setPartitioned(true); + $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; From ff5ec6a84c04e9ff823d41bfedea5e05334e8d48 Mon Sep 17 00:00:00 2001 From: NathanFreeman <1056159381@qq.com> Date: Sun, 21 Jul 2024 10:43:05 +0800 Subject: [PATCH 5/8] optimize code --- ext-src/swoole_http_cookie.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ext-src/swoole_http_cookie.cc b/ext-src/swoole_http_cookie.cc index f281bbfacbb..de7ddd36050 100644 --- a/ext-src/swoole_http_cookie.cc +++ b/ext-src/swoole_http_cookie.cc @@ -133,7 +133,7 @@ static PHP_METHOD(swoole_http_cookie, withName) { zend_string_addref(name); cookie->name = name; - RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); + RETURN_ZVAL(ZEND_THIS, 1, 0); } static PHP_METHOD(swoole_http_cookie, withValue) { @@ -158,7 +158,7 @@ static PHP_METHOD(swoole_http_cookie, withValue) { cookie->value = value; cookie->encode = encode; } - RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); + RETURN_ZVAL(ZEND_THIS, 1, 0); } static PHP_METHOD(swoole_http_cookie, withExpires) { @@ -171,7 +171,7 @@ static PHP_METHOD(swoole_http_cookie, withExpires) { ZEND_PARSE_PARAMETERS_END(); cookie->expires = expires; - RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); + RETURN_ZVAL(ZEND_THIS, 1, 0); } static PHP_METHOD(swoole_http_cookie, withPath) { @@ -190,7 +190,7 @@ static PHP_METHOD(swoole_http_cookie, withPath) { zend_string_addref(path); cookie->path = path; - RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); + RETURN_ZVAL(ZEND_THIS, 1, 0); } static PHP_METHOD(swoole_http_cookie, withDomain) { @@ -209,7 +209,7 @@ static PHP_METHOD(swoole_http_cookie, withDomain) { zend_string_addref(domain); cookie->domain = domain; - RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); + RETURN_ZVAL(ZEND_THIS, 1, 0); } static PHP_METHOD(swoole_http_cookie, withSecure) { @@ -222,7 +222,7 @@ static PHP_METHOD(swoole_http_cookie, withSecure) { ZEND_PARSE_PARAMETERS_END(); cookie->secure = secure; - RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); + RETURN_ZVAL(ZEND_THIS, 1, 0); } static PHP_METHOD(swoole_http_cookie, withHttpOnly) { @@ -235,7 +235,7 @@ static PHP_METHOD(swoole_http_cookie, withHttpOnly) { ZEND_PARSE_PARAMETERS_END(); cookie->httpOnly = httpOnly; - RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); + RETURN_ZVAL(ZEND_THIS, 1, 0); } static PHP_METHOD(swoole_http_cookie, withSameSite) { @@ -254,7 +254,7 @@ static PHP_METHOD(swoole_http_cookie, withSameSite) { zend_string_addref(sameSite); cookie->sameSite = sameSite; - RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); + RETURN_ZVAL(ZEND_THIS, 1, 0); } static PHP_METHOD(swoole_http_cookie, withPriority) { @@ -273,7 +273,7 @@ static PHP_METHOD(swoole_http_cookie, withPriority) { zend_string_addref(priority); cookie->priority = priority; - RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); + RETURN_ZVAL(ZEND_THIS, 1, 0); } static PHP_METHOD(swoole_http_cookie, withPartitioned) { @@ -286,7 +286,7 @@ static PHP_METHOD(swoole_http_cookie, withPartitioned) { ZEND_PARSE_PARAMETERS_END(); cookie->partitioned = partitioned; - RETURN_OBJ_COPY(Z_OBJ_P(ZEND_THIS)); + RETURN_ZVAL(ZEND_THIS, 1, 0); } static PHP_METHOD(swoole_http_cookie, getCookie) { From 5838b4cdb66f1eb85668a1d62ee4948c2e2dc60c Mon Sep 17 00:00:00 2001 From: hantianfeng Date: Tue, 23 Jul 2024 19:24:05 +0800 Subject: [PATCH 6/8] refactor --- ext-src/php_swoole_http.h | 119 +---- ext-src/stubs/php_swoole_http_cookie.stub.php | 9 +- .../stubs/php_swoole_http_cookie_arginfo.h | 11 +- .../stubs/php_swoole_http_response.stub.php | 3 +- .../stubs/php_swoole_http_response_arginfo.h | 19 +- ext-src/swoole_http_cookie.cc | 453 +++++++++++------- ext-src/swoole_http_response.cc | 144 ++---- tests/start.sh | 4 + tests/swoole_http_server/cookieAlias.phpt | 4 +- .../cookie_vs_rawcookie.phpt | 19 +- tests/swoole_http_server/new_cookie.phpt | 34 +- tests/swoole_http_server/objectCookie.phpt | 4 +- 12 files changed, 402 insertions(+), 421 deletions(-) diff --git a/ext-src/php_swoole_http.h b/ext-src/php_swoole_http.h index 929d5539a5f..3d60156c2b1 100644 --- a/ext-src/php_swoole_http.h +++ b/ext-src/php_swoole_http.h @@ -213,7 +213,11 @@ struct Context { void free(); }; -struct Cookie { +class Cookie { + private: + bool encode_; + smart_str buffer_ = {0}; + protected: zend_string *name = nullptr; zend_string *value = nullptr; zend_string *path = nullptr; @@ -224,100 +228,25 @@ struct Cookie { zend_bool secure = false; zend_bool httpOnly = false; zend_bool partitioned = false; - zend_bool encode = true; - smart_str buffer = {0}; - - zend_string *create() { - zend_string *date = nullptr; - if (!value) { - smart_str_append(&buffer, name); - 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); - - smart_str_0(&buffer); - return buffer.s; - } - - smart_str_append(&buffer, name); - smart_str_appendc(&buffer, '='); - smart_str_append(&buffer, value); - - if (expires > 0) { - 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) { - smart_str_appends(&buffer, "; path="); - smart_str_append(&buffer, path); - } - - if (domain && ZSTR_LEN(domain) > 0) { - 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"); - } - - smart_str_0(&buffer); - return buffer.s; - } - - ~Cookie() { - if (name) { - zend_string_release(name); - } - - if (value) { - zend_string_release(value); - } - - if (path) { - zend_string_release(path); - } - - if (domain) { - zend_string_release(domain); - } - - if (sameSite) { - zend_string_release(sameSite); - } - - if (priority) { - zend_string_release(priority); - } + 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 *); + zend_string *create(); + void reset(); + void toArray(zval *return_value); + void toString(zval *return_value); + ~Cookie(); }; } // namespace http @@ -382,7 +311,7 @@ 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_response_get_and_check_cookie(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/stubs/php_swoole_http_cookie.stub.php b/ext-src/stubs/php_swoole_http_cookie.stub.php index 1499fad6a94..4017279f166 100644 --- a/ext-src/stubs/php_swoole_http_cookie.stub.php +++ b/ext-src/stubs/php_swoole_http_cookie.stub.php @@ -1,9 +1,9 @@ cookie; } -HttpCookie *php_swoole_http_response_get_and_check_cookie(zval *zobject) { +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; } @@ -76,15 +80,15 @@ 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, withUrlEncode); -static PHP_METHOD(swoole_http_cookie, getCookie); +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, __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) @@ -95,8 +99,9 @@ const zend_function_entry swoole_http_cookie_methods[] = 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, getCookie, arginfo_class_Swoole_Http_Cookie_getCookie, ZEND_ACC_PUBLIC) - PHP_ME(swoole_http_cookie, reset, arginfo_class_Swoole_Http_Cookie_reset, 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 @@ -113,240 +118,326 @@ void php_swoole_http_cookie_minit(int module_number) { std); } -static PHP_METHOD(swoole_http_cookie, __construct) { - php_swoole_http_response_set_cookie(ZEND_THIS, new HttpCookie()); - RETURN_TRUE; +#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); } -static PHP_METHOD(swoole_http_cookie, withName) { - zend_string *name = nullptr; - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); - - ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_STR(name) - ZEND_PARSE_PARAMETERS_END(); - - if (cookie->name) { - zend_string_release(cookie->name); - cookie->name = nullptr; - } +HttpCookie *HttpCookie::withValue(zend_string *_value) { + HTTP_COOKIE_WITH_STR(value); +} - zend_string_addref(name); - cookie->name = name; - RETURN_ZVAL(ZEND_THIS, 1, 0); +HttpCookie *HttpCookie::withDomain(zend_string *_domain) { + HTTP_COOKIE_WITH_STR(domain); } -static PHP_METHOD(swoole_http_cookie, withValue) { - zend_string *value = nullptr; - zend_bool encode = true; - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); +HttpCookie *HttpCookie::withPath(zend_string *_path) { + HTTP_COOKIE_WITH_STR(path); +} - ZEND_PARSE_PARAMETERS_START(0, 2) - Z_PARAM_OPTIONAL - Z_PARAM_STR(value) - Z_PARAM_BOOL(encode) - ZEND_PARSE_PARAMETERS_END(); +HttpCookie *HttpCookie::withSameSite(zend_string *_sameSite) { + HTTP_COOKIE_WITH_STR(sameSite); +} - if (cookie->value) { - zend_string_release(cookie->value); - cookie->value = nullptr; - cookie->encode = true; - } +HttpCookie *HttpCookie::withPriority(zend_string *_priority) { + HTTP_COOKIE_WITH_STR(priority); +} - if (value && ZSTR_LEN(value) > 0) { - zend_string_addref(value); - cookie->value = value; - cookie->encode = encode; - } - RETURN_ZVAL(ZEND_THIS, 1, 0); +HttpCookie *HttpCookie::withExpires(zend_long _expires) { + expires = _expires; + return this; } -static PHP_METHOD(swoole_http_cookie, withExpires) { - zend_long expires = 0; - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); +HttpCookie *HttpCookie::withSecure(zend_bool _secure) { + secure = _secure; + return this; +} - ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_LONG(expires) - ZEND_PARSE_PARAMETERS_END(); +HttpCookie *HttpCookie::withHttpOnly(zend_bool _httpOnly) { + httpOnly = _httpOnly; + return this; +} - cookie->expires = expires; - RETURN_ZVAL(ZEND_THIS, 1, 0); +HttpCookie *HttpCookie::withPartitioned(zend_bool _partitioned) { + partitioned = _partitioned; + return this; } -static PHP_METHOD(swoole_http_cookie, withPath) { - zend_string *path = nullptr; - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); +zend_string *HttpCookie::create() { + zend_string *date = nullptr; + if (name == nullptr || ZSTR_LEN(name) == 0) { + php_swoole_error(E_WARNING, "The name cannot be empty"); + return nullptr; + } - ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_STR(path) - ZEND_PARSE_PARAMETERS_END(); + if (strpbrk(ZSTR_VAL(name), "=" ILLEGAL_COOKIE_CHARACTER) != nullptr) { + php_swoole_error(E_WARNING, "The name cannot contain \"=\", " ILLEGAL_COOKIE_CHARACTER_PRINT); + return nullptr; + } - if (cookie->path) { - zend_string_release(cookie->path); - cookie->path = 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"); + } } - zend_string_addref(path); - cookie->path = path; - RETURN_ZVAL(ZEND_THIS, 1, 0); + return smart_str_extract(&buffer_); } -static PHP_METHOD(swoole_http_cookie, withDomain) { - zend_string *domain = nullptr; - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); +void HttpCookie::reset() { + expires = 0; + secure = false; + httpOnly = false; + partitioned = false; + encode_ = true; - ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_STR(domain) - ZEND_PARSE_PARAMETERS_END(); + if (name) { + zend_string_release(name); + name = nullptr; + } - if (cookie->domain) { - zend_string_release(cookie->domain); - cookie->domain = nullptr; + if (value) { + zend_string_release(value); + value = nullptr; } - zend_string_addref(domain); - cookie->domain = domain; - RETURN_ZVAL(ZEND_THIS, 1, 0); -} + if (path) { + zend_string_release(path); + path = nullptr; + } -static PHP_METHOD(swoole_http_cookie, withSecure) { - zend_bool secure = false; - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + if (domain) { + zend_string_release(domain); + domain = nullptr; + } - ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_BOOL(secure) - ZEND_PARSE_PARAMETERS_END(); + if (sameSite) { + zend_string_release(sameSite); + sameSite = nullptr; + } - cookie->secure = secure; - RETURN_ZVAL(ZEND_THIS, 1, 0); + if (priority) { + zend_string_release(priority); + priority = nullptr; + } + + smart_str_free_ex(&buffer_, false); } -static PHP_METHOD(swoole_http_cookie, withHttpOnly) { - zend_bool httpOnly = false; - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); +#define HTTP_COOKIE_ADD_STR_TO_ARRAY(field) \ + if (field) { \ + add_assoc_str(return_value, #field, field); \ + } else { \ + add_assoc_string(return_value, #field, ""); \ + } - ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_BOOL(httpOnly) - ZEND_PARSE_PARAMETERS_END(); +void HttpCookie::toArray(zval *return_value) { + array_init(return_value); - cookie->httpOnly = httpOnly; - RETURN_ZVAL(ZEND_THIS, 1, 0); + 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); } -static PHP_METHOD(swoole_http_cookie, withSameSite) { - zend_string *sameSite = nullptr; - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); - - ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_STR(sameSite) - ZEND_PARSE_PARAMETERS_END(); - - if (cookie->sameSite) { - zend_string_release(cookie->sameSite); - cookie->sameSite = nullptr; +void HttpCookie::toString(zval *return_value) { + auto cookie_str = create(); + if (!cookie_str) { + reset(); + RETURN_FALSE; } + ZVAL_STR(return_value, cookie_str); +} - zend_string_addref(sameSite); - cookie->sameSite = sameSite; - RETURN_ZVAL(ZEND_THIS, 1, 0); +HttpCookie::~Cookie() { + reset(); } -static PHP_METHOD(swoole_http_cookie, withPriority) { - zend_string *priority = nullptr; - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); +static PHP_METHOD(swoole_http_cookie, __construct) { + zend_bool encode = true; ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_STR(priority) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(encode) ZEND_PARSE_PARAMETERS_END(); - if (cookie->priority) { - zend_string_release(cookie->priority); - cookie->priority = nullptr; - } + php_swoole_http_response_set_cookie(ZEND_THIS, new HttpCookie(encode)); +} - zend_string_addref(priority); - cookie->priority = priority; +#define PHP_METHOD_HTTP_COOKIE_WITH_STR(field) \ + zend_string *field; \ + HttpCookie *cookie = php_swoole_http_get_cookie(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_cookie(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, withPartitioned) { - zend_bool partitioned = false; +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_cookie(ZEND_THIS); ZEND_PARSE_PARAMETERS_START(0, 1) - Z_PARAM_OPTIONAL - Z_PARAM_BOOL(partitioned) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(expires) ZEND_PARSE_PARAMETERS_END(); - cookie->partitioned = partitioned; + cookie->withExpires(expires); RETURN_ZVAL(ZEND_THIS, 1, 0); } -static PHP_METHOD(swoole_http_cookie, getCookie) { - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); - - ZEND_PARSE_PARAMETERS_NONE(); - - array_init(return_value); - cookie->name ? add_assoc_str(return_value, "name", cookie->name) : add_assoc_string(return_value, "name", ""); - cookie->value ? add_assoc_str(return_value, "value", cookie->value) : add_assoc_string(return_value, "value", ""); - cookie->domain ? add_assoc_str(return_value, "domain", cookie->path) : add_assoc_string(return_value, "domain", ""); - cookie->sameSite ? add_assoc_str(return_value, "sameSite", cookie->name) : add_assoc_string(return_value, "sameSite", ""); - cookie->priority ? add_assoc_str(return_value, "priority", cookie->name) : add_assoc_string(return_value, "priority", ""); - add_assoc_bool(return_value, "encode", cookie->encode); - add_assoc_long(return_value, "expires", cookie->expires); - add_assoc_bool(return_value, "secure", cookie->secure); - add_assoc_bool(return_value, "httpOnly", cookie->httpOnly); - add_assoc_bool(return_value, "partitioned", cookie->partitioned); +static PHP_METHOD(swoole_http_cookie, withPath) { + PHP_METHOD_HTTP_COOKIE_WITH_STR(Path); } -static PHP_METHOD(swoole_http_cookie, reset) { - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); - - ZEND_PARSE_PARAMETERS_NONE(); +static PHP_METHOD(swoole_http_cookie, withDomain) { + PHP_METHOD_HTTP_COOKIE_WITH_STR(Domain); +} - cookie->expires = 0; - cookie->secure = false; - cookie->httpOnly = false; - cookie->partitioned = false; - cookie->encode = true; +static PHP_METHOD(swoole_http_cookie, withSecure) { + PHP_METHOD_HTTP_COOKIE_WITH_BOOL(Secure); +} - if (cookie->name) { - zend_string_release(cookie->name); - cookie->name = nullptr; - } +static PHP_METHOD(swoole_http_cookie, withHttpOnly) { + PHP_METHOD_HTTP_COOKIE_WITH_BOOL(HttpOnly); +} - if (cookie->value) { - zend_string_release(cookie->value); - cookie->value = nullptr; - } +static PHP_METHOD(swoole_http_cookie, withSameSite) { + PHP_METHOD_HTTP_COOKIE_WITH_STR(SameSite); +} - if (cookie->path) { - zend_string_release(cookie->path); - cookie->path = nullptr; - } +static PHP_METHOD(swoole_http_cookie, withPriority) { + PHP_METHOD_HTTP_COOKIE_WITH_STR(Priority); +} - if (cookie->domain) { - zend_string_release(cookie->domain); - cookie->domain = nullptr; - } +static PHP_METHOD(swoole_http_cookie, withPartitioned) { + PHP_METHOD_HTTP_COOKIE_WITH_BOOL(Partitioned); +} - if (cookie->sameSite) { - zend_string_release(cookie->sameSite); - cookie->sameSite = nullptr; - } +static PHP_METHOD(swoole_http_cookie, toString) { + php_swoole_http_get_cookie(ZEND_THIS)->toString(return_value); +} - if (cookie->priority) { - zend_string_release(cookie->priority); - cookie->priority = nullptr; - } +static PHP_METHOD(swoole_http_cookie, toArray) { + php_swoole_http_get_cookie(ZEND_THIS)->toArray(return_value); +} - RETURN_TRUE; +static PHP_METHOD(swoole_http_cookie, reset) { + php_swoole_http_get_cookie(ZEND_THIS)->reset(); } diff --git a/ext-src/swoole_http_response.cc b/ext-src/swoole_http_response.cc index 9c0f73eead1..505d194639b 100644 --- a/ext-src/swoole_http_response.cc +++ b/ext-src/swoole_http_response.cc @@ -46,8 +46,6 @@ namespace HttpServer = swoole::http_server; zend_class_entry *swoole_http_response_ce; static zend_object_handlers swoole_http_response_handlers; -#define ILLEGAL_COOKIE_CHARACTER "\",\", \";\", \" \", \"\\t\", \"\\r\", \"\\n\", \"\\013\", or \"\\014\"" - static inline void http_header_key_format(char *key, int length) { int i, state = 0; for (i = 0; i < length; i++) { @@ -139,7 +137,6 @@ static PHP_METHOD(swoole_http_response, sendfile); static PHP_METHOD(swoole_http_response, redirect); static PHP_METHOD(swoole_http_response, cookie); static PHP_METHOD(swoole_http_response, rawcookie); -static PHP_METHOD(swoole_http_response, objectCookie); static PHP_METHOD(swoole_http_response, header); static PHP_METHOD(swoole_http_response, initHeader); static PHP_METHOD(swoole_http_response, isWritable); @@ -167,8 +164,6 @@ const zend_function_entry swoole_http_response_methods[] = 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, objectCookie, arginfo_class_Swoole_Http_Response_objectCookie, ZEND_ACC_PUBLIC) - PHP_MALIAS(swoole_http_response, setObjectCookie, objectCookie, arginfo_class_Swoole_Http_Response_objectCookie, 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) @@ -975,125 +970,72 @@ static bool inline php_swoole_http_response_create_cookie(HttpCookie *cookie, zv return false; } - if (ZSTR_LEN(cookie->name) == 0) { - php_swoole_error(E_WARNING, "Cookie name cannot be empty"); - return false; - } - - if (strpbrk(ZSTR_VAL(cookie->name), "=,; \t\r\n\013\014") != nullptr) { - php_swoole_error(E_WARNING, "Cookie name cannot contain \"=\", " ILLEGAL_COOKIE_CHARACTER); - return false; - } - - if (!cookie->encode && cookie->value && strpbrk(ZSTR_VAL(cookie->value), ",; \t\r\n\013\014") != nullptr) { - php_swoole_error(E_WARNING, "Cookie value cannot contain " ILLEGAL_COOKIE_CHARACTER); - return false; - } - - if (cookie->path && strpbrk(ZSTR_VAL(cookie->path), ",; \t\r\n\013\014") != NULL) { - php_swoole_error(E_WARNING, "Cookie path option cannot contain " ILLEGAL_COOKIE_CHARACTER); + zend_string *cookie_str = cookie->create(); + if (!cookie_str) { + cookie->reset(); return false; } - if (cookie->domain && strpbrk(ZSTR_VAL(cookie->domain), ",; \t\r\n\013\014") != NULL) { - php_swoole_error(E_WARNING, "Cookie domain option cannot contain " ILLEGAL_COOKIE_CHARACTER); - return false; - } - -#ifdef ZEND_ENABLE_ZVAL_LONG64 - if (cookie->expires >= 253402300800) { - php_swoole_error(E_WARNING, "Cookie expires option cannot have a year greater than 9999"); - return false; - } -#endif - - if (cookie->encode && cookie->value && ZSTR_LEN(cookie->value) > 0) { - zend_string *encoded_value = php_url_encode(ZSTR_VAL(cookie->value), ZSTR_LEN(cookie->value)); - zend_string_release(cookie->value); - cookie->value = encoded_value; - } - - zend_string *data = cookie->create(); - add_next_index_stringl( + 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)), - ZSTR_VAL(data), - ZSTR_LEN(data)); + cookie_str); - smart_str_free(&cookie->buffer); - cookie->buffer = {0}; return true; } -static void php_swoole_http_response_cookie(INTERNAL_FUNCTION_PARAMETERS, const bool encode) { - HttpCookie cookie = {}; - cookie.encode = encode; +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; + zend_bool secure = false, httpOnly = false, partitioned = false; + bool result; ZEND_PARSE_PARAMETERS_START(1, 10) - Z_PARAM_STR(cookie.name) - Z_PARAM_OPTIONAL - Z_PARAM_STR(cookie.value) - Z_PARAM_LONG(cookie.expires) - Z_PARAM_STR(cookie.path) - Z_PARAM_STR(cookie.domain) - Z_PARAM_BOOL(cookie.secure) - Z_PARAM_BOOL(cookie.httpOnly) - Z_PARAM_STR(cookie.sameSite) - Z_PARAM_STR(cookie.priority) - Z_PARAM_BOOL(cookie.partitioned) + Z_PARAM_ZVAL(name_or_object) + Z_PARAM_OPTIONAL + Z_PARAM_STR(value) + Z_PARAM_LONG(expires) + Z_PARAM_STR(path) + Z_PARAM_STR(domain) + Z_PARAM_BOOL(secure) + Z_PARAM_BOOL(httpOnly) + Z_PARAM_STR(sameSite) + Z_PARAM_STR(priority) + Z_PARAM_BOOL(partitioned) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); - if (cookie.name) { - zend_string_addref(cookie.name); - } - - if (cookie.value && ZSTR_LEN(cookie.value) > 0) { - zend_string_addref(cookie.value); + 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 { - cookie.value = nullptr; - } - - if (cookie.path) { - zend_string_addref(cookie.path); - } - - if (cookie.domain) { - zend_string_addref(cookie.domain); - } - - if (cookie.sameSite) { - zend_string_addref(cookie.sameSite); + php_swoole_error(E_WARNING, "The first argument must be a string or an cookie object"); + result = false; } - if (cookie.priority) { - zend_string_addref(cookie.priority); - } - - bool result = php_swoole_http_response_create_cookie(&cookie, ZEND_THIS); 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); -} - -static PHP_METHOD(swoole_http_response, objectCookie) { - zval *zcookie = nullptr; - ZEND_PARSE_PARAMETERS_START(1,1) - Z_PARAM_ZVAL(zcookie) - ZEND_PARSE_PARAMETERS_END(); - - HttpCookie *cookie = php_swoole_http_response_get_and_check_cookie(zcookie); - if (UNEXPECTED(!cookie)) { - RETURN_FALSE; - } - - bool result = php_swoole_http_response_create_cookie(cookie, ZEND_THIS); - RETURN_BOOL(result); + php_swoole_http_response_set_cookie(INTERNAL_FUNCTION_PARAM_PASSTHRU, false); } static PHP_METHOD(swoole_http_response, status) { 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_server/cookieAlias.phpt b/tests/swoole_http_server/cookieAlias.phpt index ed8aac44247..57946ffa6aa 100644 --- a/tests/swoole_http_server/cookieAlias.phpt +++ b/tests/swoole_http_server/cookieAlias.phpt @@ -30,12 +30,12 @@ $pm->childFunc = function () use ($pm) { ->withSameSite('None') ->withPriority('High') ->withPartitioned(true); - $response->setObjectCookie($cookie); + $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->setObjectCookie($cookie); + $response->setCookie($cookie); $response->end("

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

"); }); $server->start(); diff --git a/tests/swoole_http_server/cookie_vs_rawcookie.phpt b/tests/swoole_http_server/cookie_vs_rawcookie.phpt index 53f7e9f9208..3767d198460 100644 --- a/tests/swoole_http_server/cookie_vs_rawcookie.phpt +++ b/tests/swoole_http_server/cookie_vs_rawcookie.phpt @@ -10,13 +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), - ] - ); + Assert::eq($cli->set_cookie_headers, [ + 'cookie=' . $cookie_encoded, + 'rawcookie=' . $cookie_encoded, + ]); }); for ($i = MAX_CONCURRENCY_LOW; $i--;) { go(function () use ($pm) { @@ -40,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 +51,4 @@ $pm->childFirst(); $pm->run(); ?> --EXPECTF-- -Warning: Swoole\Http\Response::rawcookie(): Cookie value cannot contain ",", ";", " ", "\t", "\r", "\n", "\013", or "\014" in %S SUCCESS diff --git a/tests/swoole_http_server/new_cookie.phpt b/tests/swoole_http_server/new_cookie.phpt index 97353f3ca46..17fc34117ce 100644 --- a/tests/swoole_http_server/new_cookie.phpt +++ b/tests/swoole_http_server/new_cookie.phpt @@ -7,30 +7,34 @@ require __DIR__ . '/../include/skipif.inc'; --FILE-- setName('test'); -$cookie->setValue('123456789'); -$cookie->setExpires(time() + 3600); -$cookie->setPath('/'); -$cookie->setDomain('example.com'); -$cookie->setSecure(true); -$cookie->setHttpOnly(true); -$cookie->setSameSite('None'); -var_dump($cookie->getCookie()); +$cookie->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->getCookie()); +var_dump($cookie->toArray()); ?> --EXPECTF-- -array(10) { +array(11) { ["name"]=> string(4) "test" ["value"]=> string(9) "123456789" + ["path"]=> + string(5) "/path" ["domain"]=> - string(1) "/" + string(11) "example.com" ["sameSite"]=> - string(4) "test" + string(4) "None" ["priority"]=> string(0) "" ["encode"]=> @@ -44,11 +48,13 @@ array(10) { ["partitioned"]=> bool(false) } -array(10) { +array(11) { ["name"]=> string(0) "" ["value"]=> string(0) "" + ["path"]=> + string(0) "" ["domain"]=> string(0) "" ["sameSite"]=> diff --git a/tests/swoole_http_server/objectCookie.phpt b/tests/swoole_http_server/objectCookie.phpt index 7f217368ce1..3626a6e047e 100644 --- a/tests/swoole_http_server/objectCookie.phpt +++ b/tests/swoole_http_server/objectCookie.phpt @@ -30,9 +30,9 @@ $pm->childFunc = function () use ($pm) { ->withSameSite('None') ->withPriority('High') ->withPartitioned(true); - $response->setObjectCookie($cookie); + $response->setCookie($cookie); $cookie->withValue(''); - $response->setObjectCookie($cookie); + $response->setCookie($cookie); $response->end("

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

"); }); $server->start(); From 5df67760d50d6eb9ecc197fe41a6126cd54217ea Mon Sep 17 00:00:00 2001 From: hantianfeng Date: Tue, 23 Jul 2024 19:52:43 +0800 Subject: [PATCH 7/8] optimize code --- ext-src/php_swoole_http.h | 11 ++++---- ext-src/stubs/php_swoole_http_cookie.stub.php | 2 +- .../stubs/php_swoole_http_cookie_arginfo.h | 4 +-- ext-src/swoole_http_cookie.cc | 27 +++++++++---------- ext-src/swoole_http_response.cc | 5 +--- .../check_cookie_crlf.phpt | 2 +- 6 files changed, 23 insertions(+), 28 deletions(-) diff --git a/ext-src/php_swoole_http.h b/ext-src/php_swoole_http.h index 3d60156c2b1..83d4f44144a 100644 --- a/ext-src/php_swoole_http.h +++ b/ext-src/php_swoole_http.h @@ -214,10 +214,11 @@ struct Context { }; class Cookie { - private: + private: bool encode_; smart_str buffer_ = {0}; - protected: + + protected: zend_string *name = nullptr; zend_string *value = nullptr; zend_string *path = nullptr; @@ -228,7 +229,8 @@ class Cookie { zend_bool secure = false; zend_bool httpOnly = false; zend_bool partitioned = false; - public: + + public: Cookie(bool _encode = true) { encode_ = _encode; } @@ -242,10 +244,9 @@ class Cookie { Cookie *withDomain(zend_string *); Cookie *withSameSite(zend_string *); Cookie *withPriority(zend_string *); - zend_string *create(); void reset(); void toArray(zval *return_value); - void toString(zval *return_value); + zend_string *toString(); ~Cookie(); }; diff --git a/ext-src/stubs/php_swoole_http_cookie.stub.php b/ext-src/stubs/php_swoole_http_cookie.stub.php index 4017279f166..88fbb4d2b33 100644 --- a/ext-src/stubs/php_swoole_http_cookie.stub.php +++ b/ext-src/stubs/php_swoole_http_cookie.stub.php @@ -13,7 +13,7 @@ public function withSameSite(string $sameSite = ''): \Swoole\Http\Cookie {} public function withPriority(string $priority = ''): \Swoole\Http\Cookie {} public function withPartitioned(bool $partitioned = false): \Swoole\Http\Cookie {} public function toArray(): array {} - public function toString(): string {} + public function toString(): string | false {} public function reset(): void {} } } diff --git a/ext-src/stubs/php_swoole_http_cookie_arginfo.h b/ext-src/stubs/php_swoole_http_cookie_arginfo.h index 3c0108ef2b6..af917b57513 100644 --- a/ext-src/stubs/php_swoole_http_cookie_arginfo.h +++ b/ext-src/stubs/php_swoole_http_cookie_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: e23852c332ef2c62b86048d36b2ae15a7d8a0de6 */ + * Stub hash: a11e74ea8b1a4c77a3c10fbfbd94775c504ba812 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Swoole_Http_Cookie___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encode, _IS_BOOL, 0, "true") @@ -48,7 +48,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_toArray, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_toString, 0, 0, IS_STRING, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Swoole_Http_Cookie_toString, 0, 0, MAY_BE_STRING|MAY_BE_FALSE) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Swoole_Http_Cookie_reset, 0, 0, IS_VOID, 0) diff --git a/ext-src/swoole_http_cookie.cc b/ext-src/swoole_http_cookie.cc index 9d0d1695736..1cc9a328ae1 100644 --- a/ext-src/swoole_http_cookie.cc +++ b/ext-src/swoole_http_cookie.cc @@ -174,14 +174,14 @@ HttpCookie *HttpCookie::withPartitioned(zend_bool _partitioned) { return this; } -zend_string *HttpCookie::create() { +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) { + if (strpbrk(ZSTR_VAL(name), "=" ILLEGAL_COOKIE_CHARACTER) != nullptr) { php_swoole_error(E_WARNING, "The name cannot contain \"=\", " ILLEGAL_COOKIE_CHARACTER_PRINT); return nullptr; } @@ -334,15 +334,6 @@ void HttpCookie::toArray(zval *return_value) { add_assoc_bool(return_value, "partitioned", partitioned); } -void HttpCookie::toString(zval *return_value) { - auto cookie_str = create(); - if (!cookie_str) { - reset(); - RETURN_FALSE; - } - ZVAL_STR(return_value, cookie_str); -} - HttpCookie::~Cookie() { reset(); } @@ -371,7 +362,7 @@ static PHP_METHOD(swoole_http_cookie, __construct) { #define PHP_METHOD_HTTP_COOKIE_WITH_BOOL(field) \ zend_bool field = false; \ - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); \ + HttpCookie *cookie = php_swoole_http_get_cooke_safety(ZEND_THIS); \ \ ZEND_PARSE_PARAMETERS_START(0, 1) \ Z_PARAM_OPTIONAL \ @@ -431,13 +422,19 @@ static PHP_METHOD(swoole_http_cookie, withPartitioned) { } static PHP_METHOD(swoole_http_cookie, toString) { - php_swoole_http_get_cookie(ZEND_THIS)->toString(return_value); + 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_cookie(ZEND_THIS)->toArray(return_value); + php_swoole_http_get_cooke_safety(ZEND_THIS)->toArray(return_value); } static PHP_METHOD(swoole_http_cookie, reset) { - php_swoole_http_get_cookie(ZEND_THIS)->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 505d194639b..5f412d98edd 100644 --- a/ext-src/swoole_http_response.cc +++ b/ext-src/swoole_http_response.cc @@ -966,11 +966,8 @@ static PHP_METHOD(swoole_http_response, sendfile) { static bool inline php_swoole_http_response_create_cookie(HttpCookie *cookie, zval *zobject) { HttpContext *ctx = php_swoole_http_response_get_and_check_context(zobject); - if (UNEXPECTED(!ctx)) { - return false; - } - zend_string *cookie_str = cookie->create(); + zend_string *cookie_str = cookie->toString(); if (!cookie_str) { cookie->reset(); return false; diff --git a/tests/swoole_http_server_coro/check_cookie_crlf.phpt b/tests/swoole_http_server_coro/check_cookie_crlf.phpt index c81d1119471..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(): Cookie value cannot contain ",", ";", " ", "\t", "\r", "\n", "\013", or "\014" in %s +Warning: Swoole\Http\Response::rawcookie(): The value cannot contain ",", ";", " ", "\t", "\r", "\n", "\013", or "\014" in %s DONE From 8f2a8acc5ae3a53a7f3934d853ad9493dc90f466 Mon Sep 17 00:00:00 2001 From: hantianfeng Date: Tue, 23 Jul 2024 20:19:28 +0800 Subject: [PATCH 8/8] optimize code [2] --- ext-src/swoole_http_cookie.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext-src/swoole_http_cookie.cc b/ext-src/swoole_http_cookie.cc index 1cc9a328ae1..b1bdd88f44e 100644 --- a/ext-src/swoole_http_cookie.cc +++ b/ext-src/swoole_http_cookie.cc @@ -351,7 +351,7 @@ static PHP_METHOD(swoole_http_cookie, __construct) { #define PHP_METHOD_HTTP_COOKIE_WITH_STR(field) \ zend_string *field; \ - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); \ + HttpCookie *cookie = php_swoole_http_get_cooke_safety(ZEND_THIS); \ \ ZEND_PARSE_PARAMETERS_START(1, 1) \ Z_PARAM_STR(field) \ @@ -382,7 +382,7 @@ static PHP_METHOD(swoole_http_cookie, withValue) { static PHP_METHOD(swoole_http_cookie, withExpires) { zend_long expires = 0; - HttpCookie *cookie = php_swoole_http_get_cookie(ZEND_THIS); + HttpCookie *cookie = php_swoole_http_get_cooke_safety(ZEND_THIS); ZEND_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL