PluginProbe
Gmail SMTP / trunk
Gmail SMTP vtrunk
1.2.3.21 1.2.3.20 trunk 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.9 1.2.0 1.2.3.14 1.2.3.15 1.2.3.16 1.2.3.18 1.2.3.5
gmail-smtp / google-api-php-client / vendor / guzzlehttp / guzzle / src / Handler / CurlShareHandleState.php

CurlShareHandleState.php in Gmail SMTP trunk, at google-api-php-client/vendor/guzzlehttp/guzzle/src/Handler/CurlShareHandleState.php

183 lines 5.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace GuzzleHttp\Handler;
4
5 use GuzzleHttp\TransportSharing;
6
7 /**
8 * @internal
9 */
10 final class CurlShareHandleState
11 {
12 /**
13 * @var resource|\CurlShareHandle|null
14 */
15 public $handle;
16
17 /**
18 * @var string
19 */
20 public $mode;
21
22 /**
23 * @param resource|\CurlShareHandle|null $handle
24 */
25 private function __construct(string $mode, $handle)
26 {
27 $this->mode = $mode;
28 $this->handle = $handle;
29 }
30
31 /**
32 * @param mixed $sharing
33 */
34 public static function fromOption($sharing): ?self
35 {
36 if ($sharing instanceof self) {
37 return $sharing;
38 }
39
40 $mode = self::normalizeMode($sharing, 'transport_sharing');
41 if ($mode === TransportSharing::NONE) {
42 return null;
43 }
44
45 if ($mode === TransportSharing::HANDLER_PREFER) {
46 return self::createHandlerShareOrNull($mode);
47 }
48
49 return self::createHandlerShare($mode);
50 }
51
52 /**
53 * @param mixed $sharing
54 */
55 public static function normalizeMode($sharing, string $option): string
56 {
57 if ($sharing instanceof self) {
58 return $sharing->mode;
59 }
60
61 if ($sharing === null || $sharing === TransportSharing::NONE) {
62 return TransportSharing::NONE;
63 }
64
65 if ($sharing === TransportSharing::HANDLER_PREFER || $sharing === TransportSharing::HANDLER_REQUIRE) {
66 return $sharing;
67 }
68
69 throw new \InvalidArgumentException(\sprintf(
70 'The "%s" option must be null or a GuzzleHttp\\TransportSharing::* constant; received %s.',
71 $option,
72 \get_debug_type($sharing)
73 ));
74 }
75
76 public static function assertNoRequiredSharingCustomFactoryConflict(array $options, string $handlerName): void
77 {
78 if (!\array_key_exists('handle_factory', $options) || $options['handle_factory'] === null) {
79 return;
80 }
81
82 $mode = self::normalizeMode($options['transport_sharing'] ?? null, 'transport_sharing');
83 if ($mode !== TransportSharing::HANDLER_REQUIRE) {
84 return;
85 }
86
87 throw new \InvalidArgumentException(\sprintf(
88 'The "transport_sharing" %s option cannot require sharing with a custom "handle_factory" because Guzzle cannot ensure that the custom factory applies CURLOPT_SHARE.',
89 $handlerName
90 ));
91 }
92
93 private static function createHandlerShareOrNull(string $mode): ?self
94 {
95 try {
96 return self::createHandlerShare($mode);
97 } catch (\Throwable $e) {
98 return null;
99 }
100 }
101
102 private static function createHandlerShare(string $mode): self
103 {
104 if (!\function_exists('curl_share_init') || !\function_exists('curl_share_setopt')) {
105 throw new \InvalidArgumentException('The "transport_sharing" option requires cURL share support.');
106 }
107
108 self::requireCurlConstant('CURLOPT_SHARE');
109 $shareOption = self::requireCurlConstant('CURLSHOPT_SHARE');
110 $locks = self::handlerLocks($mode);
111 $handle = curl_share_init();
112
113 try {
114 foreach ($locks as $lock) {
115 try {
116 $success = curl_share_setopt($handle, $shareOption, $lock);
117 } catch (\Throwable $e) {
118 throw new \InvalidArgumentException('Unable to configure cURL share handle: '.$e->getMessage(), 0, $e);
119 }
120
121 if (!$success) {
122 throw new \InvalidArgumentException(\sprintf('Unable to configure cURL share handle with lock data %d.', $lock));
123 }
124 }
125 } catch (\Throwable $e) {
126 self::closeHandlerShareHandleOnPhp7($handle);
127
128 throw $e;
129 }
130
131 return new self($mode, $handle);
132 }
133
134 /**
135 * @return int[]
136 */
137 private static function handlerLocks(string $mode): array
138 {
139 CurlVersion::ensureHandlerSharingSupported();
140
141 if ($mode === TransportSharing::HANDLER_REQUIRE) {
142 CurlVersion::ensureSslSessionSharingSupported();
143 }
144
145 $locks = [
146 self::requireCurlConstant('CURL_LOCK_DATA_DNS'),
147 ];
148
149 if (CurlVersion::supportsSslSessionSharing()) {
150 $locks[] = self::requireCurlConstant('CURL_LOCK_DATA_SSL_SESSION');
151 }
152
153 return $locks;
154 }
155
156 private static function requireCurlConstant(string $constant): int
157 {
158 if (!\defined($constant)) {
159 throw new \InvalidArgumentException(\sprintf(
160 'The "transport_sharing" option requires %s, but it is not available in the installed PHP cURL extension.',
161 $constant
162 ));
163 }
164
165 $value = \constant($constant);
166 if (!\is_int($value)) {
167 throw new \InvalidArgumentException(\sprintf('The cURL constant %s must resolve to an integer.', $constant));
168 }
169
170 return $value;
171 }
172
173 /**
174 * @param resource|\CurlShareHandle $handle
175 */
176 private static function closeHandlerShareHandleOnPhp7($handle): void
177 {
178 if (\PHP_VERSION_ID < 80000 && \is_resource($handle)) {
179 curl_share_close($handle);
180 }
181 }
182 }
183