~ballot/wordpress/openstack-objectstorage-bis

« back to all changes in this revision

Viewing changes to vendor/guzzlehttp/guzzle/src/Adapter/Curl/CurlAdapter.php

  • Committer: Thomas Cuthbert
  • Date: 2020-04-23 05:22:45 UTC
  • Revision ID: thomas.cuthbert@canonical.com-20200423052245-1jxao3mw31w435js
[,r=trivial] bionic composer vendor update

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<?php
2
 
 
3
 
namespace GuzzleHttp\Adapter\Curl;
4
 
 
5
 
use GuzzleHttp\Adapter\AdapterInterface;
6
 
use GuzzleHttp\Adapter\TransactionInterface;
7
 
use GuzzleHttp\Event\RequestEvents;
8
 
use GuzzleHttp\Exception\AdapterException;
9
 
use GuzzleHttp\Message\MessageFactoryInterface;
10
 
 
11
 
/**
12
 
 * HTTP adapter that uses cURL easy handles as a transport layer.
13
 
 *
14
 
 * Requires PHP 5.5+
15
 
 *
16
 
 * When using the CurlAdapter, custom curl options can be specified as an
17
 
 * associative array of curl option constants mapping to values in the
18
 
 * **curl** key of a request's configuration options.
19
 
 */
20
 
class CurlAdapter implements AdapterInterface
21
 
{
22
 
    /** @var CurlFactory */
23
 
    private $curlFactory;
24
 
 
25
 
    /** @var MessageFactoryInterface */
26
 
    private $messageFactory;
27
 
 
28
 
    /** @var array Array of curl easy handles */
29
 
    private $handles = [];
30
 
 
31
 
    /** @var array Array of owned curl easy handles */
32
 
    private $ownedHandles = [];
33
 
 
34
 
    /** @var int Total number of idle handles to keep in cache */
35
 
    private $maxHandles;
36
 
 
37
 
    /**
38
 
     * Accepts an associative array of options:
39
 
     *
40
 
     * - handle_factory: Optional callable factory used to create cURL handles.
41
 
     *   The callable is invoked with the following arguments:
42
 
     *   TransactionInterface, MessageFactoryInterface, and an optional cURL
43
 
     *   handle to modify. The factory method must then return a cURL resource.
44
 
     * - max_handles: Maximum number of idle handles (defaults to 5).
45
 
     *
46
 
     * @param MessageFactoryInterface $messageFactory
47
 
     * @param array $options Array of options to use with the adapter
48
 
     */
49
 
    public function __construct(
50
 
        MessageFactoryInterface $messageFactory,
51
 
        array $options = []
52
 
    ) {
53
 
        $this->handles = $this->ownedHandles = [];
54
 
        $this->messageFactory = $messageFactory;
55
 
        $this->curlFactory = isset($options['handle_factory'])
56
 
            ? $options['handle_factory']
57
 
            : new CurlFactory();
58
 
        $this->maxHandles = isset($options['max_handles'])
59
 
            ? $options['max_handles']
60
 
            : 5;
61
 
    }
62
 
 
63
 
    public function __destruct()
64
 
    {
65
 
        foreach ($this->handles as $handle) {
66
 
            if (is_resource($handle)) {
67
 
                curl_close($handle);
68
 
            }
69
 
        }
70
 
    }
71
 
 
72
 
    public function send(TransactionInterface $transaction)
73
 
    {
74
 
        RequestEvents::emitBefore($transaction);
75
 
        if ($response = $transaction->getResponse()) {
76
 
            return $response;
77
 
        }
78
 
 
79
 
        $factory = $this->curlFactory;
80
 
        $handle = $factory(
81
 
            $transaction,
82
 
            $this->messageFactory,
83
 
            $this->checkoutEasyHandle()
84
 
        );
85
 
 
86
 
        curl_exec($handle);
87
 
        $info = curl_getinfo($handle);
88
 
        $info['curl_result'] = curl_errno($handle);
89
 
 
90
 
        if ($info['curl_result']) {
91
 
            $this->handleError($transaction, $info, $handle);
92
 
        } else {
93
 
            $this->releaseEasyHandle($handle);
94
 
            if ($body = $transaction->getResponse()->getBody()) {
95
 
                $body->seek(0);
96
 
            }
97
 
            RequestEvents::emitComplete($transaction, $info);
98
 
        }
99
 
 
100
 
        return $transaction->getResponse();
101
 
    }
102
 
 
103
 
    private function handleError(
104
 
        TransactionInterface $transaction,
105
 
        $info,
106
 
        $handle
107
 
    ) {
108
 
        $error = curl_error($handle);
109
 
        $this->releaseEasyHandle($handle);
110
 
        RequestEvents::emitError(
111
 
            $transaction,
112
 
            new AdapterException("cURL error {$info['curl_result']}: {$error}"),
113
 
            $info
114
 
        );
115
 
    }
116
 
 
117
 
    private function checkoutEasyHandle()
118
 
    {
119
 
        // Find an unused handle in the cache
120
 
        if (false !== ($key = array_search(false, $this->ownedHandles, true))) {
121
 
            $this->ownedHandles[$key] = true;
122
 
            return $this->handles[$key];
123
 
        }
124
 
 
125
 
        // Add a new handle
126
 
        $handle = curl_init();
127
 
        $id = (int) $handle;
128
 
        $this->handles[$id] = $handle;
129
 
        $this->ownedHandles[$id] = true;
130
 
 
131
 
        return $handle;
132
 
    }
133
 
 
134
 
    private function releaseEasyHandle($handle)
135
 
    {
136
 
        $id = (int) $handle;
137
 
        if (count($this->ownedHandles) > $this->maxHandles) {
138
 
            curl_close($this->handles[$id]);
139
 
            unset($this->handles[$id], $this->ownedHandles[$id]);
140
 
        } else {
141
 
            // curl_reset doesn't clear these out for some reason
142
 
            curl_setopt_array($handle, [
143
 
                CURLOPT_HEADERFUNCTION   => null,
144
 
                CURLOPT_WRITEFUNCTION    => null,
145
 
                CURLOPT_READFUNCTION     => null,
146
 
                CURLOPT_PROGRESSFUNCTION => null
147
 
            ]);
148
 
            curl_reset($handle);
149
 
            $this->ownedHandles[$id] = false;
150
 
        }
151
 
    }
152
 
}