From a4114b0ea5757190fdd7218dbf23588b6ae6e9a8 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Fri, 7 Nov 2014 13:16:16 +0100 Subject: [PATCH] ditch php_url --- php_http_client_curl.c | 33 +++----- php_http_client_request.c | 45 +++++------ php_http_info.c | 2 +- php_http_info.h | 9 ++- php_http_message.c | 69 ++++++++++------ php_http_url.c | 165 +++++++++++++++++++++----------------- php_http_url.h | 15 ++-- 7 files changed, 183 insertions(+), 155 deletions(-) diff --git a/php_http_client_curl.c b/php_http_client_curl.c index 48bd0de..b057216 100644 --- a/php_http_client_curl.c +++ b/php_http_client_curl.c @@ -1598,7 +1598,7 @@ static STATUS php_http_client_curl_handler_prepare(php_http_client_curl_handler_ if (storage->url) { pefree(storage->url, 1); } - storage->url = pestrdup(PHP_HTTP_INFO(msg).request.url, 1); + php_http_url_to_string(PHP_HTTP_INFO(msg).request.url, &storage->url, NULL, 1); curl_easy_setopt(curl->handle, CURLOPT_URL, storage->url); /* request method */ @@ -1784,38 +1784,29 @@ static void queue_dtor(php_http_client_enqueue_t *e) php_http_client_curl_handler_dtor(handler); } -static php_resource_factory_t *create_rf(const char *url TSRMLS_DC) +static php_resource_factory_t *create_rf(php_http_url_t *url TSRMLS_DC) { - php_url *purl; + php_persistent_handle_factory_t *pf; php_resource_factory_t *rf = NULL; + char *id_str = NULL; + size_t id_len; - if (!url || !*url) { + if (!url || (!url->host && !url->path)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot request empty URL"); return NULL; } - purl = php_url_parse(url); + id_len = spprintf(&id_str, 0, "%s:%d", STR_PTR(url->host), url->port ? url->port : 80); - if (!purl) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not parse URL '%s'", url); - return NULL; + pf = php_persistent_handle_concede(NULL, ZEND_STRL("http\\Client\\Curl\\Request"), id_str, id_len, NULL, NULL TSRMLS_CC); + if (pf) { + rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void*)) php_persistent_handle_abandon); } else { - char *id_str = NULL; - size_t id_len = spprintf(&id_str, 0, "%s:%d", STR_PTR(purl->host), purl->port ? purl->port : 80); - php_persistent_handle_factory_t *pf = php_persistent_handle_concede(NULL, ZEND_STRL("http\\Client\\Curl\\Request"), id_str, id_len, NULL, NULL TSRMLS_CC); - - if (pf) { - rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void*)) php_persistent_handle_abandon); - } - - php_url_free(purl); - efree(id_str); - } - - if (!rf) { rf = php_resource_factory_init(NULL, &php_http_curle_resource_factory_ops, NULL, NULL); } + efree(id_str); + return rf; } diff --git a/php_http_client_request.c b/php_http_client_request.c index ea223be..eaf71da 100644 --- a/php_http_client_request.c +++ b/php_http_client_request.c @@ -31,12 +31,12 @@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest___construct, 0, 0, 0) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpClientRequest, __construct) { - char *meth_str = NULL, *url_str = NULL; - int meth_len = 0, url_len = 0; - zval *zheaders = NULL, *zbody = NULL; + char *meth_str = NULL; + int meth_len = 0; + zval *zheaders = NULL, *zbody = NULL, *zurl = NULL; php_http_message_object_t *obj; - php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!a!O!", &meth_str, &meth_len, &url_str, &url_len, &zheaders, &zbody, php_http_message_body_class_entry), invalid_arg, return); + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!z!a!O!", &meth_str, &meth_len, &zurl, &zheaders, &zbody, php_http_message_body_class_entry), invalid_arg, return); obj = zend_object_store_get_object(getThis() TSRMLS_CC); @@ -52,8 +52,8 @@ static PHP_METHOD(HttpClientRequest, __construct) if (meth_str && meth_len) { PHP_HTTP_INFO(obj->message).request.method = estrndup(meth_str, meth_len); } - if (url_str && url_len) { - PHP_HTTP_INFO(obj->message).request.url = estrndup(url_str, url_len); + if (zurl) { + PHP_HTTP_INFO(obj->message).request.url = php_http_url_from_zval(zurl, ~0 TSRMLS_CC); } if (zheaders) { array_copy(Z_ARRVAL_P(zheaders), &obj->message->hdrs); @@ -113,8 +113,9 @@ static PHP_METHOD(HttpClientRequest, setQuery) { zval *qdata = NULL; php_http_message_object_t *obj; - php_url *old_url = NULL, new_url = {NULL}; + php_http_url_t *old_url = NULL, new_url = {NULL}; char empty[] = ""; + unsigned flags = PHP_HTTP_URL_REPLACE; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z!", &qdata), invalid_arg, return); @@ -137,18 +138,17 @@ static PHP_METHOD(HttpClientRequest, setQuery) new_url.query = Z_STRVAL(str); zval_dtor(&arr); } else { - new_url.query = &empty[0]; + flags = PHP_HTTP_URL_STRIP_QUERY; } if (obj->message->http.info.request.url) { - old_url = php_url_parse(obj->message->http.info.request.url); - efree(obj->message->http.info.request.url); + old_url = obj->message->http.info.request.url; } - php_http_url(PHP_HTTP_URL_REPLACE, old_url, &new_url, NULL, &obj->message->http.info.request.url, NULL TSRMLS_CC); + obj->message->http.info.request.url = php_http_url_mod(old_url, &new_url, flags TSRMLS_CC); if (old_url) { - php_url_free(old_url); + php_http_url_free(&old_url); } if (new_url.query != &empty[0]) { STR_FREE(new_url.query); @@ -166,16 +166,8 @@ static PHP_METHOD(HttpClientRequest, getQuery) PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj); - if (obj->message->http.info.request.url) { - php_url *purl = php_url_parse(obj->message->http.info.request.url); - - if (purl) { - if (purl->query) { - RETVAL_STRING(purl->query, 0); - purl->query = NULL; - } - php_url_free(purl); - } + if (obj->message->http.info.request.url && obj->message->http.info.request.url->query) { + RETVAL_STRING(obj->message->http.info.request.url->query, 1); } } } @@ -187,7 +179,7 @@ static PHP_METHOD(HttpClientRequest, addQuery) { zval *qdata, arr, str; php_http_message_object_t *obj; - php_url *old_url = NULL, new_url = {NULL}; + php_http_url_t *old_url = NULL, new_url = {NULL}; php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &qdata), invalid_arg, return); @@ -208,14 +200,13 @@ static PHP_METHOD(HttpClientRequest, addQuery) zval_dtor(&arr); if (obj->message->http.info.request.url) { - old_url = php_url_parse(obj->message->http.info.request.url); - efree(obj->message->http.info.request.url); + old_url = obj->message->http.info.request.url; } - php_http_url(PHP_HTTP_URL_JOIN_QUERY, old_url, &new_url, NULL, &obj->message->http.info.request.url, NULL TSRMLS_CC); + obj->message->http.info.request.url = php_http_url_mod(old_url, &new_url, PHP_HTTP_URL_JOIN_QUERY TSRMLS_CC); if (old_url) { - php_url_free(old_url); + php_http_url_free(&old_url); } STR_FREE(new_url.query); diff --git a/php_http_info.c b/php_http_info.c index 10ea0a3..2f1b746 100644 --- a/php_http_info.c +++ b/php_http_info.c @@ -120,7 +120,7 @@ php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_head while (' ' == *url) ++url; while (' ' == *(http-1)) --http; if (http > url) { - PHP_HTTP_INFO(info).request.url = estrndup(url, http - url); + PHP_HTTP_INFO(info).request.url = php_http_url_parse(url, http - url, ~0 TSRMLS_CC); } else { STR_SET(PHP_HTTP_INFO(info).request.method, NULL); return NULL; diff --git a/php_http_info.h b/php_http_info.h index afd747c..d31b505 100644 --- a/php_http_info.h +++ b/php_http_info.h @@ -14,14 +14,15 @@ #define PHP_HTTP_INFO_H #include "php_http_version.h" +#include "php_http_url.h" -#define PHP_HTTP_INFO_REQUEST_FMT_ARGS(_http_ptr, eol) "%s %s HTTP/%u.%u" eol, \ +#define PHP_HTTP_INFO_REQUEST_FMT_ARGS(_http_ptr, tmp, eol) "%s %s HTTP/%u.%u" eol, \ (_http_ptr)->info.request.method?(_http_ptr)->info.request.method:"UNKNOWN", \ - (_http_ptr)->info.request.url?(_http_ptr)->info.request.url:"/", \ + (_http_ptr)->info.request.url?php_http_url_to_string((_http_ptr)->info.request.url, &(tmp), NULL, 0):"/", \ (_http_ptr)->version.major||(_http_ptr)->version.major?(_http_ptr)->version.major:1, \ (_http_ptr)->version.major||(_http_ptr)->version.minor?(_http_ptr)->version.minor:1 -#define PHP_HTTP_INFO_RESPONSE_FMT_ARGS(_http_ptr, eol) "HTTP/%u.%u %d%s%s" eol, \ +#define PHP_HTTP_INFO_RESPONSE_FMT_ARGS(_http_ptr, tmp, eol) "HTTP/%u.%u %d%s%s" eol, \ (_http_ptr)->version.major||(_http_ptr)->version.major?(_http_ptr)->version.major:1, \ (_http_ptr)->version.major||(_http_ptr)->version.minor?(_http_ptr)->version.minor:1, \ (_http_ptr)->info.response.code?(_http_ptr)->info.response.code:200, \ @@ -31,7 +32,7 @@ typedef struct php_http_info_data { union { /* GET /foo/bar */ - struct { char *method; char *url; } request; + struct { char *method; php_http_url_t *url; } request; /* 200 Ok */ struct { unsigned code; char *status; } response; } info; diff --git a/php_http_message.c b/php_http_message.c index c965317..1219d5d 100644 --- a/php_http_message.c +++ b/php_http_message.c @@ -69,7 +69,7 @@ php_http_message_t *php_http_message_init_env(php_http_message_t *message, php_h message->http.info.request.method = estrdup(Z_STRVAL_P(sval)); } if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_URI"), 1 TSRMLS_CC))) { - message->http.info.request.url = estrdup(Z_STRVAL_P(sval)); + message->http.info.request.url = php_http_url_parse(Z_STRVAL_P(sval), Z_STRLEN_P(sval), ~0 TSRMLS_CC); } php_http_env_get_request_headers(&message->hdrs TSRMLS_CC); @@ -276,7 +276,7 @@ void php_http_message_set_info(php_http_message_t *message, php_http_info_t *inf message->http.version = info->http.version; switch (message->type) { case PHP_HTTP_REQUEST: - STR_SET(PHP_HTTP_INFO(message).request.url, PHP_HTTP_INFO(info).request.url ? estrdup(PHP_HTTP_INFO(info).request.url) : NULL); + STR_SET(PHP_HTTP_INFO(message).request.url, PHP_HTTP_INFO(info).request.url ? php_http_url_copy(PHP_HTTP_INFO(info).request.url, 0) : NULL); STR_SET(PHP_HTTP_INFO(message).request.method, PHP_HTTP_INFO(info).request.method ? estrdup(PHP_HTTP_INFO(info).request.method) : NULL); break; @@ -332,15 +332,18 @@ void php_http_message_update_headers(php_http_message_t *msg) static void message_headers(php_http_message_t *msg, php_http_buffer_t *str) { + char *tmp = NULL; TSRMLS_FETCH_FROM_CTX(msg->ts); switch (msg->type) { case PHP_HTTP_REQUEST: - php_http_buffer_appendf(str, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&msg->http, PHP_HTTP_CRLF)); + php_http_buffer_appendf(str, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&msg->http, tmp, PHP_HTTP_CRLF)); + STR_FREE(tmp); break; case PHP_HTTP_RESPONSE: - php_http_buffer_appendf(str, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&msg->http, PHP_HTTP_CRLF)); + php_http_buffer_appendf(str, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&msg->http, tmp, PHP_HTTP_CRLF)); + STR_FREE(tmp); break; default: @@ -566,17 +569,18 @@ static void php_http_message_object_prophandler_set_request_method(php_http_mess } } static void php_http_message_object_prophandler_get_request_url(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { - if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url) { - RETVAL_STRING(obj->message->http.info.request.url, 1); + char *url_str; + size_t url_len; + + if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url && php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0)) { + RETVAL_STRINGL(url_str, url_len, 0); } else { RETVAL_NULL(); } } static void php_http_message_object_prophandler_set_request_url(php_http_message_object_t *obj, zval *value TSRMLS_DC) { if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) { - zval *cpy = php_http_ztyp(IS_STRING, value); - STR_SET(obj->message->http.info.request.url, estrndup(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy))); - zval_ptr_dtor(&cpy); + STR_SET(obj->message->http.info.request.url, php_http_url_from_zval(value, ~0 TSRMLS_CC)); } } static void php_http_message_object_prophandler_get_response_status(php_http_message_object_t *obj, zval *return_value TSRMLS_DC) { @@ -939,8 +943,8 @@ static HashTable *php_http_message_object_get_props(zval *object TSRMLS_DC) php_http_message_object_t *obj = zend_object_store_get_object(object TSRMLS_CC); HashTable *props = zend_get_std_object_handlers()->get_properties(object TSRMLS_CC); zval array, *parent, *body; - char *version; - int verlen; + char *ver_str, *url_str = NULL; + size_t ver_len, url_len = 0; PHP_HTTP_MESSAGE_OBJECT_INIT(obj); INIT_PZVAL_ARRAY(&array, props); @@ -964,15 +968,21 @@ static HashTable *php_http_message_object_get_props(zval *object TSRMLS_DC) } while(0) ASSOC_PROP(long, "type", obj->message->type); - verlen = spprintf(&version, 0, "%u.%u", obj->message->http.version.major, obj->message->http.version.minor); - ASSOC_STRINGL_EX("httpVersion", version, verlen, 0); + ver_len = spprintf(&ver_str, 0, "%u.%u", obj->message->http.version.major, obj->message->http.version.minor); + ASSOC_STRINGL_EX("httpVersion", ver_str, ver_len, 0); switch (obj->message->type) { case PHP_HTTP_REQUEST: ASSOC_PROP(long, "responseCode", 0); ASSOC_STRINGL("responseStatus", "", 0); ASSOC_STRING("requestMethod", STR_PTR(obj->message->http.info.request.method)); - ASSOC_STRING("requestUrl", STR_PTR(obj->message->http.info.request.url)); + if (obj->message->http.info.request.url) { + php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0); + ASSOC_STRINGL_EX("requestUrl", url_str, url_len, 0); + } else { + ASSOC_STRINGL("requestUrl", "", 0); + } + break; case PHP_HTTP_RESPONSE: @@ -1320,16 +1330,19 @@ ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, getInfo) { if (SUCCESS == zend_parse_parameters_none()) { + char *tmp = NULL; php_http_message_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); PHP_HTTP_MESSAGE_OBJECT_INIT(obj); switch (obj->message->type) { case PHP_HTTP_REQUEST: - Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&obj->message->http, "")); + Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&obj->message->http, tmp, "")); + STR_FREE(tmp); break; case PHP_HTTP_RESPONSE: - Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&obj->message->http, "")); + Z_STRLEN_P(return_value) = spprintf(&Z_STRVAL_P(return_value), 0, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&obj->message->http, tmp, "")); + STR_FREE(tmp); break; default: RETURN_NULL(); @@ -1564,7 +1577,11 @@ static PHP_METHOD(HttpMessage, getRequestUrl) } if (obj->message->http.info.request.url) { - RETURN_STRING(obj->message->http.info.request.url, 1); + char *url_str; + size_t url_len; + + php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0); + RETURN_STRINGL(url_str, url_len, 0); } else { RETURN_EMPTY_STRING(); } @@ -1576,11 +1593,12 @@ ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestUrl, 0, 0, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(HttpMessage, setRequestUrl) { - char *url_str; - int url_len; + zval *zurl; + php_http_url_t *url; php_http_message_object_t *obj; + zend_error_handling zeh; - php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &url_str, &url_len), invalid_arg, return); + php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zurl), invalid_arg, return); obj = zend_object_store_get_object(getThis() TSRMLS_CC); @@ -1591,12 +1609,17 @@ static PHP_METHOD(HttpMessage, setRequestUrl) return; } - if (url_len < 1) { + zend_replace_error_handling(EH_THROW, php_http_exception_bad_url_class_entry, &zeh TSRMLS_CC); + url = php_http_url_from_zval(zurl, ~0 TSRMLS_CC); + zend_restore_error_handling(&zeh TSRMLS_CC); + + if (php_http_url_is_empty(url)) { + php_http_url_free(&url); php_http_throw(invalid_arg, "Cannot set http\\Message's request url to an empty string", NULL); - return; + } else { + STR_SET(obj->message->http.info.request.url, url); } - STR_SET(obj->message->http.info.request.url, estrndup(url_str, url_len)); RETVAL_ZVAL(getThis(), 1, 0); } diff --git a/php_http_url.c b/php_http_url.c index 5aeefa8..a375018 100644 --- a/php_http_url.c +++ b/php_http_url.c @@ -131,7 +131,7 @@ void php_http_url(int flags, const php_url *old_url, const php_url *new_url, php *url_ptr = php_http_url_to_php_url(url); } if (url_str) { - php_http_url_to_string(url, url_str, url_len TSRMLS_CC); + php_http_url_to_string(url, url_str, url_len, 0); } php_http_url_free(&url); @@ -272,7 +272,7 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u url(buf)->host = &buf.data[buf.used]; php_http_buffer_append(&buf, "localhost", sizeof("localhost")); } - + if (!url(buf)->path) { url(buf)->path = &buf.data[buf.used]; php_http_buffer_append(&buf, "/", sizeof("/")); @@ -339,16 +339,17 @@ php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_u return url(buf); } -void php_http_url_to_string(const php_http_url_t *url, char **url_str, size_t *url_len TSRMLS_DC) +char *php_http_url_to_string(const php_http_url_t *url, char **url_str, size_t *url_len, zend_bool persistent) { php_http_buffer_t buf; - php_http_buffer_init(&buf); + php_http_buffer_init_ex(&buf, PHP_HTTP_BUFFER_DEFAULT_SIZE, persistent ? + PHP_HTTP_BUFFER_INIT_PERSISTENT : 0); if (url->scheme && *url->scheme) { php_http_buffer_appendl(&buf, url->scheme); php_http_buffer_appends(&buf, "://"); - } else { + } else if ((url->user && *url->user) || (url->host && *url->host)) { php_http_buffer_appends(&buf, "//"); } @@ -363,8 +364,6 @@ void php_http_url_to_string(const php_http_url_t *url, char **url_str, size_t *u if (url->host && *url->host) { php_http_buffer_appendl(&buf, url->host); - } else { - php_http_buffer_appends(&buf, "localhost"); } if (url->port) { @@ -394,12 +393,32 @@ void php_http_url_to_string(const php_http_url_t *url, char **url_str, size_t *u if (url_str) { *url_str = buf.data; - } else { - php_http_buffer_dtor(&buf); } + + return buf.data; } -php_http_url_t *php_http_url_from_struct(HashTable *ht TSRMLS_DC) +php_http_url_t *php_http_url_from_zval(zval *value, unsigned flags TSRMLS_DC) +{ + zval *zcpy; + php_http_url_t *purl; + + switch (Z_TYPE_P(value)) { + case IS_ARRAY: + case IS_OBJECT: + purl = php_http_url_from_struct(HASH_OF(value)); + break; + + default: + zcpy = php_http_ztyp(IS_STRING, value); + purl = php_http_url_parse(Z_STRVAL_P(zcpy), Z_STRLEN_P(zcpy), flags TSRMLS_CC); + zval_ptr_dtor(&zcpy); + } + + return purl; +} + +php_http_url_t *php_http_url_from_struct(HashTable *ht) { zval **e; php_http_buffer_t buf; @@ -562,6 +581,43 @@ void php_http_url_free(php_http_url_t **url) } } +php_http_url_t *php_http_url_copy(const php_http_url_t *url, zend_bool persistent) +{ + php_http_url_t *cpy; + const char *end = NULL, *url_ptr = (const char *) url; + char *cpy_ptr; + + end = MAX(url->scheme, end); + end = MAX(url->pass, end); + end = MAX(url->user, end); + end = MAX(url->host, end); + end = MAX(url->path, end); + end = MAX(url->query, end); + end = MAX(url->fragment, end); + + if (end) { + end += strlen(end) + 1; + cpy_ptr = pecalloc(1, end - url_ptr, persistent); + cpy = (php_http_url_t *) cpy_ptr; + + memcpy(cpy_ptr + sizeof(*cpy), url_ptr + sizeof(*url), end - url_ptr - sizeof(*url)); + + cpy->scheme = url->scheme ? cpy_ptr + (url->scheme - url_ptr) : NULL; + cpy->pass = url->pass ? cpy_ptr + (url->pass - url_ptr) : NULL; + cpy->user = url->user ? cpy_ptr + (url->user - url_ptr) : NULL; + cpy->host = url->host ? cpy_ptr + (url->host - url_ptr) : NULL; + cpy->path = url->path ? cpy_ptr + (url->path - url_ptr) : NULL; + cpy->query = url->query ? cpy_ptr + (url->query - url_ptr) : NULL; + cpy->fragment = url->fragment ? cpy_ptr + (url->fragment - url_ptr) : NULL; + } else { + cpy = ecalloc(1, sizeof(*url)); + } + + cpy->port = url->port; + + return cpy; +} + static size_t parse_mb_utf8(unsigned *wc, const char *ptr, const char *end) { unsigned wchar; @@ -933,14 +989,7 @@ static const char *parse_path(struct parse_state *state) switch (*state->ptr) { case '#': case '?': - case '\0': - /* did we have any path component ? */ - if (tmp != state->ptr) { - state->buffer[state->offset++] = 0; - } else { - state->url.path = NULL; - } - return state->ptr; + goto done; case '%': if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) { @@ -979,9 +1028,16 @@ static const char *parse_path(struct parse_state *state) } state->ptr += mb - 1; } - } while (++state->ptr <= state->end); + } while (++state->ptr < state->end); - return NULL; + done: + /* did we have any path component ? */ + if (tmp != state->ptr) { + state->buffer[state->offset++] = 0; + } else { + state->url.path = NULL; + } + return state->ptr; } static const char *parse_query(struct parse_state *state) @@ -1002,9 +1058,7 @@ static const char *parse_query(struct parse_state *state) do { switch (*state->ptr) { case '#': - case '\0': - state->buffer[state->offset++] = 0; - return state->ptr; + goto done; case '%': if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) { @@ -1053,9 +1107,11 @@ static const char *parse_query(struct parse_state *state) } state->ptr += mb - 1; } - } while (++state->ptr <= state->end); + } while (++state->ptr < state->end); - return NULL; + done: + state->buffer[state->offset++] = 0; + return state->ptr; } static const char *parse_fragment(struct parse_state *state) @@ -1075,10 +1131,6 @@ static const char *parse_fragment(struct parse_state *state) do { switch (*state->ptr) { - case '\0': - state->buffer[state->offset++] = 0; - return state->ptr; - case '%': if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) { php_error_docref(NULL TSRMLS_CC, E_WARNING, @@ -1116,9 +1168,10 @@ static const char *parse_fragment(struct parse_state *state) } state->ptr += mb - 1; } - } while (++state->ptr <= state->end); + } while (++state->ptr < state->end); - return NULL; + state->buffer[state->offset++] = 0; + return state->ptr; } static const char *parse_hier(struct parse_state *state) @@ -1235,38 +1288,14 @@ PHP_METHOD(HttpUrl, __construct) php_http_url_t *res_purl, *new_purl = NULL, *old_purl = NULL; if (new_url) { - switch (Z_TYPE_P(new_url)) { - case IS_OBJECT: - case IS_ARRAY: - new_purl = php_http_url_from_struct(HASH_OF(new_url) TSRMLS_CC); - break; - default: { - zval *cpy = php_http_ztyp(IS_STRING, new_url); - - new_purl = php_http_url_parse(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy), flags TSRMLS_CC); - zval_ptr_dtor(&cpy); - break; - } - } + new_purl = php_http_url_from_zval(new_url, flags TSRMLS_CC); if (!new_purl) { zend_restore_error_handling(&zeh TSRMLS_CC); return; } } if (old_url) { - switch (Z_TYPE_P(old_url)) { - case IS_OBJECT: - case IS_ARRAY: - old_purl = php_http_url_from_struct(HASH_OF(old_url) TSRMLS_CC); - break; - default: { - zval *cpy = php_http_ztyp(IS_STRING, old_url); - - old_purl = php_http_url_parse(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy), flags TSRMLS_CC); - zval_ptr_dtor(&cpy); - break; - } - } + old_purl = php_http_url_from_zval(old_url, flags TSRMLS_CC); if (!old_purl) { if (new_purl) { php_http_url_free(&new_purl); @@ -1307,26 +1336,14 @@ PHP_METHOD(HttpUrl, mod) php_http_url_t *new_purl = NULL, *old_purl = NULL; if (new_url) { - switch (Z_TYPE_P(new_url)) { - case IS_OBJECT: - case IS_ARRAY: - new_purl = php_http_url_from_struct(HASH_OF(new_url) TSRMLS_CC); - break; - default: { - zval *cpy = php_http_ztyp(IS_STRING, new_url); - - new_purl = php_http_url_parse(Z_STRVAL_P(new_url), Z_STRLEN_P(new_url), flags TSRMLS_CC); - zval_ptr_dtor(&cpy); - break; - } - } + new_purl = php_http_url_from_zval(new_url, flags TSRMLS_CC); if (!new_purl) { zend_restore_error_handling(&zeh TSRMLS_CC); return; } } - if ((old_purl = php_http_url_from_struct(HASH_OF(getThis()) TSRMLS_CC))) { + if ((old_purl = php_http_url_from_struct(HASH_OF(getThis())))) { php_http_url_t *res_purl; ZVAL_OBJVAL(return_value, zend_objects_clone_obj(getThis() TSRMLS_CC), 0); @@ -1351,11 +1368,11 @@ PHP_METHOD(HttpUrl, toString) if (SUCCESS == zend_parse_parameters_none()) { php_http_url_t *purl; - if ((purl = php_http_url_from_struct(HASH_OF(getThis()) TSRMLS_CC))) { + if ((purl = php_http_url_from_struct(HASH_OF(getThis())))) { char *str; size_t len; - php_http_url_to_string(purl, &str, &len TSRMLS_CC); + php_http_url_to_string(purl, &str, &len, 0); php_http_url_free(&purl); RETURN_STRINGL(str, len, 0); } @@ -1374,7 +1391,7 @@ PHP_METHOD(HttpUrl, toArray) } /* strip any non-URL properties */ - purl = php_http_url_from_struct(HASH_OF(getThis()) TSRMLS_CC); + purl = php_http_url_from_struct(HASH_OF(getThis())); php_http_url_to_struct(purl, return_value TSRMLS_CC); php_http_url_free(&purl); } diff --git a/php_http_url.h b/php_http_url.h index a6dda53..fb91932 100644 --- a/php_http_url.h +++ b/php_http_url.h @@ -57,12 +57,17 @@ typedef struct php_http_url { } php_http_url_t; PHP_HTTP_API php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags TSRMLS_DC); -PHP_HTTP_API void php_http_url_free(php_http_url_t **url); - /* deprecated */ PHP_HTTP_API void php_http_url(int flags, const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC); /* use this instead */ PHP_HTTP_API php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_url_t *new_url, unsigned flags TSRMLS_DC); +PHP_HTTP_API php_http_url_t *php_http_url_copy(const php_http_url_t *url, zend_bool persistent); +PHP_HTTP_API php_http_url_t *php_http_url_from_struct(HashTable *ht); +PHP_HTTP_API php_http_url_t *php_http_url_from_zval(zval *value, unsigned flags TSRMLS_DC); +PHP_HTTP_API HashTable *php_http_url_to_struct(const php_http_url_t *url, zval *strct TSRMLS_DC); +PHP_HTTP_API char *php_http_url_to_string(const php_http_url_t *url, char **url_str, size_t *url_len, zend_bool persistent); +PHP_HTTP_API void php_http_url_free(php_http_url_t **url); + PHP_HTTP_API STATUS php_http_url_encode_hash(HashTable *hash, const char *pre_encoded_str, size_t pre_encoded_len, char **encoded_str, size_t *encoded_len TSRMLS_DC); PHP_HTTP_API STATUS php_http_url_encode_hash_ex(HashTable *hash, php_http_buffer_t *qstr, const char *arg_sep_str, size_t arg_sep_len, const char *val_sep_str, size_t val_sep_len, const char *pre_encoded_str, size_t pre_encoded_len TSRMLS_DC); @@ -90,9 +95,9 @@ static inline php_url *php_http_url_to_php_url(php_http_url_t *url) return purl; } -PHP_HTTP_API php_http_url_t *php_http_url_from_struct(HashTable *ht TSRMLS_DC); -PHP_HTTP_API HashTable *php_http_url_to_struct(const php_http_url_t *url, zval *strct TSRMLS_DC); -PHP_HTTP_API void php_http_url_to_string(const php_http_url_t *url, char **url_str, size_t *url_len TSRMLS_DC); +static inline zend_bool php_http_url_is_empty(const php_http_url_t *url) { + return !(url->scheme || url->pass || url->user || url->host || url->port || url->path || url->query || url->fragment); +} PHP_HTTP_API zend_class_entry *php_http_url_class_entry; PHP_MINIT_FUNCTION(http_url); -- 2.30.2