diff --git a/packages/uri/src/Uri.php b/packages/uri/src/Uri.php index df6dff65e..c0c4f2b8d 100644 --- a/packages/uri/src/Uri.php +++ b/packages/uri/src/Uri.php @@ -585,7 +585,7 @@ public function withPathAppend(string $suffix): static { $new = clone $this; - $new->path .= $suffix; + $new->path = UriHelper::filterPath($new->path . $suffix); return $new; } @@ -619,8 +619,9 @@ public function toString(int $parts = self::ALL): string $uri = ($parts & static::SCHEME) ? (!empty($this->scheme) ? $this->scheme . '://' : '') : ''; $uri .= ($parts & static::USER) ? $this->user : ''; $uri .= ($parts & static::PASSWORD) - ? (!empty($this->pass) ? ':' : '') . $this->pass . (!empty($this->user) ? '@' : '') + ? (!empty($this->pass) ? ':' : '') . $this->pass : ''; + $uri .= ($parts & static::USER_INFO) && !empty($this->user) ? '@' : ''; $uri .= ($parts & static::HOST) ? $this->host : ''; $uri .= ($parts & static::PORT) ? (!empty($this->port) ? ':' : '') . $this->port : ''; diff --git a/packages/uri/test/UriTest.php b/packages/uri/test/UriTest.php index d4a2ed657..88e43547b 100644 --- a/packages/uri/test/UriTest.php +++ b/packages/uri/test/UriTest.php @@ -150,6 +150,16 @@ public function withPathDoesNotDoubleEncodePath(): void self::assertEquals($expected, $uri->getPath()); } + #[Test] + public function withPathAppendEncodesSpecialCharactersWithoutDoubleEncoding(): void + { + $uri = new Uri('http://example.com/foo'); + $uri = $uri->withPathAppend('/bar^baz'); + + self::assertSame('/foo/bar%5Ebaz', $uri->getPath()); + self::assertSame('/foo/bar%5Ebaz/%5E', $uri->withPathAppend('/%5E')->getPath()); + } + #[Test] public function withQueryReplacesQuery() { @@ -367,6 +377,18 @@ public function toStringRendersSelectedParts() ); } + #[Test] + public function toStringKeepsUserInfoDelimiterWhenPasswordIsOmitted(): void + { + $uri = new Uri('https://example.com/foo'); + $uri = $uri->withUserInfo('admin', 'pw'); + + self::assertSame( + 'https://admin@example.com/foo', + $uri->toString(Uri::ALL & ~Uri::PASSWORD) + ); + } + #[Test] public function withVarSetsQueryVariable() {