From 56a8bafda01565780a0f6ee6714c5634a84e88ec Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 28 Jan 2023 10:53:58 +0000 Subject: [PATCH 1/2] parse_url raises ValueError in some error code paths. --- ext/standard/tests/url/bug55399.phpt | 8 +++- .../tests/url/parse_url_basic_001.phpt | 40 ++++++++-------- .../tests/url/parse_url_basic_002.phpt | 40 ++++++++-------- .../tests/url/parse_url_basic_003.phpt | 40 ++++++++-------- .../tests/url/parse_url_basic_004.phpt | 40 ++++++++-------- .../tests/url/parse_url_basic_005.phpt | 40 ++++++++-------- .../tests/url/parse_url_basic_006.phpt | 40 ++++++++-------- .../tests/url/parse_url_basic_007.phpt | 40 ++++++++-------- .../tests/url/parse_url_basic_008.phpt | 40 ++++++++-------- .../tests/url/parse_url_basic_009.phpt | 40 ++++++++-------- .../tests/url/parse_url_unterminated.phpt | 46 +++++++++++-------- ext/standard/url.c | 5 ++ 12 files changed, 235 insertions(+), 184 deletions(-) diff --git a/ext/standard/tests/url/bug55399.phpt b/ext/standard/tests/url/bug55399.phpt index 619c08da6d048..f99ad445f4ff0 100644 --- a/ext/standard/tests/url/bug55399.phpt +++ b/ext/standard/tests/url/bug55399.phpt @@ -3,8 +3,12 @@ Bug #55399 (parse_url() incorrectly treats ':' as a valid path) --FILE-- getMessage(); +} ?> --EXPECT-- -bool(false) +Invalid path (:) diff --git a/ext/standard/tests/url/parse_url_basic_001.phpt b/ext/standard/tests/url/parse_url_basic_001.phpt index f3abd703b263c..729f07d24d3d6 100644 --- a/ext/standard/tests/url/parse_url_basic_001.phpt +++ b/ext/standard/tests/url/parse_url_basic_001.phpt @@ -9,7 +9,11 @@ include_once(__DIR__ . '/urls.inc'); foreach ($urls as $url) { echo "\n--> $url: "; - var_dump(parse_url($url)); + try { + var_dump(parse_url($url)); + } catch (ValueError $e) { + echo $e->getMessage() . "\n"; + } } echo "Done"; @@ -762,7 +766,7 @@ echo "Done"; string(9) "/blah.com" } ---> x://::abc/?: bool(false) +--> x://::abc/?: Invalid port (abc) --> http://::?: array(3) { ["scheme"]=> @@ -791,9 +795,9 @@ echo "Done"; int(6) } ---> http://?:/: bool(false) +--> http://?:/: Invalid host (?:/) ---> http://@?:/: bool(false) +--> http://@?:/: Invalid host (?:/) --> file:///:: array(2) { ["scheme"]=> @@ -884,31 +888,31 @@ echo "Done"; string(1) "/" } ---> http:///blah.com: bool(false) +--> http:///blah.com: Invalid host (/blah.com) ---> http://:80: bool(false) +--> http://:80: Invalid host (:80) ---> http://user@:80: bool(false) +--> http://user@:80: Invalid host (:80) ---> http://user:pass@:80: bool(false) +--> http://user:pass@:80: Invalid host (:80) ---> http://:: bool(false) +--> http://:: Invalid host (:) ---> http://@/: bool(false) +--> http://@/: Invalid host (/) ---> http://@:/: bool(false) +--> http://@:/: Invalid host (:/) ---> http://:/: bool(false) +--> http://:/: Invalid host (:/) ---> http://?: bool(false) +--> http://?: Invalid host (?) ---> http://#: bool(false) +--> http://#: Invalid host (#) ---> http://?:: bool(false) +--> http://?:: Invalid host (?:) ---> http://:?: bool(false) +--> http://:?: Invalid host (:?) ---> http://blah.com:123456: bool(false) +--> http://blah.com:123456: Invalid port (123456) ---> http://blah.com:abcdef: bool(false) +--> http://blah.com:abcdef: Invalid port (abcdef) Done diff --git a/ext/standard/tests/url/parse_url_basic_002.phpt b/ext/standard/tests/url/parse_url_basic_002.phpt index a9a0d5a602bb7..d42de875c1b72 100644 --- a/ext/standard/tests/url/parse_url_basic_002.phpt +++ b/ext/standard/tests/url/parse_url_basic_002.phpt @@ -9,7 +9,11 @@ include_once(__DIR__ . '/urls.inc'); foreach ($urls as $url) { echo "--> $url : "; - var_dump(parse_url($url, PHP_URL_SCHEME)); + try { + var_dump(parse_url($url, PHP_URL_SCHEME)); + } catch (ValueError $e) { + echo $e->getMessage() . "\n"; + } } @@ -89,12 +93,12 @@ echo "Done"; --> http://x:? : string(4) "http" --> x:blah.com : string(1) "x" --> x:/blah.com : string(1) "x" ---> x://::abc/? : bool(false) +--> x://::abc/? : Invalid port (abc) --> http://::? : string(4) "http" --> http://::# : string(4) "http" --> x://::6.5 : string(1) "x" ---> http://?:/ : bool(false) ---> http://@?:/ : bool(false) +--> http://?:/ : Invalid host (?:/) +--> http://@?:/ : Invalid host (?:/) --> file:///: : string(4) "file" --> file:///a:/ : string(4) "file" --> file:///ab:/ : string(4) "file" @@ -108,18 +112,18 @@ echo "Done"; --> /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) ---> http://user:pass@:80 : bool(false) ---> http://: : bool(false) ---> http://@/ : bool(false) ---> http://@:/ : bool(false) ---> http://:/ : bool(false) ---> http://? : bool(false) ---> http://# : bool(false) ---> http://?: : bool(false) ---> http://:? : bool(false) ---> http://blah.com:123456 : bool(false) ---> http://blah.com:abcdef : bool(false) +--> http:///blah.com : Invalid host (/blah.com) +--> http://:80 : Invalid host (:80) +--> http://user@:80 : Invalid host (:80) +--> http://user:pass@:80 : Invalid host (:80) +--> http://: : Invalid host (:) +--> http://@/ : Invalid host (/) +--> http://@:/ : Invalid host (:/) +--> http://:/ : Invalid host (:/) +--> http://? : Invalid host (?) +--> http://# : Invalid host (#) +--> http://?: : Invalid host (?:) +--> http://:? : Invalid host (:?) +--> http://blah.com:123456 : Invalid port (123456) +--> http://blah.com:abcdef : Invalid port (abcdef) Done diff --git a/ext/standard/tests/url/parse_url_basic_003.phpt b/ext/standard/tests/url/parse_url_basic_003.phpt index 1eb64d6a1b1c6..c9bb32c5482c6 100644 --- a/ext/standard/tests/url/parse_url_basic_003.phpt +++ b/ext/standard/tests/url/parse_url_basic_003.phpt @@ -9,7 +9,11 @@ include_once(__DIR__ . '/urls.inc'); foreach ($urls as $url) { echo "--> $url : "; - var_dump(parse_url($url, PHP_URL_HOST)); + try { + var_dump(parse_url($url, PHP_URL_HOST)); + } catch (ValueError $e) { + echo $e->getMessage() . "\n"; + } } echo "Done"; @@ -88,12 +92,12 @@ echo "Done"; --> http://x:? : string(1) "x" --> x:blah.com : NULL --> x:/blah.com : NULL ---> x://::abc/? : bool(false) +--> x://::abc/? : Invalid port (abc) --> http://::? : string(1) ":" --> http://::# : string(1) ":" --> x://::6.5 : string(1) ":" ---> http://?:/ : bool(false) ---> http://@?:/ : bool(false) +--> http://?:/ : Invalid host (?:/) +--> http://@?:/ : Invalid host (?:/) --> file:///: : NULL --> file:///a:/ : NULL --> file:///ab:/ : NULL @@ -107,18 +111,18 @@ echo "Done"; --> /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) ---> http://user:pass@:80 : bool(false) ---> http://: : bool(false) ---> http://@/ : bool(false) ---> http://@:/ : bool(false) ---> http://:/ : bool(false) ---> http://? : bool(false) ---> http://# : bool(false) ---> http://?: : bool(false) ---> http://:? : bool(false) ---> http://blah.com:123456 : bool(false) ---> http://blah.com:abcdef : bool(false) +--> http:///blah.com : Invalid host (/blah.com) +--> http://:80 : Invalid host (:80) +--> http://user@:80 : Invalid host (:80) +--> http://user:pass@:80 : Invalid host (:80) +--> http://: : Invalid host (:) +--> http://@/ : Invalid host (/) +--> http://@:/ : Invalid host (:/) +--> http://:/ : Invalid host (:/) +--> http://? : Invalid host (?) +--> http://# : Invalid host (#) +--> http://?: : Invalid host (?:) +--> http://:? : Invalid host (:?) +--> http://blah.com:123456 : Invalid port (123456) +--> http://blah.com:abcdef : Invalid port (abcdef) Done diff --git a/ext/standard/tests/url/parse_url_basic_004.phpt b/ext/standard/tests/url/parse_url_basic_004.phpt index c1c905185524f..8c025c5fc8619 100644 --- a/ext/standard/tests/url/parse_url_basic_004.phpt +++ b/ext/standard/tests/url/parse_url_basic_004.phpt @@ -9,7 +9,11 @@ include_once(__DIR__ . '/urls.inc'); foreach ($urls as $url) { echo "--> $url : "; - var_dump(parse_url($url, PHP_URL_PORT)); + try { + var_dump(parse_url($url, PHP_URL_PORT)); + } catch (ValueError $e) { + echo $e->getMessage() . "\n"; + } } echo "Done"; @@ -88,12 +92,12 @@ echo "Done"; --> http://x:? : NULL --> x:blah.com : NULL --> x:/blah.com : NULL ---> x://::abc/? : bool(false) +--> x://::abc/? : Invalid port (abc) --> http://::? : NULL --> http://::# : NULL --> x://::6.5 : int(6) ---> http://?:/ : bool(false) ---> http://@?:/ : bool(false) +--> http://?:/ : Invalid host (?:/) +--> http://@?:/ : Invalid host (?:/) --> file:///: : NULL --> file:///a:/ : NULL --> file:///ab:/ : NULL @@ -107,18 +111,18 @@ echo "Done"; --> /rest/Users?filter={"id":"123"} : NULL --> %:x : NULL --> https://example.com:0/ : int(0) ---> http:///blah.com : bool(false) ---> http://:80 : bool(false) ---> http://user@:80 : bool(false) ---> http://user:pass@:80 : bool(false) ---> http://: : bool(false) ---> http://@/ : bool(false) ---> http://@:/ : bool(false) ---> http://:/ : bool(false) ---> http://? : bool(false) ---> http://# : bool(false) ---> http://?: : bool(false) ---> http://:? : bool(false) ---> http://blah.com:123456 : bool(false) ---> http://blah.com:abcdef : bool(false) +--> http:///blah.com : Invalid host (/blah.com) +--> http://:80 : Invalid host (:80) +--> http://user@:80 : Invalid host (:80) +--> http://user:pass@:80 : Invalid host (:80) +--> http://: : Invalid host (:) +--> http://@/ : Invalid host (/) +--> http://@:/ : Invalid host (:/) +--> http://:/ : Invalid host (:/) +--> http://? : Invalid host (?) +--> http://# : Invalid host (#) +--> http://?: : Invalid host (?:) +--> http://:? : Invalid host (:?) +--> http://blah.com:123456 : Invalid port (123456) +--> http://blah.com:abcdef : Invalid port (abcdef) Done diff --git a/ext/standard/tests/url/parse_url_basic_005.phpt b/ext/standard/tests/url/parse_url_basic_005.phpt index dfbe7e7971e44..8c69db518d3a3 100644 --- a/ext/standard/tests/url/parse_url_basic_005.phpt +++ b/ext/standard/tests/url/parse_url_basic_005.phpt @@ -9,7 +9,11 @@ include_once(__DIR__ . '/urls.inc'); foreach ($urls as $url) { echo "--> $url : "; - var_dump(parse_url($url, PHP_URL_USER)); + try { + var_dump(parse_url($url, PHP_URL_USER)); + } catch (ValueError $e) { + echo $e->getMessage() . "\n"; + } } echo "Done"; @@ -88,12 +92,12 @@ echo "Done"; --> http://x:? : NULL --> x:blah.com : NULL --> x:/blah.com : NULL ---> x://::abc/? : bool(false) +--> x://::abc/? : Invalid port (abc) --> http://::? : NULL --> http://::# : NULL --> x://::6.5 : NULL ---> http://?:/ : bool(false) ---> http://@?:/ : bool(false) +--> http://?:/ : Invalid host (?:/) +--> http://@?:/ : Invalid host (?:/) --> file:///: : NULL --> file:///a:/ : NULL --> file:///ab:/ : NULL @@ -107,18 +111,18 @@ echo "Done"; --> /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) ---> http://user:pass@:80 : bool(false) ---> http://: : bool(false) ---> http://@/ : bool(false) ---> http://@:/ : bool(false) ---> http://:/ : bool(false) ---> http://? : bool(false) ---> http://# : bool(false) ---> http://?: : bool(false) ---> http://:? : bool(false) ---> http://blah.com:123456 : bool(false) ---> http://blah.com:abcdef : bool(false) +--> http:///blah.com : Invalid host (/blah.com) +--> http://:80 : Invalid host (:80) +--> http://user@:80 : Invalid host (:80) +--> http://user:pass@:80 : Invalid host (:80) +--> http://: : Invalid host (:) +--> http://@/ : Invalid host (/) +--> http://@:/ : Invalid host (:/) +--> http://:/ : Invalid host (:/) +--> http://? : Invalid host (?) +--> http://# : Invalid host (#) +--> http://?: : Invalid host (?:) +--> http://:? : Invalid host (:?) +--> http://blah.com:123456 : Invalid port (123456) +--> http://blah.com:abcdef : Invalid port (abcdef) Done diff --git a/ext/standard/tests/url/parse_url_basic_006.phpt b/ext/standard/tests/url/parse_url_basic_006.phpt index 49f139f1454f7..7044248527e30 100644 --- a/ext/standard/tests/url/parse_url_basic_006.phpt +++ b/ext/standard/tests/url/parse_url_basic_006.phpt @@ -9,7 +9,11 @@ include_once(__DIR__ . '/urls.inc'); foreach ($urls as $url) { echo "--> $url : "; - var_dump(parse_url($url, PHP_URL_PASS)); + try { + var_dump(parse_url($url, PHP_URL_PASS)); + } catch (ValueError $e) { + echo $e->getMessage() . "\n"; + } } echo "Done"; @@ -88,12 +92,12 @@ echo "Done"; --> http://x:? : NULL --> x:blah.com : NULL --> x:/blah.com : NULL ---> x://::abc/? : bool(false) +--> x://::abc/? : Invalid port (abc) --> http://::? : NULL --> http://::# : NULL --> x://::6.5 : NULL ---> http://?:/ : bool(false) ---> http://@?:/ : bool(false) +--> http://?:/ : Invalid host (?:/) +--> http://@?:/ : Invalid host (?:/) --> file:///: : NULL --> file:///a:/ : NULL --> file:///ab:/ : NULL @@ -107,18 +111,18 @@ echo "Done"; --> /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) ---> http://user:pass@:80 : bool(false) ---> http://: : bool(false) ---> http://@/ : bool(false) ---> http://@:/ : bool(false) ---> http://:/ : bool(false) ---> http://? : bool(false) ---> http://# : bool(false) ---> http://?: : bool(false) ---> http://:? : bool(false) ---> http://blah.com:123456 : bool(false) ---> http://blah.com:abcdef : bool(false) +--> http:///blah.com : Invalid host (/blah.com) +--> http://:80 : Invalid host (:80) +--> http://user@:80 : Invalid host (:80) +--> http://user:pass@:80 : Invalid host (:80) +--> http://: : Invalid host (:) +--> http://@/ : Invalid host (/) +--> http://@:/ : Invalid host (:/) +--> http://:/ : Invalid host (:/) +--> http://? : Invalid host (?) +--> http://# : Invalid host (#) +--> http://?: : Invalid host (?:) +--> http://:? : Invalid host (:?) +--> http://blah.com:123456 : Invalid port (123456) +--> http://blah.com:abcdef : Invalid port (abcdef) Done diff --git a/ext/standard/tests/url/parse_url_basic_007.phpt b/ext/standard/tests/url/parse_url_basic_007.phpt index 8d7de1d0fb8a2..0a29b5619aebe 100644 --- a/ext/standard/tests/url/parse_url_basic_007.phpt +++ b/ext/standard/tests/url/parse_url_basic_007.phpt @@ -9,7 +9,11 @@ include_once(__DIR__ . '/urls.inc'); foreach ($urls as $url) { echo "--> $url : "; - var_dump(parse_url($url, PHP_URL_PATH)); + try { + var_dump(parse_url($url, PHP_URL_PATH)); + } catch (ValueError $e) { + echo $e->getMessage() . "\n"; + } } echo "Done"; @@ -88,12 +92,12 @@ echo "Done"; --> http://x:? : NULL --> x:blah.com : string(8) "blah.com" --> x:/blah.com : string(9) "/blah.com" ---> x://::abc/? : bool(false) +--> x://::abc/? : Invalid port (abc) --> http://::? : NULL --> http://::# : NULL --> x://::6.5 : NULL ---> http://?:/ : bool(false) ---> http://@?:/ : bool(false) +--> http://?:/ : Invalid host (?:/) +--> http://@?:/ : Invalid host (?:/) --> file:///: : string(2) "/:" --> file:///a:/ : string(3) "a:/" --> file:///ab:/ : string(5) "/ab:/" @@ -107,18 +111,18 @@ echo "Done"; --> /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) ---> http://user:pass@:80 : bool(false) ---> http://: : bool(false) ---> http://@/ : bool(false) ---> http://@:/ : bool(false) ---> http://:/ : bool(false) ---> http://? : bool(false) ---> http://# : bool(false) ---> http://?: : bool(false) ---> http://:? : bool(false) ---> http://blah.com:123456 : bool(false) ---> http://blah.com:abcdef : bool(false) +--> http:///blah.com : Invalid host (/blah.com) +--> http://:80 : Invalid host (:80) +--> http://user@:80 : Invalid host (:80) +--> http://user:pass@:80 : Invalid host (:80) +--> http://: : Invalid host (:) +--> http://@/ : Invalid host (/) +--> http://@:/ : Invalid host (:/) +--> http://:/ : Invalid host (:/) +--> http://? : Invalid host (?) +--> http://# : Invalid host (#) +--> http://?: : Invalid host (?:) +--> http://:? : Invalid host (:?) +--> http://blah.com:123456 : Invalid port (123456) +--> http://blah.com:abcdef : Invalid port (abcdef) Done diff --git a/ext/standard/tests/url/parse_url_basic_008.phpt b/ext/standard/tests/url/parse_url_basic_008.phpt index 9080523f502fd..7a4b9a1f24300 100644 --- a/ext/standard/tests/url/parse_url_basic_008.phpt +++ b/ext/standard/tests/url/parse_url_basic_008.phpt @@ -9,7 +9,11 @@ include_once(__DIR__ . '/urls.inc'); foreach ($urls as $url) { echo "--> $url : "; - var_dump(parse_url($url, PHP_URL_QUERY)); + try { + var_dump(parse_url($url, PHP_URL_QUERY)); + } catch (ValueError $e) { + echo $e->getMessage() . "\n"; + } } echo "Done"; @@ -88,12 +92,12 @@ echo "Done"; --> http://x:? : string(0) "" --> x:blah.com : NULL --> x:/blah.com : NULL ---> x://::abc/? : bool(false) +--> x://::abc/? : Invalid port (abc) --> http://::? : string(0) "" --> http://::# : NULL --> x://::6.5 : NULL ---> http://?:/ : bool(false) ---> http://@?:/ : bool(false) +--> http://?:/ : Invalid host (?:/) +--> http://@?:/ : Invalid host (?:/) --> file:///: : NULL --> file:///a:/ : NULL --> file:///ab:/ : NULL @@ -107,18 +111,18 @@ echo "Done"; --> /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) ---> http://user:pass@:80 : bool(false) ---> http://: : bool(false) ---> http://@/ : bool(false) ---> http://@:/ : bool(false) ---> http://:/ : bool(false) ---> http://? : bool(false) ---> http://# : bool(false) ---> http://?: : bool(false) ---> http://:? : bool(false) ---> http://blah.com:123456 : bool(false) ---> http://blah.com:abcdef : bool(false) +--> http:///blah.com : Invalid host (/blah.com) +--> http://:80 : Invalid host (:80) +--> http://user@:80 : Invalid host (:80) +--> http://user:pass@:80 : Invalid host (:80) +--> http://: : Invalid host (:) +--> http://@/ : Invalid host (/) +--> http://@:/ : Invalid host (:/) +--> http://:/ : Invalid host (:/) +--> http://? : Invalid host (?) +--> http://# : Invalid host (#) +--> http://?: : Invalid host (?:) +--> http://:? : Invalid host (:?) +--> http://blah.com:123456 : Invalid port (123456) +--> http://blah.com:abcdef : Invalid port (abcdef) Done diff --git a/ext/standard/tests/url/parse_url_basic_009.phpt b/ext/standard/tests/url/parse_url_basic_009.phpt index e37dee6dacf0d..1a9e5d3ac6321 100644 --- a/ext/standard/tests/url/parse_url_basic_009.phpt +++ b/ext/standard/tests/url/parse_url_basic_009.phpt @@ -9,7 +9,11 @@ include_once(__DIR__ . '/urls.inc'); foreach ($urls as $url) { echo "--> $url : "; - var_dump(parse_url($url, PHP_URL_FRAGMENT)); + try { + var_dump(parse_url($url, PHP_URL_FRAGMENT)); + } catch (ValueError $e) { + echo $e->getMessage() . "\n"; + } } echo "Done"; @@ -88,12 +92,12 @@ echo "Done"; --> http://x:? : NULL --> x:blah.com : NULL --> x:/blah.com : NULL ---> x://::abc/? : bool(false) +--> x://::abc/? : Invalid port (abc) --> http://::? : NULL --> http://::# : string(0) "" --> x://::6.5 : NULL ---> http://?:/ : bool(false) ---> http://@?:/ : bool(false) +--> http://?:/ : Invalid host (?:/) +--> http://@?:/ : Invalid host (?:/) --> file:///: : NULL --> file:///a:/ : NULL --> file:///ab:/ : NULL @@ -107,18 +111,18 @@ echo "Done"; --> /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) ---> http://user:pass@:80 : bool(false) ---> http://: : bool(false) ---> http://@/ : bool(false) ---> http://@:/ : bool(false) ---> http://:/ : bool(false) ---> http://? : bool(false) ---> http://# : bool(false) ---> http://?: : bool(false) ---> http://:? : bool(false) ---> http://blah.com:123456 : bool(false) ---> http://blah.com:abcdef : bool(false) +--> http:///blah.com : Invalid host (/blah.com) +--> http://:80 : Invalid host (:80) +--> http://user@:80 : Invalid host (:80) +--> http://user:pass@:80 : Invalid host (:80) +--> http://: : Invalid host (:) +--> http://@/ : Invalid host (/) +--> http://@:/ : Invalid host (:/) +--> http://:/ : Invalid host (:/) +--> http://? : Invalid host (?) +--> http://# : Invalid host (#) +--> http://?: : Invalid host (?:) +--> http://:? : Invalid host (:?) +--> http://blah.com:123456 : Invalid port (123456) +--> http://blah.com:abcdef : Invalid port (abcdef) Done diff --git a/ext/standard/tests/url/parse_url_unterminated.phpt b/ext/standard/tests/url/parse_url_unterminated.phpt index 10867832a6a8f..62fda91ff7e7b 100644 --- a/ext/standard/tests/url/parse_url_unterminated.phpt +++ b/ext/standard/tests/url/parse_url_unterminated.phpt @@ -14,13 +14,18 @@ include_once(__DIR__ . '/urls.inc'); foreach ($urls as $url) { echo "\n--> $url: "; $str = zend_create_unterminated_string($url); - var_dump(parse_url($str)); - zend_terminate_string($str); + try { + var_dump(parse_url($str)); + } catch (ValueError $e) { + echo $e->getMessage() . "\n"; + } finally { + zend_terminate_string($str); + } } echo "Done"; ?> ---EXPECT-- +--EXPECTF-- --> 64.246.30.37: array(1) { ["path"]=> string(12) "64.246.30.37" @@ -768,7 +773,7 @@ echo "Done"; string(9) "/blah.com" } ---> x://::abc/?: bool(false) +--> x://::abc/?: Invalid port (abc) --> http://::?: array(3) { ["scheme"]=> @@ -797,9 +802,9 @@ echo "Done"; int(6) } ---> http://?:/: bool(false) +--> http://?:/: Invalid host (?:/) ---> http://@?:/: bool(false) +--> http://@?:/: Invalid host (?:/) --> file:///:: array(2) { ["scheme"]=> @@ -890,31 +895,32 @@ echo "Done"; string(1) "/" } ---> http:///blah.com: bool(false) +--> http:///blah.com: Invalid host (%s) ---> http://:80: bool(false) +--> http://:80: Invalid host (%s) ---> http://user@:80: bool(false) +--> http://user@:80: Invalid host (%s) ---> http://user:pass@:80: bool(false) +--> http://user:pass@:80: Invalid host (%s) ---> http://:: bool(false) +--> http://:: Invalid host (%s) ---> http://@/: bool(false) +--> http://@/: Invalid host (%s) ---> http://@:/: bool(false) +--> http://@:/: Invalid host (%s) ---> http://:/: bool(false) +--> http://:/: Invalid host (%s) ---> http://?: bool(false) +--> http://?: Invalid host (%s) ---> http://#: bool(false) +--> http://#: Invalid host (%s) ---> http://?:: bool(false) +--> http://?:: Invalid host (%s) ---> http://:?: bool(false) +--> http://:?: Invalid host (%s) ---> http://blah.com:123456: bool(false) +--> http://blah.com:123456: Invalid port (%s) ---> http://blah.com:abcdef: bool(false) +--> http://blah.com:abcdef: Invalid port (%s +) Done diff --git a/ext/standard/url.c b/ext/standard/url.c index e3d95768fb019..5338075197145 100644 --- a/ext/standard/url.c +++ b/ext/standard/url.c @@ -203,10 +203,12 @@ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port s += 2; } } else { + zend_value_error("Invalid port (%s)", port_buf); php_url_free(ret); return NULL; } } else if (p == pp && pp == ue) { + zend_value_error("Invalid path (%s)", str); php_url_free(ret); return NULL; } else if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */ @@ -254,6 +256,7 @@ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port if (!ret->port) { p++; if (e-p > 5) { /* port cannot be longer then 5 characters */ + zend_value_error("Invalid port (%s)", p); php_url_free(ret); return NULL; } else if (e - p > 0) { @@ -266,6 +269,7 @@ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port *has_port = 1; ret->port = (unsigned short)port; } else { + zend_value_error("Invalid port (%s)", port_buf); php_url_free(ret); return NULL; } @@ -278,6 +282,7 @@ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port /* check if we have a valid host, if we don't reject the string as url */ if ((p-s) < 1) { + zend_value_error("Invalid host (%s)", s); php_url_free(ret); return NULL; } From d8e4aa3d5dcaeab3eeea38ab2ae4078ac8dd4d9e Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 28 Jan 2023 15:17:58 +0000 Subject: [PATCH 2/2] introduce strict mode --- ext/standard/basic_functions.stub.php | 2 +- ext/standard/basic_functions_arginfo.h | 3 +- ext/standard/ftp_fopen_wrapper.c | 6 +-- ext/standard/http_fopen_wrapper.c | 4 +- .../tests/url/parse_url_unterminated.phpt | 46 ++++++++----------- ext/standard/url.c | 38 +++++++++++---- ext/standard/url.h | 3 +- 7 files changed, 59 insertions(+), 43 deletions(-) diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index ab56a8c0e8fbb..98e06a3cbfbdd 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -3418,7 +3418,7 @@ function uniqid(string $prefix = "", bool $more_entropy = false): string {} * @return int|string|array|null|false * @refcount 1 */ -function parse_url(string $url, int $component = -1): int|string|array|null|false {} +function parse_url(string $url, int $component = -1, bool $strict = true): int|string|array|null|false {} /** * @compile-time-eval diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 077f9876df7c2..1ad5d674986aa 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 39d455982dfdea9d0b9b646bc207b05f7108d1b2 */ + * Stub hash: b0cb43b960eb4e957a0f4c9253c0bfce602e517d */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -2087,6 +2087,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_parse_url, 0, 1, MAY_BE_LONG|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, url, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, component, IS_LONG, 0, "-1") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, strict, _IS_BOOL, 0, "true") ZEND_END_ARG_INFO() #define arginfo_urlencode arginfo_base64_encode diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c index 0be729a59fddb..b5cf49f9ba475 100644 --- a/ext/standard/ftp_fopen_wrapper.c +++ b/ext/standard/ftp_fopen_wrapper.c @@ -133,7 +133,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char char *transport; int transport_len; - resource = php_url_parse(path); + resource = php_url_parse_ex(path, strlen(path)); if (resource == NULL || resource->path == NULL) { if (resource && presource) { *presource = resource; @@ -949,8 +949,8 @@ static int php_stream_ftp_rename(php_stream_wrapper *wrapper, const char *url_fr int result; char tmp_line[512]; - resource_from = php_url_parse(url_from); - resource_to = php_url_parse(url_to); + resource_from = php_url_parse_ex(url_from, strlen(url_from)); + resource_to = php_url_parse_ex(url_to, strlen(url_to)); /* Must be same scheme (ftp/ftp or ftps/ftps), same host, and same port (or a 21/0 0/21 combination which is also "same") Also require paths to/from */ diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index be0ee30b7d832..2e5d3a9adb374 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -153,7 +153,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, return NULL; } - resource = php_url_parse(path); + resource = php_url_parse_ex(path, strlen(path)); if (resource == NULL) { return NULL; } @@ -888,7 +888,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, php_url_free(resource); /* check for invalid redirection URLs */ - if ((resource = php_url_parse(new_path)) == NULL) { + if ((resource = php_url_parse_ex(new_path, strlen(new_path))) == NULL) { php_stream_wrapper_log_error(wrapper, options, "Invalid redirect URL! %s", new_path); goto out; } diff --git a/ext/standard/tests/url/parse_url_unterminated.phpt b/ext/standard/tests/url/parse_url_unterminated.phpt index 62fda91ff7e7b..387f32d5c9958 100644 --- a/ext/standard/tests/url/parse_url_unterminated.phpt +++ b/ext/standard/tests/url/parse_url_unterminated.phpt @@ -14,18 +14,13 @@ include_once(__DIR__ . '/urls.inc'); foreach ($urls as $url) { echo "\n--> $url: "; $str = zend_create_unterminated_string($url); - try { - var_dump(parse_url($str)); - } catch (ValueError $e) { - echo $e->getMessage() . "\n"; - } finally { - zend_terminate_string($str); - } + var_dump(parse_url($str, strict: false)); + zend_terminate_string($str); } echo "Done"; ?> ---EXPECTF-- +--EXPECT-- --> 64.246.30.37: array(1) { ["path"]=> string(12) "64.246.30.37" @@ -773,7 +768,7 @@ echo "Done"; string(9) "/blah.com" } ---> x://::abc/?: Invalid port (abc) +--> x://::abc/?: bool(false) --> http://::?: array(3) { ["scheme"]=> @@ -802,9 +797,9 @@ echo "Done"; int(6) } ---> http://?:/: Invalid host (?:/) +--> http://?:/: bool(false) ---> http://@?:/: Invalid host (?:/) +--> http://@?:/: bool(false) --> file:///:: array(2) { ["scheme"]=> @@ -895,32 +890,31 @@ echo "Done"; string(1) "/" } ---> http:///blah.com: Invalid host (%s) +--> http:///blah.com: bool(false) ---> http://:80: Invalid host (%s) +--> http://:80: bool(false) ---> http://user@:80: Invalid host (%s) +--> http://user@:80: bool(false) ---> http://user:pass@:80: Invalid host (%s) +--> http://user:pass@:80: bool(false) ---> http://:: Invalid host (%s) +--> http://:: bool(false) ---> http://@/: Invalid host (%s) +--> http://@/: bool(false) ---> http://@:/: Invalid host (%s) +--> http://@:/: bool(false) ---> http://:/: Invalid host (%s) +--> http://:/: bool(false) ---> http://?: Invalid host (%s) +--> http://?: bool(false) ---> http://#: Invalid host (%s) +--> http://#: bool(false) ---> http://?:: Invalid host (%s) +--> http://?:: bool(false) ---> http://:?: Invalid host (%s) +--> http://:?: bool(false) ---> http://blah.com:123456: Invalid port (%s) +--> http://blah.com:123456: bool(false) ---> http://blah.com:abcdef: Invalid port (%s -) +--> http://blah.com:abcdef: bool(false) Done diff --git a/ext/standard/url.c b/ext/standard/url.c index 5338075197145..bc13586caf189 100644 --- a/ext/standard/url.c +++ b/ext/standard/url.c @@ -102,6 +102,11 @@ PHPAPI php_url *php_url_parse_ex(char const *str, size_t length) /* {{{ php_url_parse_ex2 */ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port) +{ + return php_url_parse_ex3(str, length, false, has_port); +} + +PHPAPI php_url *php_url_parse_ex3(char const *str, size_t length, bool strict, bool *has_port) { char port_buf[6]; php_url *ret = ecalloc(1, sizeof(php_url)); @@ -203,12 +208,16 @@ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port s += 2; } } else { - zend_value_error("Invalid port (%s)", port_buf); + if (strict) { + zend_value_error("Invalid port (%s)", port_buf); + } php_url_free(ret); return NULL; } } else if (p == pp && pp == ue) { - zend_value_error("Invalid path (%s)", str); + if (strict) { + zend_value_error("Invalid path (%s)", str); + } php_url_free(ret); return NULL; } else if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */ @@ -256,7 +265,9 @@ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port if (!ret->port) { p++; if (e-p > 5) { /* port cannot be longer then 5 characters */ - zend_value_error("Invalid port (%s)", p); + if (strict) { + zend_value_error("Invalid port (%s)", p); + } php_url_free(ret); return NULL; } else if (e - p > 0) { @@ -269,7 +280,9 @@ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port *has_port = 1; ret->port = (unsigned short)port; } else { - zend_value_error("Invalid port (%s)", port_buf); + if (strict) { + zend_value_error("Invalid port (%s)", port_buf); + } php_url_free(ret); return NULL; } @@ -282,7 +295,9 @@ PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, bool *has_port /* check if we have a valid host, if we don't reject the string as url */ if ((p-s) < 1) { - zend_value_error("Invalid host (%s)", s); + if (strict) { + zend_value_error("Invalid host (%s)", s); + } php_url_free(ret); return NULL; } @@ -340,18 +355,23 @@ PHP_FUNCTION(parse_url) php_url *resource; zend_long key = -1; zval tmp; - bool has_port; + bool has_port, strict = true; - ZEND_PARSE_PARAMETERS_START(1, 2) + ZEND_PARSE_PARAMETERS_START(1, 3) Z_PARAM_STRING(str, str_len) Z_PARAM_OPTIONAL Z_PARAM_LONG(key) + Z_PARAM_BOOL(strict) ZEND_PARSE_PARAMETERS_END(); - resource = php_url_parse_ex2(str, str_len, &has_port); + resource = php_url_parse_ex3(str, str_len, strict, &has_port); if (resource == NULL) { /* @todo Find a method to determine why php_url_parse_ex() failed */ - RETURN_FALSE; + if (strict) { + RETURN_THROWS(); + } else { + RETURN_FALSE; + } } if (key > -1) { diff --git a/ext/standard/url.h b/ext/standard/url.h index 5ce9e756eef06..4d330912824c0 100644 --- a/ext/standard/url.h +++ b/ext/standard/url.h @@ -29,9 +29,10 @@ typedef struct php_url { } php_url; PHPAPI void php_url_free(php_url *theurl); -PHPAPI php_url *php_url_parse(char const *str); +PHPAPI ZEND_ATTRIBUTE_DEPRECATED 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, bool *has_port); +PHPAPI php_url *php_url_parse_ex3(char const *str, size_t length, bool strict, 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);