Skip to content

Commit

Permalink
Merge branch '6.4' into 7.1
Browse files Browse the repository at this point in the history
* 6.4:
  [HttpClient] Fix streaming and redirecting with NoPrivateNetworkHttpClient
  Bump Symfony version to 6.4.17
  Update VERSION for 6.4.16
  Update CHANGELOG for 6.4.16
  Bump Symfony version to 5.4.49
  Update VERSION for 5.4.48
  Update CONTRIBUTORS for 5.4.48
  Update CHANGELOG for 5.4.48
  • Loading branch information
nicolas-grekas committed Nov 29, 2024
2 parents 2ec4972 + 18725f0 commit f4459f8
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 43 deletions.
32 changes: 14 additions & 18 deletions NoPrivateNetworkHttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use Symfony\Contracts\HttpClient\ChunkInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
use Symfony\Contracts\HttpClient\ResponseStreamInterface;
use Symfony\Contracts\Service\ResetInterface;

/**
Expand Down Expand Up @@ -81,32 +80,34 @@ public function request(string $method, string $url, array $options = []): Respo
$ip = self::dnsResolve($dnsCache, $host, $this->ipFlags, $options);
self::ipCheck($ip, $this->subnets, $this->ipFlags, $host, $url);

if (0 < $maxRedirects = $options['max_redirects']) {
$options['max_redirects'] = 0;
$redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = $options['headers'];

if (isset($options['normalized_headers']['host']) || isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) {
$redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], static function ($h) {
return 0 !== stripos($h, 'Host:') && 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:');
});
}
}

$onProgress = $options['on_progress'] ?? null;
$subnets = $this->subnets;
$ipFlags = $this->ipFlags;

$options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use ($onProgress, $subnets, $ipFlags): void {
static $lastPrimaryIp = '';

if (($info['primary_ip'] ?? '') !== $lastPrimaryIp) {
if (!\in_array($info['primary_ip'] ?? '', ['', $lastPrimaryIp], true)) {
self::ipCheck($info['primary_ip'], $subnets, $ipFlags, null, $info['url']);
$lastPrimaryIp = $info['primary_ip'];
}

null !== $onProgress && $onProgress($dlNow, $dlSize, $info);
};

if (0 >= $maxRedirects = $options['max_redirects']) {
return new AsyncResponse($this->client, $method, $url, $options);
}

$options['max_redirects'] = 0;
$redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = $options['headers'];

if (isset($options['normalized_headers']['host']) || isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) {
$redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], static function ($h) {
return 0 !== stripos($h, 'Host:') && 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:');
});
}

return new AsyncResponse($this->client, $method, $url, $options, static function (ChunkInterface $chunk, AsyncContext $context) use (&$method, &$options, $maxRedirects, &$redirectHeaders, $subnets, $ipFlags, $dnsCache): \Generator {
if (null !== $chunk->getError() || $chunk->isTimeout() || !$chunk->isFirst()) {
yield $chunk;
Expand Down Expand Up @@ -158,11 +159,6 @@ public function request(string $method, string $url, array $options = []): Respo
});
}

public function stream(ResponseInterface|iterable $responses, ?float $timeout = null): ResponseStreamInterface
{
return $this->client->stream($responses, $timeout);
}

/**
* @deprecated since Symfony 7.1, configure the logger on the wrapped HTTP client directly instead
*/
Expand Down
5 changes: 0 additions & 5 deletions Tests/DataCollector/HttpClientDataCollectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ public static function setUpBeforeClass(): void
TestHttpServer::start();
}

public static function tearDownAfterClass(): void
{
TestHttpServer::stop();
}

public function testItCollectsRequestCount()
{
$httpClient1 = $this->httpClientThatHasTracedRequests([
Expand Down
67 changes: 67 additions & 0 deletions Tests/HttpClientTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,73 @@ public function testNoPrivateNetworkWithResolveAndRedirect()
$client->request('GET', 'http://localhost:8057/302?location=https://symfony.com/');
}

public function testNoPrivateNetwork304()
{
$client = $this->getHttpClient(__FUNCTION__);
$client = new NoPrivateNetworkHttpClient($client, '104.26.14.6/32');
$response = $client->request('GET', 'http://localhost:8057/304', [
'headers' => ['If-Match' => '"abc"'],
'buffer' => false,
]);

$this->assertSame(304, $response->getStatusCode());
$this->assertSame('', $response->getContent(false));
}

public function testNoPrivateNetwork302()
{
$client = $this->getHttpClient(__FUNCTION__);
$client = new NoPrivateNetworkHttpClient($client, '104.26.14.6/32');
$response = $client->request('GET', 'http://localhost:8057/302/relative');

$body = $response->toArray();

$this->assertSame('/', $body['REQUEST_URI']);
$this->assertNull($response->getInfo('redirect_url'));

$response = $client->request('GET', 'http://localhost:8057/302/relative', [
'max_redirects' => 0,
]);

$this->assertSame(302, $response->getStatusCode());
$this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url'));
}

public function testNoPrivateNetworkStream()
{
$client = $this->getHttpClient(__FUNCTION__);

$response = $client->request('GET', 'http://localhost:8057');
$client = new NoPrivateNetworkHttpClient($client, '104.26.14.6/32');

$response = $client->request('GET', 'http://localhost:8057');
$chunks = $client->stream($response);
$result = [];

foreach ($chunks as $r => $chunk) {
if ($chunk->isTimeout()) {
$result[] = 't';
} elseif ($chunk->isLast()) {
$result[] = 'l';
} elseif ($chunk->isFirst()) {
$result[] = 'f';
}
}

$this->assertSame($response, $r);
$this->assertSame(['f', 'l'], $result);

$chunk = null;
$i = 0;

foreach ($client->stream($response) as $chunk) {
++$i;
}

$this->assertSame(1, $i);
$this->assertTrue($chunk->isLast());
}

public function testNoRedirectWithInvalidLocation()
{
$client = $this->getHttpClient(__FUNCTION__);
Expand Down
5 changes: 0 additions & 5 deletions Tests/HttplugClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@ public static function setUpBeforeClass(): void
TestHttpServer::start();
}

public static function tearDownAfterClass(): void
{
TestHttpServer::stop();
}

/**
* @requires function ob_gzhandler
*/
Expand Down
5 changes: 0 additions & 5 deletions Tests/Psr18ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,6 @@ public static function setUpBeforeClass(): void
TestHttpServer::start();
}

public static function tearDownAfterClass(): void
{
TestHttpServer::stop();
}

/**
* @requires function ob_gzhandler
*/
Expand Down
5 changes: 0 additions & 5 deletions Tests/RetryableHttpClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@

class RetryableHttpClientTest extends TestCase
{
public static function tearDownAfterClass(): void
{
TestHttpServer::stop();
}

public function testRetryOnError()
{
$client = new RetryableHttpClient(
Expand Down
5 changes: 0 additions & 5 deletions Tests/TraceableHttpClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ public static function setUpBeforeClass(): void
TestHttpServer::start();
}

public static function tearDownAfterClass(): void
{
TestHttpServer::stop();
}

public function testItTracesRequest()
{
$httpClient = $this->createMock(HttpClientInterface::class);
Expand Down

0 comments on commit f4459f8

Please sign in to comment.