Skip to content

Commit 2cab085

Browse files
committed
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.
1 parent 00ba784 commit 2cab085

File tree

6 files changed

+26
-8
lines changed

6 files changed

+26
-8
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ PHP NEWS
2929
. Fixed bug #70461 (disable md5 code when it is not supported in net-snmp).
3030
(Alexander Bergmann, cmb)
3131

32+
- Standard:
33+
. Fixed bug #80266 (parse_url silently drops port number 0). (cmb, Nikita)
34+
3235
29 Oct 2020, PHP 7.3.24
3336

3437
- Core:

ext/standard/tests/url/parse_url_basic_001.phpt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -859,11 +859,13 @@ echo "Done";
859859
string(3) "%:x"
860860
}
861861

862-
--> https://example.com:0/: array(3) {
862+
--> https://example.com:0/: array(4) {
863863
["scheme"]=>
864864
string(5) "https"
865865
["host"]=>
866866
string(11) "example.com"
867+
["port"]=>
868+
int(0)
867869
["path"]=>
868870
string(1) "/"
869871
}

ext/standard/tests/url/parse_url_basic_004.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ echo "Done";
112112
--> / : NULL
113113
--> /rest/Users?filter={"id":"123"} : NULL
114114
--> %:x : NULL
115-
--> https://example.com:0/ : NULL
115+
--> https://example.com:0/ : int(0)
116116
--> http:///blah.com : bool(false)
117117
--> http://:80 : bool(false)
118118
--> http://user@:80 : bool(false)

ext/standard/tests/url/parse_url_unterminated.phpt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -861,11 +861,13 @@ echo "Done";
861861
string(3) "%:x"
862862
}
863863

864-
--> https://example.com:0/: array(3) {
864+
--> https://example.com:0/: array(4) {
865865
["scheme"]=>
866866
string(5) "https"
867867
["host"]=>
868868
string(11) "example.com"
869+
["port"]=>
870+
int(0)
869871
["path"]=>
870872
string(1) "/"
871873
}

ext/standard/url.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,21 @@ static const char *binary_strcspn(const char *s, const char *e, const char *char
102102
return e;
103103
}
104104

105-
/* {{{ php_url_parse
106-
*/
107105
PHPAPI php_url *php_url_parse_ex(char const *str, size_t length)
106+
{
107+
zend_bool has_port;
108+
return php_url_parse_ex2(str, length, &has_port);
109+
}
110+
111+
/* {{{ php_url_parse_ex2
112+
*/
113+
PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, zend_bool *has_port)
108114
{
109115
char port_buf[6];
110116
php_url *ret = ecalloc(1, sizeof(php_url));
111117
char const *s, *e, *p, *pp, *ue;
112118

119+
*has_port = 0;
113120
s = str;
114121
ue = s + length;
115122

@@ -199,6 +206,7 @@ PHPAPI php_url *php_url_parse_ex(char const *str, size_t length)
199206
port_buf[pp - p] = '\0';
200207
port = ZEND_STRTOL(port_buf, &end, 10);
201208
if (port >= 0 && port <= 65535 && end != port_buf) {
209+
*has_port = 1;
202210
ret->port = (unsigned short) port;
203211
if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
204212
s += 2;
@@ -264,6 +272,7 @@ PHPAPI php_url *php_url_parse_ex(char const *str, size_t length)
264272
port_buf[e - p] = '\0';
265273
port = ZEND_STRTOL(port_buf, &end, 10);
266274
if (port >= 0 && port <= 65535 && end != port_buf) {
275+
*has_port = 1;
267276
ret->port = (unsigned short)port;
268277
} else {
269278
php_url_free(ret);
@@ -332,14 +341,15 @@ PHP_FUNCTION(parse_url)
332341
php_url *resource;
333342
zend_long key = -1;
334343
zval tmp;
344+
zend_bool has_port;
335345

336346
ZEND_PARSE_PARAMETERS_START(1, 2)
337347
Z_PARAM_STRING(str, str_len)
338348
Z_PARAM_OPTIONAL
339349
Z_PARAM_LONG(key)
340350
ZEND_PARSE_PARAMETERS_END();
341351

342-
resource = php_url_parse_ex(str, str_len);
352+
resource = php_url_parse_ex2(str, str_len, &has_port);
343353
if (resource == NULL) {
344354
/* @todo Find a method to determine why php_url_parse_ex() failed */
345355
RETURN_FALSE;
@@ -354,7 +364,7 @@ PHP_FUNCTION(parse_url)
354364
if (resource->host != NULL) RETVAL_STR_COPY(resource->host);
355365
break;
356366
case PHP_URL_PORT:
357-
if (resource->port != 0) RETVAL_LONG(resource->port);
367+
if (has_port) RETVAL_LONG(resource->port);
358368
break;
359369
case PHP_URL_USER:
360370
if (resource->user != NULL) RETVAL_STR_COPY(resource->user);
@@ -390,7 +400,7 @@ PHP_FUNCTION(parse_url)
390400
ZVAL_STR_COPY(&tmp, resource->host);
391401
zend_hash_add_new(Z_ARRVAL_P(return_value), ZSTR_KNOWN(ZEND_STR_HOST), &tmp);
392402
}
393-
if (resource->port != 0) {
403+
if (has_port) {
394404
ZVAL_LONG(&tmp, resource->port);
395405
zend_hash_add_new(Z_ARRVAL_P(return_value), ZSTR_KNOWN(ZEND_STR_PORT), &tmp);
396406
}

ext/standard/url.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ typedef struct php_url {
3333
PHPAPI void php_url_free(php_url *theurl);
3434
PHPAPI php_url *php_url_parse(char const *str);
3535
PHPAPI php_url *php_url_parse_ex(char const *str, size_t length);
36+
PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, zend_bool *has_port);
3637
PHPAPI size_t php_url_decode(char *str, size_t len); /* return value: length of decoded string */
3738
PHPAPI size_t php_raw_url_decode(char *str, size_t len); /* return value: length of decoded string */
3839
PHPAPI zend_string *php_url_encode(char const *s, size_t len);

0 commit comments

Comments
 (0)