From 0b32baf358e94f0907d2fba9619c533cc2d127ac Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Thu, 17 Sep 2020 14:56:31 +0200 Subject: [PATCH 1/3] Fix #80114: parse_url does not accept URLs with port 0 URIs with a 0 port are generally valid, so `parse_url()` should recognize such URIs, but still report the port as missing. --- ext/standard/tests/url/bug80114.phpt | 15 +++++++++++++++ ext/standard/url.c | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 ext/standard/tests/url/bug80114.phpt diff --git a/ext/standard/tests/url/bug80114.phpt b/ext/standard/tests/url/bug80114.phpt new file mode 100644 index 0000000000000..a8b6d092a67ee --- /dev/null +++ b/ext/standard/tests/url/bug80114.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #80114 (parse_url does not accept URLs with port 0) +--FILE-- + +--EXPECT-- +array(3) { + ["scheme"]=> + string(5) "https" + ["host"]=> + string(11) "example.com" + ["path"]=> + string(1) "/" +} diff --git a/ext/standard/url.c b/ext/standard/url.c index 7763759bc1d0b..4aa8e78efc9c6 100644 --- a/ext/standard/url.c +++ b/ext/standard/url.c @@ -261,7 +261,7 @@ PHPAPI php_url *php_url_parse_ex(char const *str, size_t length) memcpy(port_buf, p, (e - p)); port_buf[e - p] = '\0'; port = ZEND_STRTOL(port_buf, NULL, 10); - if (port > 0 && port <= 65535) { + if ((port > 0 && port <= 65535) || (port == 0 && *port_buf == '0' && e - p == 1)) { ret->port = (unsigned short)port; } else { php_url_free(ret); From d081a74d444149de2a83a2fd9120e4a3a2a8ccbc Mon Sep 17 00:00:00 2001 From: twosee Date: Fri, 18 Sep 2020 19:09:29 +0800 Subject: [PATCH 2/3] Another way How about this way, and it also needs to be applied to `//example.com:0` --- ext/standard/url.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ext/standard/url.c b/ext/standard/url.c index 4aa8e78efc9c6..fde4ff5377967 100644 --- a/ext/standard/url.c +++ b/ext/standard/url.c @@ -194,10 +194,11 @@ PHPAPI php_url *php_url_parse_ex(char const *str, size_t length) if (pp - p > 0 && pp - p < 6 && (pp == ue || *pp == '/')) { zend_long port; + char *end; memcpy(port_buf, p, (pp - p)); port_buf[pp - p] = '\0'; - port = ZEND_STRTOL(port_buf, NULL, 10); - if (port > 0 && port <= 65535) { + port = ZEND_STRTOL(port_buf, &end, 10); + if (port >= 0 && port <= 65535 && end != port_buf) { ret->port = (unsigned short) port; if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */ s += 2; @@ -258,10 +259,11 @@ PHPAPI php_url *php_url_parse_ex(char const *str, size_t length) return NULL; } else if (e - p > 0) { zend_long port; + char *end; memcpy(port_buf, p, (e - p)); port_buf[e - p] = '\0'; - port = ZEND_STRTOL(port_buf, NULL, 10); - if ((port > 0 && port <= 65535) || (port == 0 && *port_buf == '0' && e - p == 1)) { + port = ZEND_STRTOL(port_buf, &end, 10); + if (port >= 0 && port <= 65535 && end != port_buf) { ret->port = (unsigned short)port; } else { php_url_free(ret); From 9aabb4fb522eab76a2e2d759327093855afb5fcc Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 20 Sep 2020 13:45:09 +0200 Subject: [PATCH 3/3] Move test case to urls.inc --- ext/standard/tests/url/bug80114.phpt | 15 --------------- ext/standard/tests/url/parse_url_basic_001.phpt | 9 +++++++++ ext/standard/tests/url/parse_url_basic_002.phpt | 1 + ext/standard/tests/url/parse_url_basic_003.phpt | 1 + ext/standard/tests/url/parse_url_basic_004.phpt | 1 + ext/standard/tests/url/parse_url_basic_005.phpt | 1 + ext/standard/tests/url/parse_url_basic_006.phpt | 1 + ext/standard/tests/url/parse_url_basic_007.phpt | 1 + ext/standard/tests/url/parse_url_basic_008.phpt | 1 + ext/standard/tests/url/parse_url_basic_009.phpt | 1 + .../tests/url/parse_url_unterminated.phpt | 9 +++++++++ ext/standard/tests/url/urls.inc | 1 + 12 files changed, 27 insertions(+), 15 deletions(-) delete mode 100644 ext/standard/tests/url/bug80114.phpt diff --git a/ext/standard/tests/url/bug80114.phpt b/ext/standard/tests/url/bug80114.phpt deleted file mode 100644 index a8b6d092a67ee..0000000000000 --- a/ext/standard/tests/url/bug80114.phpt +++ /dev/null @@ -1,15 +0,0 @@ ---TEST-- -Bug #80114 (parse_url does not accept URLs with port 0) ---FILE-- - ---EXPECT-- -array(3) { - ["scheme"]=> - string(5) "https" - ["host"]=> - string(11) "example.com" - ["path"]=> - string(1) "/" -} diff --git a/ext/standard/tests/url/parse_url_basic_001.phpt b/ext/standard/tests/url/parse_url_basic_001.phpt index 51bae9fe1ca44..063fc28832fcc 100644 --- a/ext/standard/tests/url/parse_url_basic_001.phpt +++ b/ext/standard/tests/url/parse_url_basic_001.phpt @@ -859,6 +859,15 @@ echo "Done"; string(3) "%:x" } +--> https://example.com:0/: array(3) { + ["scheme"]=> + string(5) "https" + ["host"]=> + string(11) "example.com" + ["path"]=> + string(1) "/" +} + --> http:///blah.com: bool(false) --> http://:80: bool(false) diff --git a/ext/standard/tests/url/parse_url_basic_002.phpt b/ext/standard/tests/url/parse_url_basic_002.phpt index 309c038794c45..42a8457431e75 100644 --- a/ext/standard/tests/url/parse_url_basic_002.phpt +++ b/ext/standard/tests/url/parse_url_basic_002.phpt @@ -113,6 +113,7 @@ echo "Done"; --> / : NULL --> /rest/Users?filter={"id":"123"} : NULL --> %:x : NULL +--> https://example.com:0/ : string(5) "https" --> http:///blah.com : bool(false) --> http://:80 : bool(false) --> http://user@:80 : bool(false) diff --git a/ext/standard/tests/url/parse_url_basic_003.phpt b/ext/standard/tests/url/parse_url_basic_003.phpt index 9649bdadb1238..8b0e7eb87500a 100644 --- a/ext/standard/tests/url/parse_url_basic_003.phpt +++ b/ext/standard/tests/url/parse_url_basic_003.phpt @@ -112,6 +112,7 @@ echo "Done"; --> / : NULL --> /rest/Users?filter={"id":"123"} : NULL --> %:x : NULL +--> https://example.com:0/ : string(11) "example.com" --> http:///blah.com : bool(false) --> http://:80 : bool(false) --> http://user@:80 : bool(false) diff --git a/ext/standard/tests/url/parse_url_basic_004.phpt b/ext/standard/tests/url/parse_url_basic_004.phpt index 75aacdf847ada..042daefeda8d9 100644 --- a/ext/standard/tests/url/parse_url_basic_004.phpt +++ b/ext/standard/tests/url/parse_url_basic_004.phpt @@ -112,6 +112,7 @@ echo "Done"; --> / : NULL --> /rest/Users?filter={"id":"123"} : NULL --> %:x : NULL +--> https://example.com:0/ : NULL --> http:///blah.com : bool(false) --> http://:80 : bool(false) --> http://user@:80 : bool(false) diff --git a/ext/standard/tests/url/parse_url_basic_005.phpt b/ext/standard/tests/url/parse_url_basic_005.phpt index 1463e0a29ae04..a5ca381a691fe 100644 --- a/ext/standard/tests/url/parse_url_basic_005.phpt +++ b/ext/standard/tests/url/parse_url_basic_005.phpt @@ -112,6 +112,7 @@ echo "Done"; --> / : NULL --> /rest/Users?filter={"id":"123"} : NULL --> %:x : NULL +--> https://example.com:0/ : NULL --> http:///blah.com : bool(false) --> http://:80 : bool(false) --> http://user@:80 : bool(false) diff --git a/ext/standard/tests/url/parse_url_basic_006.phpt b/ext/standard/tests/url/parse_url_basic_006.phpt index 78eee265ce4df..51dcb2018cd88 100644 --- a/ext/standard/tests/url/parse_url_basic_006.phpt +++ b/ext/standard/tests/url/parse_url_basic_006.phpt @@ -112,6 +112,7 @@ echo "Done"; --> / : NULL --> /rest/Users?filter={"id":"123"} : NULL --> %:x : NULL +--> https://example.com:0/ : NULL --> http:///blah.com : bool(false) --> http://:80 : bool(false) --> http://user@:80 : bool(false) diff --git a/ext/standard/tests/url/parse_url_basic_007.phpt b/ext/standard/tests/url/parse_url_basic_007.phpt index 85a420c88c910..28a6d154f9988 100644 --- a/ext/standard/tests/url/parse_url_basic_007.phpt +++ b/ext/standard/tests/url/parse_url_basic_007.phpt @@ -112,6 +112,7 @@ echo "Done"; --> / : string(1) "/" --> /rest/Users?filter={"id":"123"} : string(11) "/rest/Users" --> %:x : string(3) "%:x" +--> https://example.com:0/ : string(1) "/" --> http:///blah.com : bool(false) --> http://:80 : bool(false) --> http://user@:80 : bool(false) diff --git a/ext/standard/tests/url/parse_url_basic_008.phpt b/ext/standard/tests/url/parse_url_basic_008.phpt index 75952b2ecd732..c2adc9e0700bf 100644 --- a/ext/standard/tests/url/parse_url_basic_008.phpt +++ b/ext/standard/tests/url/parse_url_basic_008.phpt @@ -112,6 +112,7 @@ echo "Done"; --> / : NULL --> /rest/Users?filter={"id":"123"} : string(19) "filter={"id":"123"}" --> %:x : NULL +--> https://example.com:0/ : NULL --> http:///blah.com : bool(false) --> http://:80 : bool(false) --> http://user@:80 : bool(false) diff --git a/ext/standard/tests/url/parse_url_basic_009.phpt b/ext/standard/tests/url/parse_url_basic_009.phpt index ab9232a9a7dd0..3074a08347c8c 100644 --- a/ext/standard/tests/url/parse_url_basic_009.phpt +++ b/ext/standard/tests/url/parse_url_basic_009.phpt @@ -112,6 +112,7 @@ echo "Done"; --> / : NULL --> /rest/Users?filter={"id":"123"} : NULL --> %:x : NULL +--> https://example.com:0/ : NULL --> 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 6a0cf02745354..8af50dbe287fe 100644 --- a/ext/standard/tests/url/parse_url_unterminated.phpt +++ b/ext/standard/tests/url/parse_url_unterminated.phpt @@ -861,6 +861,15 @@ echo "Done"; string(3) "%:x" } +--> https://example.com:0/: array(3) { + ["scheme"]=> + string(5) "https" + ["host"]=> + string(11) "example.com" + ["path"]=> + string(1) "/" +} + --> http:///blah.com: bool(false) --> http://:80: bool(false) diff --git a/ext/standard/tests/url/urls.inc b/ext/standard/tests/url/urls.inc index 199f22caea1d3..d334f4e9ab2be 100644 --- a/ext/standard/tests/url/urls.inc +++ b/ext/standard/tests/url/urls.inc @@ -92,6 +92,7 @@ $urls = array( '/', '/rest/Users?filter={"id":"123"}', '%:x', +'https://example.com:0/', // Severely malformed URLs that do not parse: 'http:///blah.com',