PluginProbe ʕ •ᴥ•ʔ
WP Mail SMTP by WPForms – The Most Popular SMTP and Email Log Plugin / 3.7.0
WP Mail SMTP by WPForms – The Most Popular SMTP and Email Log Plugin v3.7.0
0.9.6 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.2 1.7.0 1.7.1 1.8.0 1.8.1 1.9.0 2.0.0 2.0.1 2.1.1 2.2.1 2.3.1 2.4.0 2.5.0 2.5.1 2.6.0 2.7.0 2.8.0 2.9.0 3.0.1 3.0.2 3.0.3 3.1.0 3.10.0 3.11.0 3.11.1 3.2.0 3.2.1 3.3.0 3.4.0 3.5.0 3.5.1 3.5.2 3.6.1 3.7.0 3.8.0 3.8.2 3.9.0 4.0.1 4.1.0 4.1.1 4.2.0 4.3.0 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.8.0 trunk 0.10.0 0.10.1 0.11.1 0.11.2 0.3.1 0.3.2 0.4 0.4.1 0.4.2 0.5.0 0.5.1 0.5.2 0.6 0.7 0.8 0.8.2 0.8.3 0.8.4 0.8.5 0.8.6 0.8.7 0.9.0 0.9.1 0.9.2 0.9.3 0.9.4 0.9.5
wp-mail-smtp / vendor_prefixed / guzzlehttp / guzzle / src / Handler / StreamHandler.php
wp-mail-smtp / vendor_prefixed / guzzlehttp / guzzle / src / Handler Last commit date
CurlFactory.php 3 years ago CurlFactoryInterface.php 3 years ago CurlHandler.php 3 years ago CurlMultiHandler.php 3 years ago EasyHandle.php 3 years ago MockHandler.php 3 years ago Proxy.php 3 years ago StreamHandler.php 3 years ago
StreamHandler.php
378 lines
1 <?php
2
3 namespace WPMailSMTP\Vendor\GuzzleHttp\Handler;
4
5 use WPMailSMTP\Vendor\GuzzleHttp\Exception\ConnectException;
6 use WPMailSMTP\Vendor\GuzzleHttp\Exception\RequestException;
7 use WPMailSMTP\Vendor\GuzzleHttp\Promise\FulfilledPromise;
8 use WPMailSMTP\Vendor\GuzzleHttp\Promise\PromiseInterface;
9 use WPMailSMTP\Vendor\GuzzleHttp\Psr7;
10 use WPMailSMTP\Vendor\GuzzleHttp\TransferStats;
11 use WPMailSMTP\Vendor\GuzzleHttp\Utils;
12 use WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface;
13 use WPMailSMTP\Vendor\Psr\Http\Message\ResponseInterface;
14 use WPMailSMTP\Vendor\Psr\Http\Message\StreamInterface;
15 /**
16 * HTTP handler that uses PHP's HTTP stream wrapper.
17 */
18 class StreamHandler
19 {
20 private $lastHeaders = [];
21 /**
22 * Sends an HTTP request.
23 *
24 * @param RequestInterface $request Request to send.
25 * @param array $options Request transfer options.
26 *
27 * @return PromiseInterface
28 */
29 public function __invoke(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, array $options)
30 {
31 // Sleep if there is a delay specified.
32 if (isset($options['delay'])) {
33 \usleep($options['delay'] * 1000);
34 }
35 $startTime = isset($options['on_stats']) ? \WPMailSMTP\Vendor\GuzzleHttp\Utils::currentTime() : null;
36 try {
37 // Does not support the expect header.
38 $request = $request->withoutHeader('Expect');
39 // Append a content-length header if body size is zero to match
40 // cURL's behavior.
41 if (0 === $request->getBody()->getSize()) {
42 $request = $request->withHeader('Content-Length', '0');
43 }
44 return $this->createResponse($request, $options, $this->createStream($request, $options), $startTime);
45 } catch (\InvalidArgumentException $e) {
46 throw $e;
47 } catch (\Exception $e) {
48 // Determine if the error was a networking error.
49 $message = $e->getMessage();
50 // This list can probably get more comprehensive.
51 if (\strpos($message, 'getaddrinfo') || \strpos($message, 'Connection refused') || \strpos($message, "couldn't connect to host") || \strpos($message, "connection attempt failed")) {
52 $e = new \WPMailSMTP\Vendor\GuzzleHttp\Exception\ConnectException($e->getMessage(), $request, $e);
53 }
54 $e = \WPMailSMTP\Vendor\GuzzleHttp\Exception\RequestException::wrapException($request, $e);
55 $this->invokeStats($options, $request, $startTime, null, $e);
56 return \WPMailSMTP\Vendor\GuzzleHttp\Promise\rejection_for($e);
57 }
58 }
59 private function invokeStats(array $options, \WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, $startTime, \WPMailSMTP\Vendor\Psr\Http\Message\ResponseInterface $response = null, $error = null)
60 {
61 if (isset($options['on_stats'])) {
62 $stats = new \WPMailSMTP\Vendor\GuzzleHttp\TransferStats($request, $response, \WPMailSMTP\Vendor\GuzzleHttp\Utils::currentTime() - $startTime, $error, []);
63 \call_user_func($options['on_stats'], $stats);
64 }
65 }
66 private function createResponse(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, array $options, $stream, $startTime)
67 {
68 $hdrs = $this->lastHeaders;
69 $this->lastHeaders = [];
70 $parts = \explode(' ', \array_shift($hdrs), 3);
71 $ver = \explode('/', $parts[0])[1];
72 $status = $parts[1];
73 $reason = isset($parts[2]) ? $parts[2] : null;
74 $headers = \WPMailSMTP\Vendor\GuzzleHttp\headers_from_lines($hdrs);
75 list($stream, $headers) = $this->checkDecode($options, $headers, $stream);
76 $stream = \WPMailSMTP\Vendor\GuzzleHttp\Psr7\stream_for($stream);
77 $sink = $stream;
78 if (\strcasecmp('HEAD', $request->getMethod())) {
79 $sink = $this->createSink($stream, $options);
80 }
81 $response = new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\Response($status, $headers, $sink, $ver, $reason);
82 if (isset($options['on_headers'])) {
83 try {
84 $options['on_headers']($response);
85 } catch (\Exception $e) {
86 $msg = 'An error was encountered during the on_headers event';
87 $ex = new \WPMailSMTP\Vendor\GuzzleHttp\Exception\RequestException($msg, $request, $response, $e);
88 return \WPMailSMTP\Vendor\GuzzleHttp\Promise\rejection_for($ex);
89 }
90 }
91 // Do not drain when the request is a HEAD request because they have
92 // no body.
93 if ($sink !== $stream) {
94 $this->drain($stream, $sink, $response->getHeaderLine('Content-Length'));
95 }
96 $this->invokeStats($options, $request, $startTime, $response, null);
97 return new \WPMailSMTP\Vendor\GuzzleHttp\Promise\FulfilledPromise($response);
98 }
99 private function createSink(\WPMailSMTP\Vendor\Psr\Http\Message\StreamInterface $stream, array $options)
100 {
101 if (!empty($options['stream'])) {
102 return $stream;
103 }
104 $sink = isset($options['sink']) ? $options['sink'] : \fopen('php://temp', 'r+');
105 return \is_string($sink) ? new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\LazyOpenStream($sink, 'w+') : \WPMailSMTP\Vendor\GuzzleHttp\Psr7\stream_for($sink);
106 }
107 private function checkDecode(array $options, array $headers, $stream)
108 {
109 // Automatically decode responses when instructed.
110 if (!empty($options['decode_content'])) {
111 $normalizedKeys = \WPMailSMTP\Vendor\GuzzleHttp\normalize_header_keys($headers);
112 if (isset($normalizedKeys['content-encoding'])) {
113 $encoding = $headers[$normalizedKeys['content-encoding']];
114 if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
115 $stream = new \WPMailSMTP\Vendor\GuzzleHttp\Psr7\InflateStream(\WPMailSMTP\Vendor\GuzzleHttp\Psr7\stream_for($stream));
116 $headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']];
117 // Remove content-encoding header
118 unset($headers[$normalizedKeys['content-encoding']]);
119 // Fix content-length header
120 if (isset($normalizedKeys['content-length'])) {
121 $headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];
122 $length = (int) $stream->getSize();
123 if ($length === 0) {
124 unset($headers[$normalizedKeys['content-length']]);
125 } else {
126 $headers[$normalizedKeys['content-length']] = [$length];
127 }
128 }
129 }
130 }
131 }
132 return [$stream, $headers];
133 }
134 /**
135 * Drains the source stream into the "sink" client option.
136 *
137 * @param StreamInterface $source
138 * @param StreamInterface $sink
139 * @param string $contentLength Header specifying the amount of
140 * data to read.
141 *
142 * @return StreamInterface
143 * @throws \RuntimeException when the sink option is invalid.
144 */
145 private function drain(\WPMailSMTP\Vendor\Psr\Http\Message\StreamInterface $source, \WPMailSMTP\Vendor\Psr\Http\Message\StreamInterface $sink, $contentLength)
146 {
147 // If a content-length header is provided, then stop reading once
148 // that number of bytes has been read. This can prevent infinitely
149 // reading from a stream when dealing with servers that do not honor
150 // Connection: Close headers.
151 \WPMailSMTP\Vendor\GuzzleHttp\Psr7\copy_to_stream($source, $sink, \strlen($contentLength) > 0 && (int) $contentLength > 0 ? (int) $contentLength : -1);
152 $sink->seek(0);
153 $source->close();
154 return $sink;
155 }
156 /**
157 * Create a resource and check to ensure it was created successfully
158 *
159 * @param callable $callback Callable that returns stream resource
160 *
161 * @return resource
162 * @throws \RuntimeException on error
163 */
164 private function createResource(callable $callback)
165 {
166 $errors = null;
167 \set_error_handler(function ($_, $msg, $file, $line) use(&$errors) {
168 $errors[] = ['message' => $msg, 'file' => $file, 'line' => $line];
169 return \true;
170 });
171 $resource = $callback();
172 \restore_error_handler();
173 if (!$resource) {
174 $message = 'Error creating resource: ';
175 foreach ($errors as $err) {
176 foreach ($err as $key => $value) {
177 $message .= "[{$key}] {$value}" . \PHP_EOL;
178 }
179 }
180 throw new \RuntimeException(\trim($message));
181 }
182 return $resource;
183 }
184 private function createStream(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, array $options)
185 {
186 static $methods;
187 if (!$methods) {
188 $methods = \array_flip(\get_class_methods(__CLASS__));
189 }
190 // HTTP/1.1 streams using the PHP stream wrapper require a
191 // Connection: close header
192 if ($request->getProtocolVersion() == '1.1' && !$request->hasHeader('Connection')) {
193 $request = $request->withHeader('Connection', 'close');
194 }
195 // Ensure SSL is verified by default
196 if (!isset($options['verify'])) {
197 $options['verify'] = \true;
198 }
199 $params = [];
200 $context = $this->getDefaultContext($request);
201 if (isset($options['on_headers']) && !\is_callable($options['on_headers'])) {
202 throw new \InvalidArgumentException('on_headers must be callable');
203 }
204 if (!empty($options)) {
205 foreach ($options as $key => $value) {
206 $method = "add_{$key}";
207 if (isset($methods[$method])) {
208 $this->{$method}($request, $context, $value, $params);
209 }
210 }
211 }
212 if (isset($options['stream_context'])) {
213 if (!\is_array($options['stream_context'])) {
214 throw new \InvalidArgumentException('stream_context must be an array');
215 }
216 $context = \array_replace_recursive($context, $options['stream_context']);
217 }
218 // Microsoft NTLM authentication only supported with curl handler
219 if (isset($options['auth']) && \is_array($options['auth']) && isset($options['auth'][2]) && 'ntlm' == $options['auth'][2]) {
220 throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
221 }
222 $uri = $this->resolveHost($request, $options);
223 $context = $this->createResource(function () use($context, $params) {
224 return \stream_context_create($context, $params);
225 });
226 return $this->createResource(function () use($uri, &$http_response_header, $context, $options) {
227 $resource = \fopen((string) $uri, 'r', null, $context);
228 $this->lastHeaders = $http_response_header;
229 if (isset($options['read_timeout'])) {
230 $readTimeout = $options['read_timeout'];
231 $sec = (int) $readTimeout;
232 $usec = ($readTimeout - $sec) * 100000;
233 \stream_set_timeout($resource, $sec, $usec);
234 }
235 return $resource;
236 });
237 }
238 private function resolveHost(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, array $options)
239 {
240 $uri = $request->getUri();
241 if (isset($options['force_ip_resolve']) && !\filter_var($uri->getHost(), \FILTER_VALIDATE_IP)) {
242 if ('v4' === $options['force_ip_resolve']) {
243 $records = \dns_get_record($uri->getHost(), \DNS_A);
244 if (!isset($records[0]['ip'])) {
245 throw new \WPMailSMTP\Vendor\GuzzleHttp\Exception\ConnectException(\sprintf("Could not resolve IPv4 address for host '%s'", $uri->getHost()), $request);
246 }
247 $uri = $uri->withHost($records[0]['ip']);
248 } elseif ('v6' === $options['force_ip_resolve']) {
249 $records = \dns_get_record($uri->getHost(), \DNS_AAAA);
250 if (!isset($records[0]['ipv6'])) {
251 throw new \WPMailSMTP\Vendor\GuzzleHttp\Exception\ConnectException(\sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request);
252 }
253 $uri = $uri->withHost('[' . $records[0]['ipv6'] . ']');
254 }
255 }
256 return $uri;
257 }
258 private function getDefaultContext(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request)
259 {
260 $headers = '';
261 foreach ($request->getHeaders() as $name => $value) {
262 foreach ($value as $val) {
263 $headers .= "{$name}: {$val}\r\n";
264 }
265 }
266 $context = ['http' => ['method' => $request->getMethod(), 'header' => $headers, 'protocol_version' => $request->getProtocolVersion(), 'ignore_errors' => \true, 'follow_location' => 0]];
267 $body = (string) $request->getBody();
268 if (!empty($body)) {
269 $context['http']['content'] = $body;
270 // Prevent the HTTP handler from adding a Content-Type header.
271 if (!$request->hasHeader('Content-Type')) {
272 $context['http']['header'] .= "Content-Type:\r\n";
273 }
274 }
275 $context['http']['header'] = \rtrim($context['http']['header']);
276 return $context;
277 }
278 private function add_proxy(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, &$options, $value, &$params)
279 {
280 if (!\is_array($value)) {
281 $options['http']['proxy'] = $value;
282 } else {
283 $scheme = $request->getUri()->getScheme();
284 if (isset($value[$scheme])) {
285 if (!isset($value['no']) || !\WPMailSMTP\Vendor\GuzzleHttp\is_host_in_noproxy($request->getUri()->getHost(), $value['no'])) {
286 $options['http']['proxy'] = $value[$scheme];
287 }
288 }
289 }
290 }
291 private function add_timeout(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, &$options, $value, &$params)
292 {
293 if ($value > 0) {
294 $options['http']['timeout'] = $value;
295 }
296 }
297 private function add_verify(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, &$options, $value, &$params)
298 {
299 if ($value === \true) {
300 // PHP 5.6 or greater will find the system cert by default. When
301 // < 5.6, use the Guzzle bundled cacert.
302 if (\PHP_VERSION_ID < 50600) {
303 $options['ssl']['cafile'] = \WPMailSMTP\Vendor\GuzzleHttp\default_ca_bundle();
304 }
305 } elseif (\is_string($value)) {
306 $options['ssl']['cafile'] = $value;
307 if (!\file_exists($value)) {
308 throw new \RuntimeException("SSL CA bundle not found: {$value}");
309 }
310 } elseif ($value === \false) {
311 $options['ssl']['verify_peer'] = \false;
312 $options['ssl']['verify_peer_name'] = \false;
313 return;
314 } else {
315 throw new \InvalidArgumentException('Invalid verify request option');
316 }
317 $options['ssl']['verify_peer'] = \true;
318 $options['ssl']['verify_peer_name'] = \true;
319 $options['ssl']['allow_self_signed'] = \false;
320 }
321 private function add_cert(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, &$options, $value, &$params)
322 {
323 if (\is_array($value)) {
324 $options['ssl']['passphrase'] = $value[1];
325 $value = $value[0];
326 }
327 if (!\file_exists($value)) {
328 throw new \RuntimeException("SSL certificate not found: {$value}");
329 }
330 $options['ssl']['local_cert'] = $value;
331 }
332 private function add_progress(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, &$options, $value, &$params)
333 {
334 $this->addNotification($params, function ($code, $a, $b, $c, $transferred, $total) use($value) {
335 if ($code == \STREAM_NOTIFY_PROGRESS) {
336 $value($total, $transferred, null, null);
337 }
338 });
339 }
340 private function add_debug(\WPMailSMTP\Vendor\Psr\Http\Message\RequestInterface $request, &$options, $value, &$params)
341 {
342 if ($value === \false) {
343 return;
344 }
345 static $map = [\STREAM_NOTIFY_CONNECT => 'CONNECT', \STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED', \STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT', \STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS', \STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS', \STREAM_NOTIFY_REDIRECTED => 'REDIRECTED', \STREAM_NOTIFY_PROGRESS => 'PROGRESS', \STREAM_NOTIFY_FAILURE => 'FAILURE', \STREAM_NOTIFY_COMPLETED => 'COMPLETED', \STREAM_NOTIFY_RESOLVE => 'RESOLVE'];
346 static $args = ['severity', 'message', 'message_code', 'bytes_transferred', 'bytes_max'];
347 $value = \WPMailSMTP\Vendor\GuzzleHttp\debug_resource($value);
348 $ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
349 $this->addNotification($params, function () use($ident, $value, $map, $args) {
350 $passed = \func_get_args();
351 $code = \array_shift($passed);
352 \fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
353 foreach (\array_filter($passed) as $i => $v) {
354 \fwrite($value, $args[$i] . ': "' . $v . '" ');
355 }
356 \fwrite($value, "\n");
357 });
358 }
359 private function addNotification(array &$params, callable $notify)
360 {
361 // Wrap the existing function if needed.
362 if (!isset($params['notification'])) {
363 $params['notification'] = $notify;
364 } else {
365 $params['notification'] = $this->callArray([$params['notification'], $notify]);
366 }
367 }
368 private function callArray(array $functions)
369 {
370 return function () use($functions) {
371 $args = \func_get_args();
372 foreach ($functions as $fn) {
373 \call_user_func_array($fn, $args);
374 }
375 };
376 }
377 }
378