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 / CurlClientState.php

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

150 lines 5.9 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 Psr\Log\LoggerInterface;
15 use Symfony\Component\HttpClient\Response\CurlResponse;
16
17 /**
18 * Internal representation of the cURL client's state.
19 *
20 * @author Alexander M. Turek <[email protected]>
21 *
22 * @internal
23 */
24 final class CurlClientState extends ClientState
25 {
26 /** @var \CurlMultiHandle|resource|null */
27 public $handle;
28 /** @var \CurlShareHandle|resource|null */
29 public $share;
30 /** @var PushedResponse[] */
31 public $pushedResponses = [];
32 /** @var DnsCache */
33 public $dnsCache;
34 /** @var float[] */
35 public $pauseExpiries = [];
36 public $execCounter = \PHP_INT_MIN;
37 /** @var LoggerInterface|null */
38 public $logger;
39 public $performing = false;
40
41 public static $curlVersion;
42
43 public function __construct(int $maxHostConnections, int $maxPendingPushes)
44 {
45 self::$curlVersion = self::$curlVersion ?? curl_version();
46
47 $this->handle = curl_multi_init();
48 $this->dnsCache = new DnsCache();
49 $this->reset();
50
51 // Don't enable HTTP/1.1 pipelining: it forces responses to be sent in order
52 if (\defined('CURLPIPE_MULTIPLEX')) {
53 curl_multi_setopt($this->handle, \CURLMOPT_PIPELINING, \CURLPIPE_MULTIPLEX);
54 }
55 if (\defined('CURLMOPT_MAX_HOST_CONNECTIONS')) {
56 $maxHostConnections = curl_multi_setopt($this->handle, \CURLMOPT_MAX_HOST_CONNECTIONS, 0 < $maxHostConnections ? $maxHostConnections : \PHP_INT_MAX) ? 0 : $maxHostConnections;
57 }
58 if (\defined('CURLMOPT_MAXCONNECTS') && 0 < $maxHostConnections) {
59 curl_multi_setopt($this->handle, \CURLMOPT_MAXCONNECTS, $maxHostConnections);
60 }
61
62 // Skip configuring HTTP/2 push when it's unsupported or buggy, see https://bugs.php.net/77535
63 if (0 >= $maxPendingPushes || \PHP_VERSION_ID < 70217 || (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304)) {
64 return;
65 }
66
67 // HTTP/2 push crashes before curl 7.61
68 if (!\defined('CURLMOPT_PUSHFUNCTION') || 0x073D00 > self::$curlVersion['version_number'] || !(\CURL_VERSION_HTTP2 & self::$curlVersion['features'])) {
69 return;
70 }
71
72 // Clone to prevent a circular reference
73 $multi = clone $this;
74 $multi->handle = null;
75 $multi->share = null;
76 $multi->pushedResponses = &$this->pushedResponses;
77 $multi->logger = &$this->logger;
78 $multi->handlesActivity = &$this->handlesActivity;
79 $multi->openHandles = &$this->openHandles;
80
81 curl_multi_setopt($this->handle, \CURLMOPT_PUSHFUNCTION, static function ($parent, $pushed, array $requestHeaders) use ($multi, $maxPendingPushes) {
82 return $multi->handlePush($parent, $pushed, $requestHeaders, $maxPendingPushes);
83 });
84 }
85
86 public function reset()
87 {
88 foreach ($this->pushedResponses as $url => $response) {
89 $this->logger && $this->logger->debug(sprintf('Unused pushed response: "%s"', $url));
90 curl_multi_remove_handle($this->handle, $response->handle);
91 curl_close($response->handle);
92 }
93
94 $this->pushedResponses = [];
95 $this->dnsCache->evictions = $this->dnsCache->evictions ?: $this->dnsCache->removals;
96 $this->dnsCache->removals = $this->dnsCache->hostnames = [];
97
98 $this->share = curl_share_init();
99
100 curl_share_setopt($this->share, \CURLSHOPT_SHARE, \CURL_LOCK_DATA_DNS);
101 curl_share_setopt($this->share, \CURLSHOPT_SHARE, \CURL_LOCK_DATA_SSL_SESSION);
102
103 if (\defined('CURL_LOCK_DATA_CONNECT') && \PHP_VERSION_ID >= 80000) {
104 curl_share_setopt($this->share, \CURLSHOPT_SHARE, \CURL_LOCK_DATA_CONNECT);
105 }
106 }
107
108 private function handlePush($parent, $pushed, array $requestHeaders, int $maxPendingPushes): int
109 {
110 $headers = [];
111 $origin = curl_getinfo($parent, \CURLINFO_EFFECTIVE_URL);
112
113 foreach ($requestHeaders as $h) {
114 if (false !== $i = strpos($h, ':', 1)) {
115 $headers[substr($h, 0, $i)][] = substr($h, 1 + $i);
116 }
117 }
118
119 if (!isset($headers[':method']) || !isset($headers[':scheme']) || !isset($headers[':authority']) || !isset($headers[':path'])) {
120 $this->logger && $this->logger->debug(sprintf('Rejecting pushed response from "%s": pushed headers are invalid', $origin));
121
122 return \CURL_PUSH_DENY;
123 }
124
125 $url = $headers[':scheme'][0].'://'.$headers[':authority'][0];
126
127 // curl before 7.65 doesn't validate the pushed ":authority" header,
128 // but this is a MUST in the HTTP/2 RFC; let's restrict pushes to the original host,
129 // ignoring domains mentioned as alt-name in the certificate for now (same as curl).
130 if (!str_starts_with($origin, $url.'/')) {
131 $this->logger && $this->logger->debug(sprintf('Rejecting pushed response from "%s": server is not authoritative for "%s"', $origin, $url));
132
133 return \CURL_PUSH_DENY;
134 }
135
136 if ($maxPendingPushes <= \count($this->pushedResponses)) {
137 $fifoUrl = key($this->pushedResponses);
138 unset($this->pushedResponses[$fifoUrl]);
139 $this->logger && $this->logger->debug(sprintf('Evicting oldest pushed response: "%s"', $fifoUrl));
140 }
141
142 $url .= $headers[':path'][0];
143 $this->logger && $this->logger->debug(sprintf('Queueing pushed response: "%s"', $url));
144
145 $this->pushedResponses[$url] = new PushedResponse(new CurlResponse($this, $pushed), $headers, $this->openHandles[(int) $parent][1] ?? [], $pushed);
146
147 return \CURL_PUSH_OK;
148 }
149 }
150