~ballot/wordpress/openstack-objectstorage-bis

« back to all changes in this revision

Viewing changes to vendor/guzzlehttp/guzzle/src/Client.php

  • Committer: Jacek Nykis
  • Date: 2015-02-11 15:35:31 UTC
  • Revision ID: jacek.nykis@canonical.com-20150211153531-hmy6zi0ov2qfkl0b
Initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
 
 
3
namespace GuzzleHttp;
 
4
 
 
5
use GuzzleHttp\Adapter\AdapterInterface;
 
6
use GuzzleHttp\Adapter\Curl\CurlAdapter;
 
7
use GuzzleHttp\Adapter\Curl\MultiAdapter;
 
8
use GuzzleHttp\Adapter\FakeParallelAdapter;
 
9
use GuzzleHttp\Adapter\ParallelAdapterInterface;
 
10
use GuzzleHttp\Adapter\StreamAdapter;
 
11
use GuzzleHttp\Adapter\StreamingProxyAdapter;
 
12
use GuzzleHttp\Adapter\Transaction;
 
13
use GuzzleHttp\Adapter\TransactionIterator;
 
14
use GuzzleHttp\Event\HasEmitterTrait;
 
15
use GuzzleHttp\Exception\RequestException;
 
16
use GuzzleHttp\Message\MessageFactory;
 
17
use GuzzleHttp\Message\MessageFactoryInterface;
 
18
use GuzzleHttp\Message\RequestInterface;
 
19
 
 
20
/**
 
21
 * HTTP client
 
22
 */
 
23
class Client implements ClientInterface
 
