diff --git a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php index db158103f9156..6d80d942b3cee 100644 --- a/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php +++ b/src/Symfony/Component/HttpClient/DataCollector/HttpClientDataCollector.php @@ -175,6 +175,15 @@ private function getCurlCommand(array $trace): ?string $url = $trace['url']; $command = ['curl', '--compressed']; + if (isset($trace['options']['resolve'])) { + $port = parse_url($url, \PHP_URL_PORT) ?: (str_starts_with('http:', $url) ? 80 : 443); + foreach ($trace['options']['resolve'] as $host => $ip) { + if (null !== $ip) { + $command[] = '--resolve '.escapeshellarg("$host:$port:$ip"); + } + } + } + $dataArg = []; if ($json = $trace['options']['json'] ?? null) { diff --git a/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php b/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php index cf83e316189a3..56f824c098863 100755 --- a/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php +++ b/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php @@ -168,28 +168,127 @@ public function testItIsEmptyAfterReset() /** * @requires extension openssl + * @dataProvider provideCurlRequests */ - public function testItGeneratesCurlCommandsAsExpected() + public function testItGeneratesCurlCommandsAsExpected(array $request, string $expectedCurlCommand) { $sut = new HttpClientDataCollector(); - $sut->registerClient('http_client', $this->httpClientThatHasTracedRequests([ - [ - 'method' => 'GET', - 'url' => 'https://symfony.com/releases.json', - ], - ])); + $sut->registerClient('http_client', $this->httpClientThatHasTracedRequests([$request])); $sut->collect(new Request(), new Response()); $collectedData = $sut->getClients(); self::assertCount(1, $collectedData['http_client']['traces']); $curlCommand = $collectedData['http_client']['traces'][0]['curlCommand']; - self::assertEquals(sprintf('curl \\ + self::assertEquals(sprintf($expectedCurlCommand, '\\' === \DIRECTORY_SEPARATOR ? '"' : "'"), $curlCommand); + } + + public function provideCurlRequests(): iterable + { + yield 'GET' => [ + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/json', + ], + 'curl \\ --compressed \\ --request GET \\ - --url %1$shttps://symfony.com/releases.json%1$s \\ + --url %1$shttp://localhost:8057/json%1$s \\ --header %1$sAccept: */*%1$s \\ --header %1$sAccept-Encoding: gzip%1$s \\ - --header %1$sUser-Agent: Symfony HttpClient/Native%1$s', '\\' === \DIRECTORY_SEPARATOR ? '"' : "'"), $curlCommand - ); + --header %1$sUser-Agent: Symfony HttpClient/Native%1$s', + ]; + yield 'GET with resolve' => [ + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/json', + 'options' => [ + 'resolve' => [ + 'localhost' => '127.0.0.1', + 'example.com' => null, + ], + ], + ], + 'curl \\ + --compressed \\ + --resolve %1$slocalhost:8057:127.0.0.1%1$s \\ + --request GET \\ + --url %1$shttp://localhost:8057/json%1$s \\ + --header %1$sAccept: */*%1$s \\ + --header %1$sAccept-Encoding: gzip%1$s \\ + --header %1$sUser-Agent: Symfony HttpClient/Native%1$s', + ]; + yield 'POST with string body' => [ + [ + 'method' => 'POST', + 'url' => 'http://localhost:8057/json', + 'options' => [ + 'body' => 'foobarbaz', + ], + ], + 'curl \\ + --compressed \\ + --request POST \\ + --url %1$shttp://localhost:8057/json%1$s \\ + --header %1$sAccept: */*%1$s \\ + --header %1$sContent-Length: 9%1$s \\ + --header %1$sContent-Type: application/x-www-form-urlencoded%1$s \\ + --header %1$sAccept-Encoding: gzip%1$s \\ + --header %1$sUser-Agent: Symfony HttpClient/Native%1$s \\ + --data %1$sfoobarbaz%1$s', + ]; + yield 'POST with array body' => [ + [ + 'method' => 'POST', + 'url' => 'http://localhost:8057/json', + 'options' => [ + 'body' => [ + 'foo' => 'fooval', + 'bar' => 'barval', + 'baz' => 'bazval', + ], + ], + ], + 'curl \\ + --compressed \\ + --request POST \\ + --url %1$shttp://localhost:8057/json%1$s \\ + --header %1$sAccept: */*%1$s \\ + --header %1$sContent-Length: 32%1$s \\ + --header %1$sContent-Type: application/x-www-form-urlencoded%1$s \\ + --header %1$sAccept-Encoding: gzip%1$s \\ + --header %1$sUser-Agent: Symfony HttpClient/Native%1$s \\ + --data %1$sfoo=fooval%1$s --data %1$sbar=barval%1$s --data %1$sbaz=bazval%1$s', + ]; + + // escapeshellarg on Windows replaces double quotes with spaces + if ('\\' !== \DIRECTORY_SEPARATOR) { + yield 'POST with json' => [ + [ + 'method' => 'POST', + 'url' => 'http://localhost:8057/json', + 'options' => [ + 'json' => [ + 'foo' => [ + 'bar' => 'baz', + ], + ], + ], + ], + 'curl \\ + --compressed \\ + --request POST \\ + --url %1$shttp://localhost:8057/json%1$s \\ + --header %1$sContent-Type: application/json%1$s \\ + --header %1$sAccept: */*%1$s \\ + --header %1$sContent-Length: 21%1$s \\ + --header %1$sAccept-Encoding: gzip%1$s \\ + --header %1$sUser-Agent: Symfony HttpClient/Native%1$s \\ + --data %1$s{ + "foo": { + "bar": "baz" + } +}%1$s', + ]; + } } /** @@ -199,11 +298,14 @@ public function testItDoesNotFollowRedirectionsWhenGeneratingCurlCommands() { $sut = new HttpClientDataCollector(); $sut->registerClient('http_client', $this->httpClientThatHasTracedRequests([ - [ - 'method' => 'GET', - 'url' => 'http://symfony.com/releases.json', + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/301', + 'options' => [ + 'auth_basic' => 'foo:bar', ], - ])); + ], + ])); $sut->collect(new Request(), new Response()); $collectedData = $sut->getClients(); self::assertCount(1, $collectedData['http_client']['traces']); @@ -211,8 +313,9 @@ public function testItDoesNotFollowRedirectionsWhenGeneratingCurlCommands() self::assertEquals(sprintf('curl \\ --compressed \\ --request GET \\ - --url %1$shttp://symfony.com/releases.json%1$s \\ + --url %1$shttp://localhost:8057/301%1$s \\ --header %1$sAccept: */*%1$s \\ + --header %1$sAuthorization: Basic Zm9vOmJhcg==%1$s \\ --header %1$sAccept-Encoding: gzip%1$s \\ --header %1$sUser-Agent: Symfony HttpClient/Native%1$s', '\\' === \DIRECTORY_SEPARATOR ? '"' : "'"), $curlCommand ); @@ -225,14 +328,14 @@ public function testItDoesNotGeneratesCurlCommandsForUnsupportedBodyType() { $sut = new HttpClientDataCollector(); $sut->registerClient('http_client', $this->httpClientThatHasTracedRequests([ - [ - 'method' => 'GET', - 'url' => 'https://symfony.com/releases.json', - 'options' => [ - 'body' => static fn (int $size): string => '', - ], + [ + 'method' => 'GET', + 'url' => 'http://localhost:8057/json', + 'options' => [ + 'body' => static fn (int $size): string => '', ], - ])); + ], + ])); $sut->collect(new Request(), new Response()); $collectedData = $sut->getClients(); self::assertCount(1, $collectedData['http_client']['traces']);