Skip to content

Commit

Permalink
URL-encodes the userInfo component of an URI (#253)
Browse files Browse the repository at this point in the history
* Fixes issue #252

* Adds a unit test for special chars in the `userInfo` component

* Corrections following the code review

* Fixes the `Uri::applyParts` method
  • Loading branch information
cedx authored and Tobion committed Dec 28, 2018
1 parent 5e61346 commit ae7949e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 5 deletions.
32 changes: 27 additions & 5 deletions src/Uri.php
Expand Up @@ -437,9 +437,9 @@ public function withScheme($scheme)

public function withUserInfo($user, $password = null)
{
$info = $user;
if ($password != '') {
$info .= ':' . $password;
$info = $this->filterUserInfoComponent($user);
if ($password !== null) {
$info .= ':' . $this->filterUserInfoComponent($password);
}

if ($this->userInfo === $info) {
Expand Down Expand Up @@ -537,7 +537,9 @@ private function applyParts(array $parts)
$this->scheme = isset($parts['scheme'])
? $this->filterScheme($parts['scheme'])
: '';
$this->userInfo = isset($parts['user']) ? $parts['user'] : '';
$this->userInfo = isset($parts['user'])
? $this->filterUserInfoComponent($parts['user'])
: '';
$this->host = isset($parts['host'])
? $this->filterHost($parts['host'])
: '';
Expand All @@ -554,7 +556,7 @@ private function applyParts(array $parts)
? $this->filterQueryAndFragment($parts['fragment'])
: '';
if (isset($parts['pass'])) {
$this->userInfo .= ':' . $parts['pass'];
$this->userInfo .= ':' . $this->filterUserInfoComponent($parts['pass']);
}

$this->removeDefaultPort();
Expand All @@ -576,6 +578,26 @@ private function filterScheme($scheme)
return strtolower($scheme);
}

/**
* @param string $component
*
* @return string
*
* @throws \InvalidArgumentException If the user info is invalid.
*/
private function filterUserInfoComponent($component)
{
if (!is_string($component)) {
throw new \InvalidArgumentException('User info must be a string');
}

return preg_replace_callback(
'/(?:[^%' . self::$charUnreserved . self::$charSubDelims . ']+|%(?![A-Fa-f0-9]{2}))/',
[$this, 'rawurlencodeMatchZero'],
$component
);
}

/**
* @param string $host
*
Expand Down
11 changes: 11 additions & 0 deletions tests/UriTest.php
Expand Up @@ -680,6 +680,17 @@ public function testExtendingClassesInstantiates()
new ExtendedUriTest('http://h:9/')
);
}

public function testSpecialCharsOfUserInfo()
{
// The `userInfo` must always be URL-encoded.
$uri = (new Uri)->withUserInfo('foo@bar.com', 'pass#word');
$this->assertSame('foo%40bar.com:pass%23word', $uri->getUserInfo());

// The `userInfo` can already be URL-encoded: it should not be encoded twice.
$uri = (new Uri)->withUserInfo('foo%40bar.com', 'pass%23word');
$this->assertSame('foo%40bar.com:pass%23word', $uri->getUserInfo());
}
}

class ExtendedUriTest extends Uri
Expand Down

0 comments on commit ae7949e

Please sign in to comment.