From bf87f6e654235acb023ca052a5e71faeb2635a3f Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Sun, 18 Dec 2005 22:27:39 +0000 Subject: [PATCH] - http_build_url() replaces http_absolute_(url|uri)/http_build_uri; # This is most probably the final name. :) # # Based on a request by ilia who probably wanted to see something similar along # the following lines to be possible: # http_build_url(parse_url(...)) # # It basically can still work like the removed function: # echo http_build_url('/foo/bar', array('scheme' => 'https', 'host' => 'example.com')); # # The third param will be filled with an array like parse_url() of the result url would return. --- http.c | 3 +- http_filter_api.c | 29 ++ http_functions.c | 101 +++++-- http_message_api.c | 23 +- http_request_object.c | 16 +- http_url_api.c | 263 +++++++++--------- http_util_object.c | 9 +- php_http.h | 2 +- php_http_std_defs.h | 2 - php_http_url_api.h | 61 +++- php_http_util_object.h | 2 +- tests/abs_uri_002.phpt | 19 -- .../{abs_uri_001.phpt => build_url_001.phpt} | 6 +- tests/build_url_002.phpt | 30 ++ ...{build_uri_001.phpt => build_url_003.phpt} | 10 +- tests/ut_HttpUtil.phpt | 8 +- 16 files changed, 359 insertions(+), 225 deletions(-) delete mode 100644 tests/abs_uri_002.phpt rename tests/{abs_uri_001.phpt => build_url_001.phpt} (55%) create mode 100644 tests/build_url_002.phpt rename tests/{build_uri_001.phpt => build_url_003.phpt} (53%) diff --git a/http.c b/http.c index eb8f5e9..d0617b6 100644 --- a/http.c +++ b/http.c @@ -62,8 +62,7 @@ ZEND_GET_MODULE(http) zend_function_entry http_functions[] = { PHP_FE(http_test, NULL) PHP_FE(http_date, NULL) - PHP_FE(http_build_uri, NULL) - PHP_FALIAS(http_absolute_uri, http_build_uri, NULL) + PHP_FE(http_build_url, http_arg_pass_ref_3) PHP_FE(http_negotiate_language, http_arg_pass_ref_2) PHP_FE(http_negotiate_charset, http_arg_pass_ref_2) PHP_FE(http_negotiate_content_type, http_arg_pass_ref_2) diff --git a/http_filter_api.c b/http_filter_api.c index 648c509..4b54998 100644 --- a/http_filter_api.c +++ b/http_filter_api.c @@ -381,6 +381,7 @@ static HTTP_FILTER_OPS(deflate) = { static php_stream_filter *http_filter_create(const char *name, zval *params, int p TSRMLS_DC) { + zval **tmp = ¶ms; php_stream_filter *f = NULL; if (!strcasecmp(name, "http.chunked_decode")) { @@ -407,6 +408,20 @@ static php_stream_filter *http_filter_create(const char *name, zval *params, int if (p) { b->flags |= HTTP_ENCODING_STREAM_PERSISTENT; } + if (params) { + switch (Z_TYPE_P(params)) + { + case IS_ARRAY: + case IS_OBJECT: + if (SUCCESS != zend_hash_find(HASH_OF(params), "zlib", sizeof("zlib"), (void **) &tmp)) { + break; + } + default: + if (zval_is_true(*tmp)) { + b->flags |= HTTP_ENCODING_STREAM_ZLIB_HEADER; + } + } + } if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(gzencode), b, p))) { pefree(b, p); } @@ -420,6 +435,20 @@ static php_stream_filter *http_filter_create(const char *name, zval *params, int if (p) { b->flags |= HTTP_ENCODING_STREAM_PERSISTENT; } + if (params) { + switch (Z_TYPE_P(params)) + { + case IS_ARRAY: + case IS_OBJECT: + if (SUCCESS != zend_hash_find(HASH_OF(params), "zlib", sizeof("zlib"), (void **) &tmp)) { + break; + } + default: + if (zval_is_true(*tmp)) { + b->flags |= HTTP_ENCODING_STREAM_ZLIB_HEADER; + } + } + } if (!(f = php_stream_filter_alloc(&HTTP_FILTER_OP(deflate), b, p))) { pefree(b, p); } diff --git a/http_functions.c b/http_functions.c index ed59fc2..1b71506 100644 --- a/http_functions.c +++ b/http_functions.c @@ -68,41 +68,84 @@ PHP_FUNCTION(http_date) } /* }}} */ -/* {{{ proto string http_build_uri(string url[, string proto[, string host[, int port]]]) +/* {{{ proto string http_build_url(mixed url[, mixed parts[, array new_url]]) * - * Build a complete URI according to the supplied parameters. - * - * If the url is already abolute but a different proto was supplied, - * only the proto part of the URI will be updated. If url has no - * path specified, the path of the current REQUEST_URI will be taken. - * The host will be taken either from the Host HTTP header of the client - * the SERVER_NAME or just localhost if prior are not available. - * If a port is pecified in either the url or as sperate parameter, - * it will be added if it differs from te default port for HTTP(S). - * - * Returns the absolute URI as string on success or false on failure. - * - * Examples: - *
- * 
- * 
+ * Returns the new URL as string on success or FALSE on failure. */ -PHP_FUNCTION(http_build_uri) +PHP_FUNCTION(http_build_url) { - char *url = NULL, *proto = NULL, *host = NULL, *built = NULL; - int url_len = 0, proto_len = 0, host_len = 0; - long port = 0; + char *url_str = NULL; + size_t url_len = 0; + zval *z_old_url = NULL, *z_new_url = NULL, *z_composed_url = NULL; + php_url *old_url = NULL, *new_url = NULL, *composed_url = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ssl", &url, &url_len, &proto, &proto_len, &host, &host_len, &port) != SUCCESS) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/|z/z", &z_old_url, &z_new_url, &z_composed_url) != SUCCESS) { RETURN_FALSE; } - - if ((built = http_absolute_uri_ex(url, url_len, proto, proto_len, host, host_len, port))) { - RETURN_STRING(built, 0); + + if (z_new_url) { + if (Z_TYPE_P(z_new_url) == IS_ARRAY || Z_TYPE_P(z_new_url) == IS_OBJECT) { + new_url = array2url(HASH_OF(z_new_url)); + } else { + convert_to_string(z_new_url); + if (!(new_url = php_url_parse_ex(Z_STRVAL_P(z_new_url), Z_STRLEN_P(z_new_url)))) { + RETURN_FALSE; + } + } + } + + if (Z_TYPE_P(z_old_url) == IS_ARRAY || Z_TYPE_P(z_old_url) == IS_OBJECT) { + old_url = array2url(HASH_OF(z_old_url)); + } else { + convert_to_string(z_old_url); + if (!(old_url = php_url_parse_ex(Z_STRVAL_P(z_old_url), Z_STRLEN_P(z_old_url)))) { + if (new_url) { + php_url_free(new_url); + } + RETURN_FALSE; + } } - RETURN_FALSE; + + if (z_composed_url) { + http_build_url(old_url, new_url, &composed_url, &url_str, &url_len); + + zval_dtor(z_composed_url); + array_init(z_composed_url); + if (composed_url->scheme) { + add_assoc_string(z_composed_url, "scheme", composed_url->scheme, 1); + } + if (composed_url->user) { + add_assoc_string(z_composed_url, "user", composed_url->user, 1); + } + if (composed_url->pass) { + add_assoc_string(z_composed_url, "pass", composed_url->pass, 1); + } + if (composed_url->host) { + add_assoc_string(z_composed_url, "host", composed_url->host, 1); + } + if (composed_url->port) { + add_assoc_long(z_composed_url, "port", composed_url->port); + } + if (composed_url->path) { + add_assoc_string(z_composed_url, "path", composed_url->path, 1); + } + if (composed_url->query) { + add_assoc_string(z_composed_url, "query", composed_url->query, 1); + } + if (composed_url->fragment) { + add_assoc_string(z_composed_url, "fragment", composed_url->fragment, 1); + } + php_url_free(composed_url); + } else { + http_build_url(old_url, new_url, NULL, &url_str, &url_len); + } + + if (new_url) { + php_url_free(new_url); + } + php_url_free(old_url); + + RETURN_STRINGL(url_str, url_len, 0); } /* }}} */ @@ -686,7 +729,7 @@ PHP_FUNCTION(http_redirect) } } - URI = http_absolute_uri(url); + URI = http_absolute_url(url); if (query_len) { spprintf(&LOC, 0, "Location: %s?%s", URI, query); diff --git a/http_message_api.c b/http_message_api.c index dd38e7c..fee445b 100644 --- a/http_message_api.c +++ b/http_message_api.c @@ -500,23 +500,24 @@ PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC) /* check host header */ if (SUCCESS == zend_hash_find(&message->hdrs, "Host", sizeof("Host"), (void **) &zhost)) { - char *colon = NULL, *host = NULL; - size_t host_len = 0; - int port = 0; + char *colon = NULL; + php_url parts, *url = php_url_parse(message->http.info.request.URI); + + memset(&parts, 0, sizeof(php_url)); /* check for port */ if ((colon = strchr(Z_STRVAL_PP(zhost), ':'))) { - port = atoi(colon + 1); - host = estrndup(Z_STRVAL_PP(zhost), host_len = (Z_STRVAL_PP(zhost) - colon - 1)); + parts.port = atoi(colon + 1); + parts.host = estrndup(Z_STRVAL_PP(zhost), (Z_STRVAL_PP(zhost) - colon - 1)); } else { - host = estrndup(Z_STRVAL_PP(zhost), host_len = Z_STRLEN_PP(zhost)); + parts.host = estrndup(Z_STRVAL_PP(zhost), Z_STRLEN_PP(zhost)); } - uri = http_absolute_uri_ex( - message->http.info.request.URI, strlen(message->http.info.request.URI), - NULL, 0, host, host_len, port); - efree(host); + + http_build_url(url, &parts, NULL, &uri, NULL); + php_url_free(url); + efree(parts.host); } else { - uri = http_absolute_uri(message->http.info.request.URI); + uri = http_absolute_url(message->http.info.request.URI); } if ((request.meth = http_request_method_exists(1, 0, message->http.info.request.method))) { diff --git a/http_request_object.c b/http_request_object.c index 8280f97..facd8e9 100644 --- a/http_request_object.c +++ b/http_request_object.c @@ -431,14 +431,8 @@ STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ HTTP_CHECK_CURL_INIT(obj->request->ch, curl_easy_init(), return FAILURE); URL = convert_to_type_ex(IS_STRING, GET_PROP(obj, url), &URL_p); - obj->request->url = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0); - if (URL_p) { - zval_ptr_dtor(&URL_p); - } - - if (!obj->request->url) { - return FAILURE; - } + obj->request->url = http_absolute_url(Z_STRVAL_P(URL)); + if (URL_p) zval_ptr_dtor(&URL_p); switch (obj->request->meth = Z_LVAL_P(convert_to_type_ex(IS_LONG, GET_PROP(obj, method), &meth_p))) { @@ -532,11 +526,11 @@ STATUS _http_request_object_requesthandler(http_request_object *obj, zval *this_ if (Z_STRLEN_P(qdata)) { if (!strchr(obj->request->url, '?')) { - strlcat(obj->request->url, "?", HTTP_URI_MAXLEN); + strlcat(obj->request->url, "?", HTTP_URL_MAXLEN); } else { - strlcat(obj->request->url, "&", HTTP_URI_MAXLEN); + strlcat(obj->request->url, "&", HTTP_URL_MAXLEN); } - strlcat(obj->request->url, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN); + strlcat(obj->request->url, Z_STRVAL_P(qdata), HTTP_URL_MAXLEN); } http_request_prepare(obj->request, Z_ARRVAL_P(options)); diff --git a/http_url_api.c b/http_url_api.c index 4f20de5..99c8af9 100644 --- a/http_url_api.c +++ b/http_url_api.c @@ -22,158 +22,167 @@ #include "SAPI.h" #include "zend_ini.h" #include "php_output.h" -#include "ext/standard/url.h" #include "php_http_api.h" #include "php_http_url_api.h" ZEND_EXTERN_MODULE_GLOBALS(http); -/* {{{ char *http_absolute_url(char *) */ -PHP_HTTP_API char *_http_absolute_url_ex( - const char *url, size_t url_len, - const char *proto, size_t proto_len, - const char *host, size_t host_len, - unsigned port TSRMLS_DC) +PHP_HTTP_API char *_http_absolute_url(const char *url TSRMLS_DC) { -#if defined(PHP_WIN32) || defined(HAVE_NETDB_H) - struct servent *se; -#endif - php_url *purl = NULL, furl; - size_t full_len = 0; - zval *zhost = NULL; - char *scheme = NULL, *uri, *URL; - - if ((!url || !url_len) && ( - (!(url = SG(request_info).request_uri)) || - (!(url_len = strlen(SG(request_info).request_uri))))) { - http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot build an absolute URI if supplied URL and REQUEST_URI is empty"); - return NULL; - } - - uri = estrndup(url, url_len); - if (!(purl = php_url_parse(uri))) { - efree(uri); - http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse supplied URL: %s", url); - return NULL; + char *abs = estrdup(url); + php_url *purl = php_url_parse(abs); + + STR_SET(abs, NULL); + + if (purl) { + http_build_url(purl, NULL, NULL, &abs, NULL); + php_url_free(purl); } + + return abs; +} - URL = ecalloc(1, HTTP_URI_MAXLEN + 1); - - furl.user = purl->user; - furl.pass = purl->pass; - furl.path = purl->path; - furl.query = purl->query; - furl.fragment = purl->fragment; - - if (proto && proto_len) { - furl.scheme = scheme = estrdup(proto); - } else if (purl->scheme) { - furl.scheme = purl->scheme; +/* {{{ void http_build_url(const php_url *, const php_url *, php_url **, char **, size_t *) */ +PHP_HTTP_API void _http_build_url(const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC) +{ #if defined(PHP_WIN32) || defined(HAVE_NETDB_H) - } else if (port && (se = getservbyport(htons((short) port), "tcp"))) { - furl.scheme = (scheme = estrdup(se->s_name)); + struct servent *se; #endif - } else { - furl.scheme = "http"; - } + php_url *url = emalloc(sizeof(php_url)); + +#define __URLCPY(n) \ + url->n = (new_url&&new_url->n) ? estrdup(new_url->n) : ((old_url&&old_url->n) ? estrdup(old_url->n) : NULL) + url->port = (new_url&&new_url->port) ? new_url->port : ((old_url) ? old_url->port : 0); + __URLCPY(scheme); + __URLCPY(user); + __URLCPY(pass); + __URLCPY(host); + __URLCPY(path); + __URLCPY(path); + __URLCPY(query); + __URLCPY(fragment); + + if (!url->scheme) { + switch (url->port) + { + case 443: + url->scheme = estrndup("https", lenof("https")); + break; - if (port) { - furl.port = port; - } else if (purl->port) { - furl.port = purl->port; - } else if (strncmp(furl.scheme, "http", 4)) { +#if !defined(PHP_WIN32) && !defined(HAVE_NETDB_H) + default: +#endif + case 80: + url->scheme = estrndup("http", lenof("http")); + break; + #if defined(PHP_WIN32) || defined(HAVE_NETDB_H) - if ((se = getservbyname(furl.scheme, "tcp"))) { - furl.port = ntohs(se->s_port); - } + default: + if ((se = getservbyport(htons(url->port), "tcp")) && se->s_name) { + url->scheme = estrdup(se->s_name); + } else { + url->scheme = estrndup("http", lenof("http")); + } + break; #endif - furl.port = 0; - } else { - furl.port = (furl.scheme[4] == 's') ? 443 : 80; - } - - if (host && host_len) { - furl.host = (char *) host; - } else if (purl->host) { - furl.host = purl->host; - } else if ( (zhost = http_get_server_var("HTTP_HOST")) || - (zhost = http_get_server_var("SERVER_NAME"))) { - furl.host = Z_STRVAL_P(zhost); - } else { - furl.host = "localhost"; + } } -#define HTTP_URI_STRLCATS(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, sizeof(add_string)-1) -#define HTTP_URI_STRLCATL(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, strlen(add_string)) -#define HTTP_URI_STRLCAT(URL, full_len, add_string, add_len) \ - if ((full_len += add_len) > HTTP_URI_MAXLEN) { \ - http_error_ex(HE_NOTICE, HTTP_E_URL, \ - "Absolute URI would have exceeded max URI length (%d bytes) - " \ - "tried to add %d bytes ('%s')", \ - HTTP_URI_MAXLEN, add_len, add_string); \ - if (scheme) { \ - efree(scheme); \ - } \ - php_url_free(purl); \ - efree(uri); \ - return URL; \ - } else { \ - strcat(URL, add_string); \ + if (!url->host) { + zval *zhost; + + if ((((zhost = http_get_server_var("HTTP_HOST")) || + (zhost = http_get_server_var("SERVER_NAME")))) && Z_STRLEN_P(zhost)) { + url->host = estrndup(Z_STRVAL_P(zhost), Z_STRLEN_P(zhost)); + } else { + url->host = estrndup("localhost", lenof("localhost")); + } } - - HTTP_URI_STRLCATL(URL, full_len, furl.scheme); - HTTP_URI_STRLCATS(URL, full_len, "://"); - - if (furl.user) { - HTTP_URI_STRLCATL(URL, full_len, furl.user); - if (furl.pass) { - HTTP_URI_STRLCATS(URL, full_len, ":"); - HTTP_URI_STRLCATL(URL, full_len, furl.pass); + + /* FIXXME: dirname(REQUEST_URI) if path is relative */ + if (!url->path) { + if (SG(request_info).request_uri) { + const char *q = strchr(SG(request_info).request_uri, '?'); + + if (q) { + url->path = estrndup(SG(request_info).request_uri, q - SG(request_info).request_uri); + } else { + url->path = estrdup(SG(request_info).request_uri); + } + } else { + url->path = ecalloc(1, 1); } - HTTP_URI_STRLCATS(URL, full_len, "@"); } - - HTTP_URI_STRLCATL(URL, full_len, furl.host); - - if (furl.port && ( - (!strcmp(furl.scheme, "http") && (furl.port != 80)) || - (!strcmp(furl.scheme, "https") && (furl.port != 443)) + + if (url->port) { + if ( ((url->port == 80) && !strcmp(url->scheme, "http")) + || ((url->port ==443) && !strcmp(url->scheme, "https")) #if defined(PHP_WIN32) || defined(HAVE_NETDB_H) - || ((!(se = getservbyname(furl.scheme, "tcp"))) || (ntohs(se->s_port) != furl.port)) + || ((se = getservbyname(url->scheme, "tcp")) && se->s_port && + (url->port == ntohs(se->s_port))) #endif - )) { - char port_string[8] = {0}; - snprintf(port_string, 7, ":%u", furl.port); - HTTP_URI_STRLCATL(URL, full_len, port_string); - } - - if (furl.path) { - if (furl.path[0] != '/') { - HTTP_URI_STRLCATS(URL, full_len, "/"); + ) { + url->port = 0; } - HTTP_URI_STRLCATL(URL, full_len, furl.path); - } else { - HTTP_URI_STRLCATS(URL, full_len, "/"); - } - - if (furl.query) { - HTTP_URI_STRLCATS(URL, full_len, "?"); - HTTP_URI_STRLCATL(URL, full_len, furl.query); } - - if (furl.fragment) { - HTTP_URI_STRLCATS(URL, full_len, "#"); - HTTP_URI_STRLCATL(URL, full_len, furl.fragment); + + if (url_str) { + size_t len; + + *url_str = emalloc(HTTP_URL_MAXLEN + 1); + + **url_str = '\0'; + strlcat(*url_str, url->scheme, HTTP_URL_MAXLEN); + strlcat(*url_str, "://", HTTP_URL_MAXLEN); + + if (url->user && *url->user) { + strlcat(*url_str, url->user, HTTP_URL_MAXLEN); + if (url->pass && *url->pass) { + strlcat(*url_str, ":", HTTP_URL_MAXLEN); + strlcat(*url_str, url->pass, HTTP_URL_MAXLEN); + } + strlcat(*url_str, "@", HTTP_URL_MAXLEN); + } + + strlcat(*url_str, url->host, HTTP_URL_MAXLEN); + + if (url->port) { + char port_str[6] = {0}; + + snprintf(port_str, 5, "%d", (int) url->port); + strlcat(*url_str, ":", HTTP_URL_MAXLEN); + strlcat(*url_str, port_str, HTTP_URL_MAXLEN); + } + + if (*url->path != '/') { + strlcat(*url_str, "/", HTTP_URL_MAXLEN); + } + strlcat(*url_str, url->path, HTTP_URL_MAXLEN); + + if (url->query && *url->query) { + strlcat(*url_str, "?", HTTP_URL_MAXLEN); + strlcat(*url_str, url->query, HTTP_URL_MAXLEN); + } + + if (url->fragment && *url->fragment) { + strlcat(*url_str, "#", HTTP_URL_MAXLEN); + strlcat(*url_str, url->fragment, HTTP_URL_MAXLEN); + } + + if (HTTP_URL_MAXLEN == (len = strlen(*url_str))) { + http_error(HE_NOTICE, HTTP_E_URL, "Length of URL exceeds HTTP_URL_MAXLEN"); + } + if (url_len) { + *url_len = len; + } } - - if (scheme) { - efree(scheme); + + if (url_ptr) { + *url_ptr = url; + } else { + php_url_free(url); } - php_url_free(purl); - efree(uri); - - return URL; } /* }}} */ diff --git a/http_util_object.c b/http_util_object.c index 03429f4..110ff08 100644 --- a/http_util_object.c +++ b/http_util_object.c @@ -32,11 +32,10 @@ HTTP_BEGIN_ARGS(date, 0) HTTP_ARG_VAL(timestamp, 0) HTTP_END_ARGS; -HTTP_BEGIN_ARGS(buildUri, 1) +HTTP_BEGIN_ARGS(buildUrl, 1) HTTP_ARG_VAL(url, 0) - HTTP_ARG_VAL(proto, 0) - HTTP_ARG_VAL(host, 0) - HTTP_ARG_VAL(port, 0) + HTTP_ARG_VAL(parts, 0) + HTTP_ARG_VAL(composed, 1) HTTP_END_ARGS; HTTP_BEGIN_ARGS(negotiateLanguage, 1) @@ -113,7 +112,7 @@ HTTP_END_ARGS; zend_class_entry *http_util_object_ce; zend_function_entry http_util_object_fe[] = { HTTP_UTIL_ALIAS(date, http_date) - HTTP_UTIL_ALIAS(buildUri, http_build_uri) + HTTP_UTIL_ALIAS(buildUrl, http_build_url) HTTP_UTIL_ALIAS(negotiateLanguage, http_negotiate_language) HTTP_UTIL_ALIAS(negotiateCharset, http_negotiate_charset) HTTP_UTIL_ALIAS(negotiateContentType, http_negotiate_content_type) diff --git a/php_http.h b/php_http.h index b4c4ab3..6f623ff 100644 --- a/php_http.h +++ b/php_http.h @@ -107,7 +107,7 @@ ZEND_END_MODULE_GLOBALS(http) PHP_FUNCTION(http_test); PHP_FUNCTION(http_date); -PHP_FUNCTION(http_build_uri); +PHP_FUNCTION(http_build_url); PHP_FUNCTION(http_negotiate_language); PHP_FUNCTION(http_negotiate_charset); PHP_FUNCTION(http_negotiate_content_type); diff --git a/php_http_std_defs.h b/php_http_std_defs.h index 4b5f44d..0cc40c9 100644 --- a/php_http_std_defs.h +++ b/php_http_std_defs.h @@ -97,11 +97,9 @@ typedef int STATUS; /* max URL length */ #define HTTP_URL_MAXLEN 4096 -#define HTTP_URI_MAXLEN HTTP_URL_MAXLEN /* def URL arg separator */ #define HTTP_URL_ARGSEP "&" -#define HTTP_URI_ARGSEP HTTP_URL_ARGSEP /* send buffer size */ #define HTTP_SENDBUF_SIZE 40960 diff --git a/php_http_url_api.h b/php_http_url_api.h index 77e6ef0..72cb538 100644 --- a/php_http_url_api.h +++ b/php_http_url_api.h @@ -15,11 +15,13 @@ #ifndef PHP_HTTP_URL_API_H #define PHP_HTTP_URL_API_H -#define http_absolute_uri(url) http_absolute_url(url) -#define http_absolute_uri_ex(url, url_len, proto, proto_len, host, host_len, port) _http_absolute_url_ex((url), (url_len), (proto), (proto_len), (host), (host_len), (port) TSRMLS_CC) -#define http_absolute_url(url) http_absolute_url_ex((url), strlen(url), NULL, 0, NULL, 0, 0) -#define http_absolute_url_ex(url, url_len, proto, proto_len, host, host_len, port) _http_absolute_url_ex((url), (url_len), (proto), (proto_len), (host), (host_len), (port) TSRMLS_CC) -PHP_HTTP_API char *_http_absolute_url_ex(const char *url, size_t url_len, const char *proto, size_t proto_len, const char *host, size_t host_len, unsigned port TSRMLS_DC); +#include "ext/standard/url.h" + +#define http_absolute_url(u) _http_absolute_url((u) TSRMLS_CC) +PHP_HTTP_API char *_http_absolute_url(const char *url TSRMLS_DC); + +#define http_build_url(o, n, p, s, l) _http_build_url((o), (n), (p), (s), (l) TSRMLS_CC) +PHP_HTTP_API void _http_build_url(const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC); #define http_urlencode_hash(h, q) _http_urlencode_hash_ex((h), 1, NULL, 0, (q), NULL TSRMLS_CC) #define http_urlencode_hash_ex(h, o, p, pl, q, ql) _http_urlencode_hash_ex((h), (o), (p), (pl), (q), (ql) TSRMLS_CC) @@ -28,6 +30,55 @@ PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_ #define http_urlencode_hash_recursive(ht, s, as, al, pr, pl) _http_urlencode_hash_recursive((ht), (s), (as), (al), (pr), (pl) TSRMLS_CC) PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, const char *arg_sep, size_t arg_sep_len, const char *prefix, size_t prefix_len TSRMLS_DC); +#define array2url(ht) _array2url((ht) TSRMLS_CC) +static inline php_url *_array2url(HashTable *ht TSRMLS_DC) +{ + zval **e; + php_url *url = ecalloc(1, sizeof(php_url)); + + if ((SUCCESS == zend_hash_find(ht, "scheme", sizeof("scheme"), (void **) &e)) + && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { + url->scheme = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); + } + if ((SUCCESS == zend_hash_find(ht, "user", sizeof("user"), (void **) &e)) + && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { + url->user = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); + } + if ((SUCCESS == zend_hash_find(ht, "pass", sizeof("pass"), (void **) &e)) + && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { + url->pass = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); + } + if ((SUCCESS == zend_hash_find(ht, "host", sizeof("host"), (void **) &e)) + && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { + url->host = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); + } + if ((SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void **) &e)) + && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { + url->path = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); + } + if ((SUCCESS == zend_hash_find(ht, "query", sizeof("query"), (void **) &e)) + && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { + url->query = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); + } + if ((SUCCESS == zend_hash_find(ht, "fragment", sizeof("fragment"), (void **) &e)) + && (Z_TYPE_PP(e) == IS_STRING) && Z_STRLEN_PP(e)) { + url->fragment = estrndup(Z_STRVAL_PP(e), Z_STRLEN_PP(e)); + } + if (SUCCESS == zend_hash_find(ht, "port", sizeof("port"), (void **) &e)) { + if (Z_TYPE_PP(e) == IS_LONG) { + url->port = (unsigned short) Z_LVAL_PP(e); + } else { + zval *o = *e; + + convert_to_long_ex(e); + url->port = (unsigned short) Z_LVAL_PP(e); + if (o != *e) zval_ptr_dtor(e); + } + } + + return url; +} + #endif /* diff --git a/php_http_util_object.h b/php_http_util_object.h index 6225ae8..eff4817 100644 --- a/php_http_util_object.h +++ b/php_http_util_object.h @@ -22,7 +22,7 @@ extern zend_function_entry http_util_object_fe[]; extern PHP_MINIT_FUNCTION(http_util_object); PHP_METHOD(HttpUtil, date); -PHP_METHOD(HttpUtil, absoluteUri); +PHP_METHOD(HttpUtil, buildUrl); PHP_METHOD(HttpUtil, negotiateLanguage); PHP_METHOD(HttpUtil, negotiateCharset); PHP_METHOD(HttpUtil, negotiateContentType); diff --git a/tests/abs_uri_002.phpt b/tests/abs_uri_002.phpt deleted file mode 100644 index 47f796b..0000000 --- a/tests/abs_uri_002.phpt +++ /dev/null @@ -1,19 +0,0 @@ ---TEST-- -http_absolute_uri() with proto ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -%sTEST -https://localhost/sec -ftp://localhost/pub -http://localhost/ - diff --git a/tests/abs_uri_001.phpt b/tests/build_url_001.phpt similarity index 55% rename from tests/abs_uri_001.phpt rename to tests/build_url_001.phpt index e76191e..541e0f3 100644 --- a/tests/abs_uri_001.phpt +++ b/tests/build_url_001.phpt @@ -1,5 +1,5 @@ --TEST-- -http_absolute_uri() with relative paths +http_build_url() with relative paths --SKIPIF-- --EXPECTF-- %sTEST diff --git a/tests/build_url_002.phpt b/tests/build_url_002.phpt new file mode 100644 index 0000000..6dc55f0 --- /dev/null +++ b/tests/build_url_002.phpt @@ -0,0 +1,30 @@ +--TEST-- +http_build_url() with parse_url() +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +%sTEST +https://www.example.com:9999/replaced?q=1#n +https://www.example.com:9999/replaced?q=1#n +Array +( + [scheme] => https + [host] => www.example.com + [port] => 9999 + [path] => /replaced + [query] => q=1 + [fragment] => n +) +Done diff --git a/tests/build_uri_001.phpt b/tests/build_url_003.phpt similarity index 53% rename from tests/build_uri_001.phpt rename to tests/build_url_003.phpt index b80f52e..6e343a3 100644 --- a/tests/build_uri_001.phpt +++ b/tests/build_url_003.phpt @@ -1,5 +1,5 @@ --TEST-- -http_build_uri() +http_build_url() --SKIPIF-- 'https'))); +printf("-%s-\n", http_build_url($url, array('scheme' => 'https', 'host' => 'ssl.example.com'))); +printf("-%s-\n", http_build_url($url, array('scheme' => 'ftp', 'host' => 'ftp.example.com', 'port' => 21))); echo "Done\n"; ?> --EXPECTF-- diff --git a/tests/ut_HttpUtil.phpt b/tests/ut_HttpUtil.phpt index bbd61e0..98a11e8 100644 --- a/tests/ut_HttpUtil.phpt +++ b/tests/ut_HttpUtil.phpt @@ -24,12 +24,12 @@ class HttpUtilTest extends PHPUnit2_Framework_TestCase $this->assertEquals('Thu, 01 Jan 1970 00:00:01 GMT', HttpUtil::date(1)); } - function test_buildUri() + function test_buildUrl() { $_SERVER['SERVER_NAME'] = 'www.example.com'; - $this->assertEquals('http://www.example.com/test.php?foo=bar', HttpUtil::buildUri('/test.php?foo=bar', null, null, 80)); - $this->assertEquals('https://www.example.com/', HttpUtil::buildUri('/', 'https')); - $this->assertEquals('ftp://ftp.example.com/pub', HttpUtil::buildUri('/pub', null, 'ftp.example.com', 21)); + $this->assertEquals('http://www.example.com/test.php?foo=bar', HttpUtil::buildUrl('/test.php?foo=bar', null, null, 80)); + $this->assertEquals('https://www.example.com/', HttpUtil::buildUrl('/', 'https')); + $this->assertEquals('ftp://ftp.example.com/pub', HttpUtil::buildUrl('/pub', null, 'ftp.example.com', 21)); } function test_negotiateLanguage() -- 2.30.2