PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 2.8.16
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v2.8.16
3.13.3 3.13.2 3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 All 261 releases
wpfunnels / vendor / symfony / http-client / Internal / AmpClientState.php

AmpClientState.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 2.8.16, at vendor/symfony/http-client/Internal/AmpClientState.php

218 lines 8.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <[email protected]>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Symfony\Component\HttpClient\Internal;
13
14 use Amp\CancellationToken;
15 use Amp\Deferred;
16 use Amp\Http\Client\Connection\ConnectionLimitingPool;
17 use Amp\Http\Client\Connection\DefaultConnectionFactory;
18 use Amp\Http\Client\InterceptedHttpClient;
19 use Amp\Http\Client\Interceptor\RetryRequests;
20 use Amp\Http\Client\PooledHttpClient;
21 use Amp\Http\Client\Request;
22 use Amp\Http\Client\Response;
23 use Amp\Http\Tunnel\Http1TunnelConnector;
24 use Amp\Http\Tunnel\Https1TunnelConnector;
25 use Amp\Promise;
26 use Amp\Socket\Certificate;
27 use Amp\Socket\ClientTlsContext;
28 use Amp\Socket\ConnectContext;
29 use Amp\Socket\Connector;
30 use Amp\Socket\DnsConnector;
31 use Amp\Socket\SocketAddress;
32 use Amp\Success;
33 use Psr\Log\LoggerInterface;
34
35 /**
36 * Internal representation of the Amp client's state.
37 *
38 * @author Nicolas Grekas <[email protected]>
39 *
40 * @internal
41 */
42 final class AmpClientState extends ClientState
43 {
44 public $dnsCache = [];
45 public $responseCount = 0;
46 public $pushedResponses = [];
47
48 private $clients = [];
49 private $clientConfigurator;
50 private $maxHostConnections;
51 private $maxPendingPushes;
52 private $logger;
53
54 public function __construct(?callable $clientConfigurator, int $maxHostConnections, int $maxPendingPushes, ?LoggerInterface &$logger)
55 {
56 $this->clientConfigurator = $clientConfigurator ?? static function (PooledHttpClient $client) {
57 return new InterceptedHttpClient($client, new RetryRequests(2));
58 };
59 $this->maxHostConnections = $maxHostConnections;
60 $this->maxPendingPushes = $maxPendingPushes;
61 $this->logger = &$logger;
62 }
63
64 /**
65 * @return Promise<Response>
66 */
67 public function request(array $options, Request $request, CancellationToken $cancellation, array &$info, \Closure $onProgress, &$handle): Promise
68 {
69 if ($options['proxy']) {
70 if ($request->hasHeader('proxy-authorization')) {
71 $options['proxy']['auth'] = $request->getHeader('proxy-authorization');
72 }
73
74 // Matching "no_proxy" should follow the behavior of curl
75 $host = $request->getUri()->getHost();
76 foreach ($options['proxy']['no_proxy'] as $rule) {
77 $dotRule = '.'.ltrim($rule, '.');
78
79 if ('*' === $rule || $host === $rule || substr($host, -\strlen($dotRule)) === $dotRule) {
80 $options['proxy'] = null;
81 break;
82 }
83 }
84 }
85
86 $request = clone $request;
87
88 if ($request->hasHeader('proxy-authorization')) {
89 $request->removeHeader('proxy-authorization');
90 }
91
92 if ($options['capture_peer_cert_chain']) {
93 $info['peer_certificate_chain'] = [];
94 }
95
96 $request->addEventListener(new AmpListener($info, $options['peer_fingerprint']['pin-sha256'] ?? [], $onProgress, $handle));
97 $request->setPushHandler(function ($request, $response) use ($options): Promise {
98 return $this->handlePush($request, $response, $options);
99 });
100
101 ($request->hasHeader('content-length') ? new Success((int) $request->getHeader('content-length')) : $request->getBody()->getBodyLength())
102 ->onResolve(static function ($e, $bodySize) use (&$info) {
103 if (null !== $bodySize && 0 <= $bodySize) {
104 $info['upload_content_length'] = ((1 + $info['upload_content_length']) ?? 1) - 1 + $bodySize;
105 }
106 });
107
108 [$client, $connector] = $this->getClient($options);
109 $response = $client->request($request, $cancellation);
110 $response->onResolve(static function ($e) use ($connector, &$handle) {
111 if (null === $e) {
112 $handle = $connector->handle;
113 }
114 });
115
116 return $response;
117 }
118
119 private function getClient(array $options): array
120 {
121 $options = [
122 'bindto' => $options['bindto'] ?: '0',
123 'verify_peer' => $options['verify_peer'],
124 'capath' => $options['capath'],
125 'cafile' => $options['cafile'],
126 'local_cert' => $options['local_cert'],
127 'local_pk' => $options['local_pk'],
128 'ciphers' => $options['ciphers'],
129 'capture_peer_cert_chain' => $options['capture_peer_cert_chain'] || $options['peer_fingerprint'],
130 'proxy' => $options['proxy'],
131 ];
132
133 $key = md5(serialize($options));
134
135 if (isset($this->clients[$key])) {
136 return $this->clients[$key];
137 }
138
139 $context = new ClientTlsContext('');
140 $options['verify_peer'] || $context = $context->withoutPeerVerification();
141 $options['cafile'] && $context = $context->withCaFile($options['cafile']);
142 $options['capath'] && $context = $context->withCaPath($options['capath']);
143 $options['local_cert'] && $context = $context->withCertificate(new Certificate($options['local_cert'], $options['local_pk']));
144 $options['ciphers'] && $context = $context->withCiphers($options['ciphers']);
145 $options['capture_peer_cert_chain'] && $context = $context->withPeerCapturing();
146
147 $connector = $handleConnector = new class() implements Connector {
148 public $connector;
149 public $uri;
150 public $handle;
151
152 public function connect(string $uri, ConnectContext $context = null, CancellationToken $token = null): Promise
153 {
154 $result = $this->connector->connect($this->uri ?? $uri, $context, $token);
155 $result->onResolve(function ($e, $socket) {
156 $this->handle = null !== $socket ? $socket->getResource() : false;
157 });
158
159 return $result;
160 }
161 };
162 $connector->connector = new DnsConnector(new AmpResolver($this->dnsCache));
163
164 $context = (new ConnectContext())
165 ->withTcpNoDelay()
166 ->withTlsContext($context);
167
168 if ($options['bindto']) {
169 if (file_exists($options['bindto'])) {
170 $connector->uri = 'unix://'.$options['bindto'];
171 } else {
172 $context = $context->withBindTo($options['bindto']);
173 }
174 }
175
176 if ($options['proxy']) {
177 $proxyUrl = parse_url($options['proxy']['url']);
178 $proxySocket = new SocketAddress($proxyUrl['host'], $proxyUrl['port']);
179 $proxyHeaders = $options['proxy']['auth'] ? ['Proxy-Authorization' => $options['proxy']['auth']] : [];
180
181 if ('ssl' === $proxyUrl['scheme']) {
182 $connector = new Https1TunnelConnector($proxySocket, $context->getTlsContext(), $proxyHeaders, $connector);
183 } else {
184 $connector = new Http1TunnelConnector($proxySocket, $proxyHeaders, $connector);
185 }
186 }
187
188 $maxHostConnections = 0 < $this->maxHostConnections ? $this->maxHostConnections : \PHP_INT_MAX;
189 $pool = new DefaultConnectionFactory($connector, $context);
190 $pool = ConnectionLimitingPool::byAuthority($maxHostConnections, $pool);
191
192 return $this->clients[$key] = [($this->clientConfigurator)(new PooledHttpClient($pool)), $handleConnector];
193 }
194
195 private function handlePush(Request $request, Promise $response, array $options): Promise
196 {
197 $deferred = new Deferred();
198 $authority = $request->getUri()->getAuthority();
199
200 if ($this->maxPendingPushes <= \count($this->pushedResponses[$authority] ?? [])) {
201 $fifoUrl = key($this->pushedResponses[$authority]);
202 unset($this->pushedResponses[$authority][$fifoUrl]);
203 $this->logger && $this->logger->debug(sprintf('Evicting oldest pushed response: "%s"', $fifoUrl));
204 }
205
206 $url = (string) $request->getUri();
207 $this->logger && $this->logger->debug(sprintf('Queueing pushed response: "%s"', $url));
208 $this->pushedResponses[$authority][] = [$url, $deferred, $request, $response, [
209 'proxy' => $options['proxy'],
210 'bindto' => $options['bindto'],
211 'local_cert' => $options['local_cert'],
212 'local_pk' => $options['local_pk'],
213 ]];
214
215 return $deferred->promise();
216 }
217 }
218