1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

uri: Use the “includes credentials” rule for WhatWg user/password getters (#20303)

* uri: Use the “includes credentials” rule for WhatWg user/password getters

The URL serializing algorithm from the WHATWG URL Standard uses an “includes
credentials” rule to decide whether or not to include the `@` in the output,
indicating the presence of a userinfo component in RFC 3986 terminology. Use
this rule to determine whether or not an empty username or password should be
returned as the empty string (present but empty) or NULL (not present).

* uri: Use ZVAL_STRINGL_FAST in `whatwg_(username|password)_read()`

This nicely sidesteps the undefined behavior with passing a `(NULL, 0)` pair
without needing manual logic.

* NEWS
This commit is contained in:
Tim Düsterhus
2025-11-01 14:15:06 +01:00
committed by GitHub
parent cda8daaccf
commit 81f6ba5503
8 changed files with 59 additions and 10 deletions

5
NEWS
View File

@@ -28,6 +28,11 @@ PHP NEWS
. Fixed bug GH-19798: XP_SOCKET XP_SSL (Socket stream modules): Incorrect
condition for Win32/Win64. (Jakub Zelenka)
- URI:
. Use the "includes credentials" rule of the WHATWG URL Standard to
decide whether Uri\WhatWg\Url::getUsername() and ::getPassword()
getters should return null or an empty string. (timwolla)
- Zip:
. Fixed missing zend_release_fcall_info_cache on the following methods
ZipArchive::registerProgressCallback() and ZipArchive::registerCancelCallback()

View File

@@ -15,5 +15,5 @@ var_dump($url2->toAsciiString());
?>
--EXPECT--
string(8) "password"
NULL
string(0) ""
string(29) "https://username@example.com/"

View File

@@ -0,0 +1,19 @@
--TEST--
Test Uri\WhatWg\Url component modification - password - unsetting existing
--EXTENSIONS--
uri
--FILE--
<?php
$url1 = Uri\WhatWg\Url::parse("https://:password@example.com");
$url2 = $url1->withPassword(null);
var_dump($url1->getPassword());
var_dump($url2->getPassword());
var_dump($url2->toAsciiString());
?>
--EXPECT--
string(8) "password"
NULL
string(20) "https://example.com/"

View File

@@ -14,6 +14,6 @@ var_dump($url2->toAsciiString());
?>
--EXPECT--
NULL
NULL
string(0) ""
string(0) ""
string(29) "https://username@example.com/"

View File

@@ -15,5 +15,5 @@ var_dump($url2->toAsciiString());
?>
--EXPECT--
string(8) "username"
NULL
string(0) ""
string(30) "https://:password@example.com/"

View File

@@ -0,0 +1,19 @@
--TEST--
Test Uri\WhatWg\Url component modification - username - unsetting existing
--EXTENSIONS--
uri
--FILE--
<?php
$url1 = Uri\WhatWg\Url::parse("https://username:@example.com");
$url2 = $url1->withUsername(null);
var_dump($url1->getUsername());
var_dump($url2->getUsername());
var_dump($url2->toAsciiString());
?>
--EXPECT--
string(8) "username"
NULL
string(20) "https://example.com/"

View File

@@ -14,6 +14,6 @@ var_dump($url2->toAsciiString());
?>
--EXPECT--
NULL
NULL
string(0) ""
string(0) ""
string(30) "https://:password@example.com/"

View File

@@ -274,12 +274,18 @@ static zend_result php_uri_parser_whatwg_scheme_write(void *uri, zval *value, zv
return SUCCESS;
}
/* 4.2. URL miscellaneous: A URL includes credentials if its username or password is not the empty string. */
static bool includes_credentials(const lxb_url_t *lexbor_uri)
{
return lexbor_uri->username.length > 0 || lexbor_uri->password.length > 0;
}
static zend_result php_uri_parser_whatwg_username_read(void *uri, php_uri_component_read_mode read_mode, zval *retval)
{
const lxb_url_t *lexbor_uri = uri;
if (lexbor_uri->username.length) {
ZVAL_STRINGL(retval, (const char *) lexbor_uri->username.data, lexbor_uri->username.length);
if (includes_credentials(lexbor_uri)) {
ZVAL_STRINGL_FAST(retval, (const char *) lexbor_uri->username.data, lexbor_uri->username.length);
} else {
ZVAL_NULL(retval);
}
@@ -307,8 +313,8 @@ static zend_result php_uri_parser_whatwg_password_read(void *uri, php_uri_compon
{
const lxb_url_t *lexbor_uri = uri;
if (lexbor_uri->password.length > 0) {
ZVAL_STRINGL(retval, (const char *) lexbor_uri->password.data, lexbor_uri->password.length);
if (includes_credentials(lexbor_uri)) {
ZVAL_STRINGL_FAST(retval, (const char *) lexbor_uri->password.data, lexbor_uri->password.length);
} else {
ZVAL_NULL(retval);
}