Skip to content

Commit d77d8e2

Browse files
[HttpClient] Fix streaming and redirecting with NoPrivateNetworkHttpClient
1 parent 63a1278 commit d77d8e2

7 files changed

+81
-46
lines changed

NoPrivateNetworkHttpClient.php

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
use Symfony\Contracts\HttpClient\ChunkInterface;
2121
use Symfony\Contracts\HttpClient\HttpClientInterface;
2222
use Symfony\Contracts\HttpClient\ResponseInterface;
23-
use Symfony\Contracts\HttpClient\ResponseStreamInterface;
2423
use Symfony\Contracts\Service\ResetInterface;
2524

2625
/**
@@ -103,31 +102,33 @@ public function request(string $method, string $url, array $options = []): Respo
103102
$ip = self::dnsResolve($dnsCache, $host, $this->ipFlags, $options);
104103
self::ipCheck($ip, $this->subnets, $this->ipFlags, $host, $url);
105104

106-
if (0 < $maxRedirects = $options['max_redirects']) {
107-
$options['max_redirects'] = 0;
108-
$redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = $options['headers'];
109-
110-
if (isset($options['normalized_headers']['host']) || isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) {
111-
$redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], static function ($h) {
112-
return 0 !== stripos($h, 'Host:') && 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:');
113-
});
114-
}
115-
}
116-
117105
$onProgress = $options['on_progress'] ?? null;
118106
$subnets = $this->subnets;
119107
$ipFlags = $this->ipFlags;
120108
$lastPrimaryIp = '';
121109

122110
$options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use ($onProgress, $subnets, $ipFlags, &$lastPrimaryIp): void {
123-
if (($info['primary_ip'] ?? '') !== $lastPrimaryIp) {
111+
if (!\in_array($info['primary_ip'] ?? '', ['', $lastPrimaryIp], true)) {
124112
self::ipCheck($info['primary_ip'], $subnets, $ipFlags, null, $info['url']);
125113
$lastPrimaryIp = $info['primary_ip'];
126114
}
127115

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

119+
if (0 >= $maxRedirects = $options['max_redirects']) {
120+
return new AsyncResponse($this->client, $method, $url, $options);
121+
}
122+
123+
$options['max_redirects'] = 0;
124+
$redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = $options['headers'];
125+
126+
if (isset($options['normalized_headers']['host']) || isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) {
127+
$redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], static function ($h) {
128+
return 0 !== stripos($h, 'Host:') && 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:');
129+
});
130+
}
131+
131132
return new AsyncResponse($this->client, $method, $url, $options, static function (ChunkInterface $chunk, AsyncContext $context) use (&$method, &$options, $maxRedirects, &$redirectHeaders, $subnets, $ipFlags, $dnsCache): \Generator {
132133
if (null !== $chunk->getError() || $chunk->isTimeout() || !$chunk->isFirst()) {
133134
yield $chunk;
@@ -178,14 +179,6 @@ public function request(string $method, string $url, array $options = []): Respo
178179
});
179180
}
180181

181-
/**
182-
* {@inheritdoc}
183-
*/
184-
public function stream($responses, ?float $timeout = null): ResponseStreamInterface
185-
{
186-
return $this->client->stream($responses, $timeout);
187-
}
188-
189182
/**
190183
* {@inheritdoc}
191184
*/

Tests/DataCollector/HttpClientDataCollectorTest.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,6 @@ public static function setUpBeforeClass(): void
2424
TestHttpServer::start();
2525
}
2626

