Skip to content

Commit

Permalink
Drop PSR7 v1 and redact URI user info in errors (#3236)
Browse files Browse the repository at this point in the history
* Redact URI user info in errors

Co-Authored-By: Tim Düsterhus <209270+TimWolla@users.noreply.github.com>

* guzzlehttp/psr7 `^2.7`

* Update CurlFactory.php

* Fizes

* Update CurlFactory.php

* Update CurlFactory.php

* Update CurlFactory.php

---------

Co-authored-by: Tim Düsterhus <209270+TimWolla@users.noreply.github.com>
  • Loading branch information
GrahamCampbell and TimWolla authored Jul 18, 2024
1 parent 740e191 commit 3bec073
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 38 deletions.
13 changes: 2 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,10 @@ jobs:
max-parallel: 10
matrix:
php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4']
psr7: ['^1.9.1', '^2.6.3']
psr7: ['^2.7.0']
include:
- php: '8.4'
psr7: '^2.6.3@dev'
exclude:
- php: '8.1'
psr7: '^1.9.1'
- php: '8.2'
psr7: '^1.9.1'
- php: '8.3'
psr7: '^1.9.1'
- php: '8.4'
psr7: '^1.9.1'
psr7: '^2.7.0@dev'

steps:
- name: Set up PHP
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"php": "^7.2.5 || ^8.0",
"ext-json": "*",
"guzzlehttp/promises": "^1.5.3 || ^2.0.3",
"guzzlehttp/psr7": "^1.9.1 || ^2.6.3",
"guzzlehttp/psr7": "^2.7.0",
"psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
},
Expand Down
5 changes: 0 additions & 5 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ parameters:
count: 3
path: src/Cookie/SetCookie.php

-
message: "#^Unsafe call to private method GuzzleHttp\\\\Exception\\\\RequestException\\:\\:obfuscateUri\\(\\) through static\\:\\:\\.$#"
count: 1
path: src/Exception/RequestException.php

-
message: "#^Cannot access offset 'features' on array\\|false\\.$#"
count: 3
Expand Down
18 changes: 1 addition & 17 deletions src/Exception/RequestException.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Psr\Http\Client\RequestExceptionInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;

/**
* HTTP Request exception
Expand Down Expand Up @@ -90,8 +89,7 @@ public static function create(
$className = __CLASS__;
}

$uri = $request->getUri();
$uri = static::obfuscateUri($uri);
$uri = \GuzzleHttp\Psr7\Utils::redactUserInfo($request->getUri());

// Client Error: `GET /` resulted in a `404 Not Found` response:
// <html> ... (truncated)
Expand All @@ -113,20 +111,6 @@ public static function create(
return new $className($message, $request, $response, $previous, $handlerContext);
}

/**
* Obfuscates URI if there is a username and a password present
*/
private static function obfuscateUri(UriInterface $uri): UriInterface
{
$userInfo = $uri->getUserInfo();

if (false !== ($pos = \strpos($userInfo, ':'))) {
return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');
}

return $uri;
}

/**
* Get the request that caused the exception
*/
Expand Down
34 changes: 30 additions & 4 deletions src/Handler/CurlFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use GuzzleHttp\TransferStats;
use GuzzleHttp\Utils;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\UriInterface;

/**
* Creates curl resources from a request
Expand Down Expand Up @@ -251,15 +252,22 @@ private static function createRejection(EasyHandle $easy, array $ctx): PromiseIn
);
}

$uri = $easy->request->getUri();

$sanitizedError = self::sanitizeCurlError($ctx['error'] ?? '', $uri);

$message = \sprintf(
'cURL error %s: %s (%s)',
$ctx['errno'],
$ctx['error'],
$sanitizedError,
'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
);
$uriString = (string) $easy->request->getUri();
if ($uriString !== '' && false === \strpos($ctx['error'], $uriString)) {
$message .= \sprintf(' for %s', $uriString);

if ('' !== $sanitizedError) {
$redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($uri)->__toString();
if ($redactedUriString !== '' && false === \strpos($sanitizedError, $redactedUriString)) {
$message .= \sprintf(' for %s', $redactedUriString);
}
}

// Create a connection exception if it was a specific error code.
Expand All @@ -270,6 +278,24 @@ private static function createRejection(EasyHandle $easy, array $ctx): PromiseIn
return P\Create::rejectionFor($error);
}

private static function sanitizeCurlError(string $error, UriInterface $uri): string
{
if ('' === $error) {
return $error;
}

$baseUri = $uri->withQuery('')->withFragment('');
$baseUriString = $baseUri->__toString();

if ('' === $baseUriString) {
return $error;
}

$redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($baseUri)->__toString();

return str_replace($baseUriString, $redactedUriString, $error);
}

/**
* @return array<int|string, mixed>
*/
Expand Down
13 changes: 13 additions & 0 deletions tests/Handler/CurlHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ public function testCreatesCurlErrors()
$handler($request, ['timeout' => 0.001, 'connect_timeout' => 0.001])->wait();
}

public function testRedactsUserInfoInErrors()
{
$handler = new CurlHandler();
$request = new Request('GET', 'http://my_user:secretPass@localhost:123');

try {
$handler($request, ['timeout' => 0.001, 'connect_timeout' => 0.001])->wait();
$this->fail('Must throw an Exception.');
} catch (\Throwable $e) {
$this->assertStringNotContainsString('secretPass', $e->getMessage());
}
}

public function testReusesHandles()
{
Server::flush();
Expand Down

0 comments on commit 3bec073

Please sign in to comment.