X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_url_api.c;h=8a70b0f2fb18b3435110b436b7f1f68023cafb15;hp=cac64ec81ee880812cb10e186169363b50252855;hb=ad5f896b03adaa073134a00108a9cdf00720673a;hpb=5b969e9665308562361cb01c0f63a2793f81f0ef diff --git a/http_url_api.c b/http_url_api.c index cac64ec..8a70b0f 100644 --- a/http_url_api.c +++ b/http_url_api.c @@ -6,7 +6,7 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2006, Michael Wallner | + | Copyright (c) 2004-2010, Michael Wallner | +--------------------------------------------------------------------+ */ @@ -21,6 +21,7 @@ #include "ext/standard/php_string.h" #include "php_http_api.h" +#include "php_http_querystring_api.h" #include "php_http_url_api.h" static inline char *localhostname(void) @@ -31,10 +32,10 @@ static inline char *localhostname(void) if (SUCCESS == gethostname(hostname, lenof(hostname))) { return estrdup(hostname); } -#elif defined(HAVE_UNISTD_H) +#elif defined(HAVE_GETHOSTNAME) if (SUCCESS == gethostname(hostname, lenof(hostname))) { +# if defined(HAVE_GETDOMAINNAME) size_t hlen = strlen(hostname); - if (hlen <= lenof(hostname) - lenof("(none)")) { hostname[hlen++] = '.'; if (SUCCESS == getdomainname(&hostname[hlen], lenof(hostname) - hlen)) { @@ -44,9 +45,13 @@ static inline char *localhostname(void) return estrdup(hostname); } } +# endif + if (strcmp(hostname, "(none)")) { + return estrdup(hostname); + } } #endif - return estrdup("localhost"); + return estrndup("localhost", lenof("localhost")); } PHP_MINIT_FUNCTION(http_url) @@ -61,21 +66,29 @@ PHP_MINIT_FUNCTION(http_url) HTTP_LONG_CONSTANT("HTTP_URL_STRIP_PATH", HTTP_URL_STRIP_PATH); HTTP_LONG_CONSTANT("HTTP_URL_STRIP_QUERY", HTTP_URL_STRIP_QUERY); HTTP_LONG_CONSTANT("HTTP_URL_STRIP_FRAGMENT", HTTP_URL_STRIP_FRAGMENT); + HTTP_LONG_CONSTANT("HTTP_URL_STRIP_ALL", HTTP_URL_STRIP_ALL); + HTTP_LONG_CONSTANT("HTTP_URL_FROM_ENV", HTTP_URL_FROM_ENV); return SUCCESS; } -PHP_HTTP_API char *_http_absolute_url(const char *url TSRMLS_DC) +PHP_HTTP_API char *_http_absolute_url_ex(const char *url, int flags TSRMLS_DC) { - char *abs = estrdup(url); - php_url *purl = php_url_parse(abs); + char *abs = NULL; + php_url *purl = NULL; - STR_SET(abs, NULL); + if (url) { + purl = php_url_parse(abs = estrdup(url)); + STR_SET(abs, NULL); + if (!purl) { + http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse URL (%s)", url); + return NULL; + } + } + + http_build_url(flags, purl, NULL, NULL, &abs, NULL); if (purl) { - http_build_url(0, purl, NULL, NULL, &abs, NULL); php_url_free(purl); - } else { - http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse URL (%s)", url); } return abs; @@ -84,7 +97,7 @@ PHP_HTTP_API char *_http_absolute_url(const char *url TSRMLS_DC) /* {{{ void http_build_url(int flags, const php_url *, const php_url *, php_url **, char **, size_t *) */ PHP_HTTP_API void _http_build_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) { -#ifdef HTTP_HAVE_NETDB +#if defined(HAVE_GETSERVBYPORT) || defined(HAVE_GETSERVBYNAME) struct servent *se; #endif php_url *url = ecalloc(1, sizeof(php_url)); @@ -95,12 +108,12 @@ PHP_HTTP_API void _http_build_url(int flags, const php_url *old_url, const php_u url->n = __URLSET(new_url,n) ? estrdup(new_url->n) : (__URLSET(old_url,n) ? estrdup(old_url->n) : NULL) if (!(flags & HTTP_URL_STRIP_PORT)) { - url->port = (new_url&&new_url->port) ? new_url->port : ((old_url) ? old_url->port : 0); + url->port = __URLSET(new_url, port) ? new_url->port : ((old_url) ? old_url->port : 0); } - if ((!(flags & HTTP_URL_STRIP_AUTH)) && (!(flags & HTTP_URL_STRIP_USER))) { + if (!(flags & HTTP_URL_STRIP_USER)) { __URLCPY(user); } - if ((!(flags & HTTP_URL_STRIP_AUTH)) && (!(flags & HTTP_URL_STRIP_PASS))) { + if (!(flags & HTTP_URL_STRIP_PASS)) { __URLCPY(pass); } @@ -125,10 +138,21 @@ PHP_HTTP_API void _http_build_url(int flags, const php_url *old_url, const php_u } if (!(flags & HTTP_URL_STRIP_QUERY)) { if ((flags & HTTP_URL_JOIN_QUERY) && __URLSET(new_url, query) && __URLSET(old_url, query)) { - url->query = ecalloc(1, strlen(new_url->query) + strlen(old_url->query) + 1 + 1); - strcat(url->query, old_url->query); - strcat(url->query, "&"); - strcat(url->query, new_url->query); + zval qarr, qstr; + + INIT_PZVAL(&qstr); + INIT_PZVAL(&qarr); + array_init(&qarr); + + ZVAL_STRING(&qstr, old_url->query, 0); + http_querystring_modify(&qarr, &qstr); + ZVAL_STRING(&qstr, new_url->query, 0); + http_querystring_modify(&qarr, &qstr); + + ZVAL_NULL(&qstr); + http_querystring_update(&qarr, &qstr); + url->query = Z_STRVAL(qstr); + zval_dtor(&qarr); } else { __URLCPY(query); } @@ -138,44 +162,55 @@ PHP_HTTP_API void _http_build_url(int flags, const php_url *old_url, const php_u } if (!url->scheme) { - switch (url->port) - { - case 443: + if (flags & HTTP_URL_FROM_ENV) { + zval *https = http_get_server_var("HTTPS", 1); + if (https && !strcasecmp(Z_STRVAL_P(https), "ON")) { url->scheme = estrndup("https", lenof("https")); - break; + } else switch (url->port) { + case 443: + url->scheme = estrndup("https", lenof("https")); + break; -#ifndef HTTP_HAVE_NETDB - default: +#ifndef HAVE_GETSERVBYPORT + default: #endif - case 80: - url->scheme = estrndup("http", lenof("http")); - break; - -#ifdef HTTP_HAVE_NETDB - default: - if ((se = getservbyport(htons(url->port), "tcp")) && se->s_name) { - url->scheme = estrdup(se->s_name); - } else { + case 80: + case 0: url->scheme = estrndup("http", lenof("http")); - } - break; + break; + +#ifdef HAVE_GETSERVBYPORT + 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 + } + } else { + url->scheme = estrndup("http", lenof("http")); } } 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)); + if (flags & HTTP_URL_FROM_ENV) { + zval *zhost; + + if ((((zhost = http_get_server_var("HTTP_HOST", 1)) || + (zhost = http_get_server_var("SERVER_NAME", 1)))) && Z_STRLEN_P(zhost)) { + url->host = estrndup(Z_STRVAL_P(zhost), Z_STRLEN_P(zhost)); + } else { + url->host = localhostname(); + } } else { - url->host = localhostname(); + url->host = estrndup("localhost", lenof("localhost")); } } if (!url->path) { - if (SG(request_info).request_uri && *SG(request_info).request_uri) { + if ((flags & HTTP_URL_FROM_ENV) && SG(request_info).request_uri && SG(request_info).request_uri[0]) { const char *q = strchr(SG(request_info).request_uri, '?'); if (q) { @@ -186,42 +221,43 @@ PHP_HTTP_API void _http_build_url(int flags, const php_url *old_url, const php_u } else { url->path = estrndup("/", 1); } - } else if (*url->path != '/') { - if (SG(request_info).request_uri && *SG(request_info).request_uri) { - const char *q = strchr(SG(request_info).request_uri, '?'); - char *uri, *path; - size_t len; + } else if (url->path[0] != '/') { + if ((flags & HTTP_URL_FROM_ENV) && SG(request_info).request_uri && SG(request_info).request_uri[0]) { + size_t ulen = strlen(SG(request_info).request_uri); + size_t plen = strlen(url->path); + char *path; - if (q) { - uri = estrndup(SG(request_info).request_uri, len = q - SG(request_info).request_uri); - } else { - uri = estrndup(SG(request_info).request_uri, len = strlen(SG(request_info).request_uri)); + if (SG(request_info).request_uri[ulen-1] != '/') { + for (--ulen; ulen && SG(request_info).request_uri[ulen - 1] != '/'; --ulen); } - php_dirname(uri, len); - spprintf(&path, 0, "%s/%s", uri, url->path); - efree(uri); + path = emalloc(ulen + plen + 1); + memcpy(path, SG(request_info).request_uri, ulen); + memcpy(path + ulen, url->path, plen); + path[ulen + plen] = '\0'; STR_SET(url->path, path); } else { - char *uri; + size_t plen = strlen(url->path); + char *path = emalloc(plen + 1 + 1); - spprintf(&uri, 0, "/%s", url->path); - STR_SET(url->path, uri); + path[0] = '/'; + memcpy(&path[1], url->path, plen + 1); + STR_SET(url->path, path); } } - if (url->path) { + /* replace directory references if path is not a single slash */ + if (url->path[0] && (url->path[0] != '/' || url->path[1])) { char *ptr, *end = url->path + strlen(url->path) + 1; for (ptr = strstr(url->path, "/."); ptr; ptr = strstr(ptr, "/.")) { - switch (ptr[2]) - { + switch (ptr[2]) { case '\0': ptr[1] = '\0'; - break; + break; case '/': memmove(&ptr[1], &ptr[3], end - &ptr[3]); - break; + break; case '.': if (ptr[3] == '/') { @@ -232,13 +268,17 @@ PHP_HTTP_API void _http_build_url(int flags, const php_url *old_url, const php_u } } memmove(&ptr[1], pos, end - pos); + break; + } else if (!ptr[3]) { + /* .. at the end */ + ptr[1] = '\0'; } - break; + /* fallthrough */ default: /* something else */ ++ptr; - break; + break; } } } @@ -246,7 +286,7 @@ PHP_HTTP_API void _http_build_url(int flags, const php_url *old_url, const php_u if (url->port) { if ( ((url->port == 80) && !strcmp(url->scheme, "http")) || ((url->port ==443) && !strcmp(url->scheme, "https")) -#ifdef HTTP_HAVE_NETDB +#ifdef HAVE_GETSERVBYNAME || ((se = getservbyname(url->scheme, "tcp")) && se->s_port && (url->port == ntohs(se->s_port))) #endif @@ -276,16 +316,13 @@ PHP_HTTP_API void _http_build_url(int flags, const php_url *old_url, const php_u strlcat(*url_str, url->host, HTTP_URL_MAXLEN); if (url->port) { - char port_str[8] = {0}; + char port_str[8]; - snprintf(port_str, lenof(port_str), "%d", (int) url->port); + snprintf(port_str, sizeof(port_str), "%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) { @@ -347,9 +384,7 @@ PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_ /* {{{ http_urlencode_hash_recursive */ 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) { - char *key = NULL; - uint len = 0; - ulong idx = 0; + HashKey key = initHashKey(0); zval **data = NULL; HashPosition pos; @@ -361,7 +396,7 @@ PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, c return SUCCESS; } - FOREACH_HASH_KEYLENVAL(pos, ht, key, len, idx, data) { + FOREACH_HASH_KEYVAL(pos, ht, key, data) { char *encoded_key; int encoded_len; phpstr new_prefix; @@ -371,36 +406,39 @@ PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, c return FAILURE; } - if (key) { - if (len && key[len - 1] == '\0') { - --len; + if (key.type == HASH_KEY_IS_STRING) { + if (!*key.str) { + /* only public properties */ + continue; + } + if (key.len && key.str[key.len - 1] == '\0') { + --key.len; } - encoded_key = php_url_encode(key, len, &encoded_len); - key = NULL; + encoded_key = php_url_encode(key.str, key.len, &encoded_len); } else { - encoded_len = spprintf(&encoded_key, 0, "%ld", idx); + encoded_len = spprintf(&encoded_key, 0, "%ld", key.num); } { phpstr_init(&new_prefix); if (prefix && prefix_len) { phpstr_append(&new_prefix, prefix, prefix_len); - phpstr_appends(&new_prefix, "["); + phpstr_appends(&new_prefix, "%5B"); } phpstr_append(&new_prefix, encoded_key, encoded_len); efree(encoded_key); if (prefix && prefix_len) { - phpstr_appends(&new_prefix, "]"); + phpstr_appends(&new_prefix, "%5D"); } phpstr_fix(&new_prefix); } - if (Z_TYPE_PP(data) == IS_ARRAY) { + if (Z_TYPE_PP(data) == IS_ARRAY || Z_TYPE_PP(data) == IS_OBJECT) { STATUS status; ++ht->nApplyCount; - status = http_urlencode_hash_recursive(Z_ARRVAL_PP(data), str, arg_sep, arg_sep_len, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix)); + status = http_urlencode_hash_recursive(HASH_OF(*data), str, arg_sep, arg_sep_len, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix)); --ht->nApplyCount; if (SUCCESS != status) { phpstr_dtor(&new_prefix); @@ -408,7 +446,7 @@ PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, c return FAILURE; } } else { - zval *val = zval_copy(IS_STRING, *data); + zval *val = http_zsep(IS_STRING, *data); if (PHPSTR_LEN(str)) { phpstr_append(str, arg_sep, arg_sep_len); @@ -425,7 +463,7 @@ PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, c efree(encoded_val); } - zval_free(&val); + zval_ptr_dtor(&val); } phpstr_dtor(&new_prefix); }