24
{
 
25
    use HasEmitterTrait;
 
26
 
 
27
    const DEFAULT_CONCURRENCY = 25;
 
28
 
 
29
    /** @var MessageFactoryInterface Request factory used by the client */
 
30
    private $messageFactory;
 
31
 
 
32
    /** @var AdapterInterface */
 
33
    private $adapter;
 
34
 
 
35
    /** @var ParallelAdapterInterface */
 
36
    private $parallelAdapter;
 
37
 
 
38
    /** @var Url Base URL of the client */
 
39
    private $baseUrl;
 
40
 
 
41
    /** @var array Default request options */
 
42
    private $defaults;
 
43
 
 
44
    /**
 
45
     * Clients accept an array of constructor parameters.
 
46
     *
 
47
     * Here's an example of creating a client using an URI template for the
 
48
     * client's base_url and an array of default request options to apply
 
49
     * to each request:
 
50
     *
 
51
     *     $client = new Client([
 
52
     *         'base_url' => [
 
53
     *              'http://www.foo.com/{version}/',
 
54
     *              ['version' => '123']
 
55
     *          ],
 
56
     *         'defaults' => [
 
57
     *             'timeout'         => 10,
 
58
     *             'allow_redirects' => false,
 
59
     *             'proxy'           => '192.168.16.1:10'
 
60
     *         ]
 
61
     *     ]);
 
62
     *
 
63
     * @param array $config Client configuration settings
 
64
     *     - base_url: Base URL of the client that is merged into relative URLs.
 
65
     *       Can be a string or an array that contains a URI template followed
 
66
     *       by an associative array of expansion variables to inject into the
 
67
     *       URI template.
 
68
     *     - adapter: Adapter used to transfer requests
 
69
     *     - parallel_adapter: Adapter used to transfer requests in parallel
 
70
     *     - message_factory: Factory used to create request and response object
 
71
     *     - defaults: Default request options to apply to each request
 
72
     *     - emitter: Event emitter used for request events
 
73
     */
 
74
    public function __construct(array $config = [])
 
75
    {
 
76
        $this->configureBaseUrl($config);
 
77
        $this->configureDefaults($config);
 
78
        $this->configureAdapter($config);
 
79
        if (isset($config['emitter'])) {
 
80
            $this->emitter = $config['emitter'];
 
81
        }
 
82
    }
 
83
 
 
84
    /**
 
85
     * Get the default User-Agent string to use with Guzzle
 
86
     *
 
87
     * @return string
 
88
     */
 
89
    public static function getDefaultUserAgent()
 
90
    {
 
91
        static $defaultAgent = '';
 
92
        if (!$defaultAgent) {
 
93
            $defaultAgent = 'Guzzle/' . self::VERSION;
 
94
            if (extension_loaded('curl')) {
 
95
                $defaultAgent .= ' curl/' . curl_version()['version'];
 
96
            }
 
97
            $defaultAgent .= ' PHP/' . PHP_VERSION;
 
98
        }
 
99
 
 
100
        return $defaultAgent;
 
101
    }
 
102
 
 
103
    public function __call($name, $arguments)
 
104
    {
 
105
        return \GuzzleHttp\deprecation_proxy(
 
106
            $this,
 
107
            $name,
 
108
            $arguments,
 
109
            ['getEventDispatcher' => 'getEmitter']
 
110
        );
 
111
    }
 
112
 
 
113
    public function getDefaultOption($keyOrPath = null)
 
114
    {
 
115
        return $keyOrPath === null
 
116
            ? $this->defaults
 
117
            : \GuzzleHttp\get_path($this->defaults, $keyOrPath);
 
118
    }
 
119
 
 
120
    public function setDefaultOption($keyOrPath, $value)
 
121
    {
 
122
        \GuzzleHttp\set_path($this->defaults, $keyOrPath, $value);
 
123
    }
 
124
 
 
125
    public function getBaseUrl()
 
126
    {
 
127
        return (string) $this->baseUrl;
 
128
    }
 
129
 
 
130
    public function createRequest($method, $url = null, array $options = [])
 
131
    {
 
132
        $headers = $this->mergeDefaults($options);
 
133
        // Use a clone of the client's emitter
 
134
        $options['config']['emitter'] = clone $this->getEmitter();
 
135
 
 
136
        $request = $this->messageFactory->createRequest(
 
137
            $method,
 
138
            $url ? (string) $this->buildUrl($url) : (string) $this->baseUrl,
 
139
            $options
 
140
        );
 
141
 
 
142
        // Merge in default headers
 
143
        if ($headers) {
 
144
            foreach ($headers as $key => $value) {
 
145
                if (!$request->hasHeader($key)) {
 
146
                    $request->setHeader($key, $value);
 
147
                }
 
148
            }
 
149
        }
 
150
 
 
151
        return $request;
 
152
    }
 
153
 
 
154
    public function get($url = null, $options = [])
 
155
    {
 
156
        return $this->send($this->createRequest('GET', $url, $options));
 
157
    }
 
158
 
 
159
    public function head($url = null, array $options = [])
 
160
    {
 
161
        return $this->send($this->createRequest('HEAD', $url, $options));
 
162
    }
 
163
 
 
164
    public function delete($url = null, array $options = [])
 
165
    {
 
166
        return $this->send($this->createRequest('DELETE', $url, $options));
 
167
    }
 
168
 
 
169
    public function put($url = null, array $options = [])
 
170
    {
 
171
        return $this->send($this->createRequest('PUT', $url, $options));
 
172
    }
 
173
 
 
174
    public function patch($url = null, array $options = [])
 
175
    {
 
176
        return $this->send($this->createRequest('PATCH', $url, $options));
 
177
    }
 
178
 
 
179
    public function post($url = null, array $options = [])
 
180
    {
 
181
        return $this->send($this->createRequest('POST', $url, $options));
 
182
    }
 
183
 
 
184
    public function options($url = null, array $options = [])
 
185
    {
 
186
        return $this->send($this->createRequest('OPTIONS', $url, $options));
 
187
    }
 
188
 
 
189
    public function send(RequestInterface $request)
 
190
    {
 
191
        $transaction = new Transaction($this, $request);
 
192
        try {
 
193
            if ($response = $this->adapter->send($transaction)) {
 
194
                return $response;
 
195
            }
 
196
            throw new \LogicException('No response was associated with the transaction');
 
197
        } catch (RequestException $e) {
 
198
            throw $e;
 
199
        } catch (\Exception $e) {
 
200
            // Wrap exceptions in a RequestException to adhere to the interface
 
201
            throw new RequestException($e->getMessage(), $request, null, $e);
 
202
        }
 
203
    }
 
204
 
 
205
    public function sendAll($requests, array $options = [])
 
206
    {
 
207
        if (!($requests instanceof TransactionIterator)) {
 
208
            $requests = new TransactionIterator($requests, $this, $options);
 
209
        }
 
210
 
 
211
        $this->parallelAdapter->sendAll(
 
212
            $requests,
 
213
            isset($options['parallel'])
 
214
                ? $options['parallel']
 
215
                : self::DEFAULT_CONCURRENCY
 
216
        );
 
217
    }
 
218
 
 
219
    /**
 
220
     * Get an array of default options to apply to the client
 
221
     *
 
222
     * @return array
 
223
     */
 
224
    protected function getDefaultOptions()
 
225
    {
 
226
        $settings = [
 
227
            'allow_redirects' => true,
 
228
            'exceptions'      => true,
 
229
            'decode_content'  => true,
 
230
            'verify'          => __DIR__ . '/cacert.pem'
 
231
        ];
 
232
 
 
233
        // Use the bundled cacert if it is a regular file, or set to true if
 
234
        // using a phar file (because curL and the stream wrapper can't read
 
235
        // cacerts from the phar stream wrapper). Favor the ini setting over
 
236
        // the system's cacert.
 
237
        if (substr(__FILE__, 0, 7) == 'phar://') {
 
238
            $settings['verify'] = ini_get('openssl.cafile') ?: true;
 
239
        }
 
240
 
 
241
        // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set
 
242
        if ($proxy = getenv('HTTP_PROXY')) {
 
243
            $settings['proxy']['http'] = $proxy;
 
244
        }
 
245
 
 
246
        if ($proxy = getenv('HTTPS_PROXY')) {
 
247
            $settings['proxy']['https'] = $proxy;
 
248
        }
 
249
 
 
250
        return $settings;
 
251
    }
 
252
 
 
253
    /**
 
254
     * Expand a URI template and inherit from the base URL if it's relative
 
255
     *
 
256
     * @param string|array $url URL or URI template to expand
 
257
     *
 
258
     * @return string
 
259
     */
 
260
    private function buildUrl($url)
 
261
    {
 
262
        if (!is_array($url)) {
 
263
            if (strpos($url, '://')) {
 
264
                return (string) $url;
 
265
            }
 
266
            return (string) $this->baseUrl->combine($url);
 
267
        } elseif (strpos($url[0], '://')) {
 
268
            return \GuzzleHttp\uri_template($url[0], $url[1]);
 
269
        }
 
270
 
 
271
        return (string) $this->baseUrl->combine(
 
272
            \GuzzleHttp\uri_template($url[0], $url[1])
 
273
        );
 
274
    }
 
275
 
 
276
    /**
 
277
     * Get a default parallel adapter to use based on the environment
 
278
     *
 
279
     * @return ParallelAdapterInterface
 
280
     */
 
281
    private function getDefaultParallelAdapter()
 
282
    {
 
283
        return extension_loaded('curl')
 
284
            ? new MultiAdapter($this->messageFactory)
 
285
            : new FakeParallelAdapter($this->adapter);
 
286
    }
 
287
 
 
288
    /**
 
289
     * Create a default adapter to use based on the environment
 
290
     * @throws \RuntimeException
 
291
     */
 
292
    private function getDefaultAdapter()
 
293
    {
 
294
        if (extension_loaded('curl')) {
 
295
            $this->parallelAdapter = new MultiAdapter($this->messageFactory);
 
296
            $this->adapter = function_exists('curl_reset')
 
297
                ? new CurlAdapter($this->messageFactory)
 
298
                : $this->parallelAdapter;
 
299
            if (ini_get('allow_url_fopen')) {
 
300
                $this->adapter = new StreamingProxyAdapter(
 
301
                    $this->adapter,
 
302
                    new StreamAdapter($this->messageFactory)
 
303
                );
 
304
            }
 
305
        } elseif (ini_get('allow_url_fopen')) {
 
306
            $this->adapter = new StreamAdapter($this->messageFactory);
 
307
        } else {
 
308
            throw new \RuntimeException('Guzzle requires cURL, the '
 
309
                . 'allow_url_fopen ini setting, or a custom HTTP adapter.');
 
310
        }
 
311
    }
 
312
 
 
313
    private function configureBaseUrl(&$config)
 
314
    {
 
315
        if (!isset($config['base_url'])) {
 
316
            $this->baseUrl = new Url('', '');
 
317
        } elseif (is_array($config['base_url'])) {
 
318
            $this->baseUrl = Url::fromString(
 
319
                \GuzzleHttp\uri_template(
 
320
                    $config['base_url'][0],
 
321
                    $config['base_url'][1]
 
322
                )
 
323
            );
 
324
            $config['base_url'] = (string) $this->baseUrl;
 
325
        } else {
 
326
            $this->baseUrl = Url::fromString($config['base_url']);
 
327
        }
 
328
    }
 
329
 
 
330
    private function configureDefaults($config)
 
331
    {
 
332
        if (!isset($config['defaults'])) {
 
333
            $this->defaults = $this->getDefaultOptions();
 
334
        } else {
 
335
            $this->defaults = array_replace(
 
336
                $this->getDefaultOptions(),
 
337
                $config['defaults']
 
338
            );
 
339
        }
 
340
 
 
341
        // Add the default user-agent header
 
342
        if (!isset($this->defaults['headers'])) {
 
343
            $this->defaults['headers'] = [
 
344
                'User-Agent' => static::getDefaultUserAgent()
 
345
            ];
 
346
        } elseif (!isset(array_change_key_case($this->defaults['headers'])['user-agent'])) {
 
347
            // Add the User-Agent header if one was not already set
 
348
            $this->defaults['headers']['User-Agent'] = static::getDefaultUserAgent();
 
349
        }
 
350
    }
 
351
 
 
352
    private function configureAdapter(&$config)
 
353
    {
 
354
        if (isset($config['message_factory'])) {
 
355
            $this->messageFactory = $config['message_factory'];
 
356
        } else {
 
357
            $this->messageFactory = new MessageFactory();
 
358
        }
 
359
        if (isset($config['adapter'])) {
 
360
            $this->adapter = $config['adapter'];
 
361
        } else {
 
362
            $this->getDefaultAdapter();
 
363
        }
 
364
        // If no parallel adapter was explicitly provided and one was not
 
365
        // defaulted when creating the default adapter, then create one now.
 
366
        if (isset($config['parallel_adapter'])) {
 
367
            $this->parallelAdapter = $config['parallel_adapter'];
 
368
        } elseif (!$this->parallelAdapter) {
 
369
            $this->parallelAdapter = $this->getDefaultParallelAdapter();
 
370
        }
 
371
    }
 
372
 
 
373
    /**
 
374
     * Merges default options into the array passed by reference and returns
 
375
     * an array of headers that need to be merged in after the request is
 
376
     * created.
 
377
     *
 
378
     * @param array $options Options to modify by reference
 
379
     *
 
380
     * @return array|null
 
381
     */
 
382
    private function mergeDefaults(&$options)
 
383
    {
 
384
        // Merging optimization for when no headers are present
 
385
        if (!isset($options['headers'])
 
386
            || !isset($this->defaults['headers'])) {
 
387
            $options = array_replace_recursive($this->defaults, $options);
 
388
            return null;
 
389
        }
 
390
 
 
391
        $defaults = $this->defaults;
 
392
        unset($defaults['headers']);
 
393
        $options = array_replace_recursive($defaults, $options);
 
394
 
 
395
        return $this->defaults['headers'];
 
396
    }
 
397
}