27-
public static function tearDownAfterClass(): void
28-
{
29-
TestHttpServer::stop();
30-
}
31-
3227
public function testItCollectsRequestCount()
3328
{
3429
$httpClient1 = $this->httpClientThatHasTracedRequests([

Tests/HttpClientTestCase.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,73 @@ public function testNoPrivateNetworkWithResolveAndRedirect()
523523
$client->request('GET', 'http://localhost:8057/302?location=https://symfony.com/');
524524
}
525525

526+
public function testNoPrivateNetwork304()
527+
{
528+
$client = $this->getHttpClient(__FUNCTION__);
529+
$client = new NoPrivateNetworkHttpClient($client, '104.26.14.6/32');
530+
$response = $client->request('GET', 'http://localhost:8057/304', [
531+
'headers' => ['If-Match' => '"abc"'],
532+
'buffer' => false,
533+
]);
534+
535+
$this->assertSame(304, $response->getStatusCode());
536+
$this->assertSame('', $response->getContent(false));
537+
}
538+
539+
public function testNoPrivateNetwork302()
540+
{
541+
$client = $this->getHttpClient(__FUNCTION__);
542+
$client = new NoPrivateNetworkHttpClient($client, '104.26.14.6/32');
543+
$response = $client->request('GET', 'http://localhost:8057/302/relative');
544+
545+
$body = $response->toArray();
546+
547+
$this->assertSame('/', $body['REQUEST_URI']);
548+
$this->assertNull($response->getInfo('redirect_url'));
549+
550+
$response = $client->request('GET', 'http://localhost:8057/302/relative', [
551+
'max_redirects' => 0,
552+
]);
553+
554+
$this->assertSame(302, $response->getStatusCode());
555+
$this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url'));
556+
}
557+
558+
public function testNoPrivateNetworkStream()
559+
{
560+
$client = $this->getHttpClient(__FUNCTION__);
561+
562+
$response = $client->request('GET', 'http://localhost:8057');
563+
$client = new NoPrivateNetworkHttpClient($client, '104.26.14.6/32');
564+
565+
$response = $client->request('GET', 'http://localhost:8057');
566+
$chunks = $client->stream($response);
567+
$result = [];
568+
569+
foreach ($chunks as $r => $chunk) {
570+
if ($chunk->isTimeout()) {
571+
$result[] = 't';
572+
} elseif ($chunk->isLast()) {
573+
$result[] = 'l';
574+
} elseif ($chunk->isFirst()) {
575+
$result[] = 'f';
576+
}
577+
}
578+
579+
$this->assertSame($response, $r);
580+
$this->assertSame(['f', 'l'], $result);
581+
582+
$chunk = null;
583+
$i = 0;
584+
585+
foreach ($client->stream($response) as $chunk) {
586+
++$i;
587+
}
588+
589+
$this->assertSame(1, $i);
590+
$this->assertTrue($chunk->isLast());
591+
}
592+
526593
public function testNoRedirectWithInvalidLocation()
527594
{
528595
$client = $this->getHttpClient(__FUNCTION__);

Tests/HttplugClientTest.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,6 @@ public static function setUpBeforeClass(): void
3232
TestHttpServer::start();
3333
}
3434

35-
public static function tearDownAfterClass(): void
36-
{
37-
TestHttpServer::stop();
38-
}
39-
4035
/**
4136
* @requires function ob_gzhandler
4237
*/

Tests/Psr18ClientTest.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@ public static function setUpBeforeClass(): void
2828
TestHttpServer::start();
2929
}
3030

31-
public static function tearDownAfterClass(): void
32-
{
33-
TestHttpServer::stop();
34-
}
35-
3631
/**
3732
* @requires function ob_gzhandler
3833
*/

Tests/RetryableHttpClientTest.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,6 @@
2727

2828
class RetryableHttpClientTest extends TestCase
2929
{
30-
public static function tearDownAfterClass(): void
31-
{
32-
TestHttpServer::stop();
33-
}
34-
3530
public function testRetryOnError()
3631
{
3732
$client = new RetryableHttpClient(

Tests/TraceableHttpClientTest.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,6 @@ public static function setUpBeforeClass(): void
2929
TestHttpServer::start();
3030
}
3131

32-
public static function tearDownAfterClass(): void
33-
{
34-
TestHttpServer::stop();
35-
}
36-
3732
public function testItTracesRequest()
3833
{
3934
$httpClient = $this->createMock(HttpClientInterface::class);

0 commit comments

Comments
 (0)