summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph M. Becker <cmbecker69@gmx.de>2020-11-04 11:34:10 +0100
committerChristoph M. Becker <cmbecker69@gmx.de>2020-11-04 14:53:19 +0100
commit2cab085bb37a6980b8f23a4b3c31b813ac67cda0 (patch)
tree3db67a8c445768500b408e96dbf5667aed9f5d61
parent00ba784a2ce95e009f98e0e6d263634673a3f2e1 (diff)
downloadphp-git-2cab085bb37a6980b8f23a4b3c31b813ac67cda0.tar.gz
Fix #80266: parse_url silently drops port number 0
As of commit 81b2f3e[1], `parse_url()` accepts URLs with a zero port, but does not report that port, what is wrong in hindsight. Since the port number is stored as `unsigned short` there is no way to distinguish between port zero and no port. For BC reasons, we thus introduce `parse_url_ex2()` which accepts an output parameter that allows that distinction, and use the new function to fix the behavior. The introduction of `parse_url_ex2()` has been suggested by Nikita. [1] <http://git.php.net/?p=php-src.git;a=commit;h=81b2f3e5d9fcdffd87a4fcd12bd8c708a97091e1> Closes GH-6399.
-rw-r--r--NEWS3
-rw-r--r--ext/standard/tests/url/parse_url_basic_001.phpt4
-rw-r--r--ext/standard/tests/url/parse_url_basic_004.phpt2
-rw-r--r--ext/standard/tests/url/parse_url_unterminated.phpt4
-rw-r--r--ext/standard/url.c20
-rw-r--r--ext/standard/url.h1
6 files changed, 26 insertions, 8 deletions
diff --git a/NEWS b/NEWS
index f6963784d8..4513508271 100644
--- a/NEWS
+++ b/NEWS
@@ -29,6 +29,9 @@ PHP NEWS
. Fixed bug #70461 (disable md5 code when it is not supported in net-snmp).
(Alexander Bergmann, cmb)
+- Standard:
+ . Fixed bug #80266 (parse_url silently drops port number 0). (cmb, Nikita)
+
29 Oct 2020, PHP 7.3.24
- Core:
diff --git a/ext/standard/tests/url/parse_url_basic_001.phpt b/ext/standard/tests/url/parse_url_basic_001.phpt
index 063fc28832..7ffd001856 100644
--- a/ext/standard/tests/url/parse_url_basic_001.phpt
+++ b/ext/standard/tests/url/parse_url_basic_001.phpt
@@ -859,11 +859,13 @@ echo "Done";
string(3) "%:x"
}
---> https://example.com:0/: array(3) {
+--> https://example.com:0/: array(4) {
["scheme"]=>
string(5) "https"
["host"]=>
string(11) "example.com"
+ ["port"]=>
+ int(0)
["path"]=>
string(1) "/"
}
diff --git a/ext/standard/tests/url/parse_url_basic_004.phpt b/ext/standard/tests/url/parse_url_basic_004.phpt
index 042daefeda..533d304ee7 100644
--- a/ext/standard/tests/url/parse_url_basic_004.phpt
+++ b/ext/standard/tests/url/parse_url_basic_004.phpt
@@ -112,7 +112,7 @@ echo "Done";
--> / : NULL
--> /rest/Users?filter={"id":"123"} : NULL
--> %:x : NULL
---> https://example.com:0/ : NULL
+--> https://example.com:0/ : int(0)
--> http:///blah.com : bool(false)
--> http://:80 : bool(false)
--> http://user@:80 : bool(false)
diff --git a/ext/standard/tests/url/parse_url_unterminated.phpt b/ext/standard/tests/url/parse_url_unterminated.phpt
index 8af50dbe28..8f46eb3dbe 100644
--- a/ext/standard/tests/url/parse_url_unterminated.phpt
+++ b/ext/standard/tests/url/parse_url_unterminated.phpt
@@ -861,11 +861,13 @@ echo "Done";
string(3) "%:x"
}
---> https://example.com:0/: array(3) {
+--> https://example.com:0/: array(4) {
["scheme"]=>
string(5) "https"
["host"]=>
string(11) "example.com"
+ ["port"]=>
+ int(0)
["path"]=>
string(1) "/"
}
diff --git a/ext/standard/url.c b/ext/standard/url.c
index fde4ff5377..98dc0f786d 100644
--- a/ext/standard/url.c
+++ b/ext/standard/url.c
@@ -102,14 +102,21 @@ static const char *binary_strcspn(const char *s, const char *e, const char *char
return e;
}
-/* {{{ php_url_parse
- */
PHPAPI php_url *php_url_parse_ex(char const *str, size_t length)
{
+ zend_bool has_port;
+ return php_url_parse_ex2(str, length, &has_port);
+}
+
+/* {{{ php_url_parse_ex2
+ */
+PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, zend_bool *has_port)
+{
char port_buf[6];
php_url *ret = ecalloc(1, sizeof(php_url));
char const *s, *e, *p, *pp, *ue;
+ *has_port = 0;
s = str;
ue = s + length;
@@ -199,6 +206,7 @@ PHPAPI php_url *php_url_parse_ex(char const *str, size_t length)
port_buf[pp - p] = '\0';
port = ZEND_STRTOL(port_buf, &end, 10);
if (port >= 0 && port <= 65535 && end != port_buf) {
+ *has_port = 1;
ret->port = (unsigned short) port;
if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
s += 2;
@@ -264,6 +272,7 @@ parse_host:
port_buf[e - p] = '\0';
port = ZEND_STRTOL(port_buf, &end, 10);
if (port >= 0 && port <= 65535 && end != port_buf) {
+ *has_port = 1;
ret->port = (unsigned short)port;
} else {
php_url_free(ret);
@@ -332,6 +341,7 @@ PHP_FUNCTION(parse_url)
php_url *resource;
zend_long key = -1;
zval tmp;
+ zend_bool has_port;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STRING(str, str_len)
@@ -339,7 +349,7 @@ PHP_FUNCTION(parse_url)
Z_PARAM_LONG(key)
ZEND_PARSE_PARAMETERS_END();
- resource = php_url_parse_ex(str, str_len);
+ resource = php_url_parse_ex2(str, str_len, &has_port);
if (resource == NULL) {
/* @todo Find a method to determine why php_url_parse_ex() failed */
RETURN_FALSE;
@@ -354,7 +364,7 @@ PHP_FUNCTION(parse_url)
if (resource->host != NULL) RETVAL_STR_COPY(resource->host);
break;
case PHP_URL_PORT:
- if (resource->port != 0) RETVAL_LONG(resource->port);
+ if (has_port) RETVAL_LONG(resource->port);
break;
case PHP_URL_USER:
if (resource->user != NULL) RETVAL_STR_COPY(resource->user);
@@ -390,7 +400,7 @@ PHP_FUNCTION(parse_url)
ZVAL_STR_COPY(&tmp, resource->host);
zend_hash_add_new(Z_ARRVAL_P(return_value), ZSTR_KNOWN(ZEND_STR_HOST), &tmp);
}
- if (resource->port != 0) {
+ if (has_port) {
ZVAL_LONG(&tmp, resource->port);
zend_hash_add_new(Z_ARRVAL_P(return_value), ZSTR_KNOWN(ZEND_STR_PORT), &tmp);
}
diff --git a/ext/standard/url.h b/ext/standard/url.h
index ec925a2bd0..0e187065df 100644
--- a/ext/standard/url.h
+++ b/ext/standard/url.h
@@ -33,6 +33,7 @@ typedef struct php_url {
PHPAPI void php_url_free(php_url *theurl);
PHPAPI php_url *php_url_parse(char const *str);
PHPAPI php_url *php_url_parse_ex(char const *str, size_t length);
+PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, zend_bool *has_port);
PHPAPI size_t php_url_decode(char *str, size_t len); /* return value: length of decoded string */
PHPAPI size_t php_raw_url_decode(char *str, size_t len); /* return value: length of decoded string */
PHPAPI zend_string *php_url_encode(char const *s, size_t len);