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();