~ballot/wordpress/openstack-objectstorage-bis

« back to all changes in this revision

Viewing changes to vendor/guzzlehttp/guzzle/src/Message/MessageFactory.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
 
namespace GuzzleHttp\Message;
3
 
 
4
 
use GuzzleHttp\Cookie\CookieJar;
5
 
use GuzzleHttp\Cookie\CookieJarInterface;
6
 
use GuzzleHttp\Event\ListenerAttacherTrait;
7
 
use GuzzleHttp\Post\PostBody;
8
 
use GuzzleHttp\Post\PostFile;
9
 
use GuzzleHttp\Post\PostFileInterface;
10
 
use GuzzleHttp\Query;
11
 
use GuzzleHttp\Stream\Stream;
12
 
use GuzzleHttp\Subscriber\Cookie;
13
 
use GuzzleHttp\Subscriber\HttpError;
14
 
use GuzzleHttp\Subscriber\Redirect;
15
 
use GuzzleHttp\Url;
16
 
 
17
 
/**
18
 
 * Default HTTP request factory used to create Request and Response objects.
19
 
 */
20
 
class MessageFactory implements MessageFactoryInterface
21
 
{
22
 
    use ListenerAttacherTrait;
23
 
 
24
 
    /** @var HttpError */
25
 
    private $errorPlugin;
26
 
 
27
 
    /** @var Redirect */
28
 
    private $redirectPlugin;
29
 
 
30
 
    /** @var array */
31
 
    protected static $classMethods = [];
32
 
 
33
 
    public function __construct()
34
 
    {
35
 
        $this->errorPlugin = new HttpError();
36
 
        $this->redirectPlugin = new Redirect();
37
 
    }
38
 
 
39
 
    public function createResponse(
40
 
        $statusCode,
41
 
        array $headers = [],
42
 
        $body = null,
43
 
        array $options = []
44
 
    ) {
45
 
        if (null !== $body) {
46
 
            $body = Stream::factory($body);
47
 
        }
48
 
 
49
 
        return new Response($statusCode, $headers, $body, $options);
50
 
    }
51
 
 
52
 
    public function createRequest($method, $url, array $options = [])
53
 
    {
54
 
        // Handle the request protocol version option that needs to be
55
 
        // specified in the request constructor.
56
 
        if (isset($options['version'])) {
57
 
            $options['config']['protocol_version'] = $options['version'];
58
 
            unset($options['version']);
59
 
        }
60
 
 
61
 
        $request = new Request($method, $url, [], null,
62
 
            isset($options['config']) ? $options['config'] : []);
63
 
 
64
 
        unset($options['config']);
65
 
 
66
 
        // Use a POST body by default
67
 
        if ($method == 'POST' &&
68
 
            !isset($options['body']) &&
69
 
            !isset($options['json'])
70
 
        ) {
71
 
            $options['body'] = [];
72
 
        }
73
 
 
74
 
        if ($options) {
75
 
            $this->applyOptions($request, $options);
76
 
        }
77
 
 
78
 
        return $request;
79
 
    }
80
 
 
81
 
    /**
82
 
     * Create a request or response object from an HTTP message string
83
 
     *
84
 
     * @param string $message Message to parse
85
 
     *
86
 
     * @return RequestInterface|ResponseInterface
87
 
     * @throws \InvalidArgumentException if unable to parse a message
88
 
     */
89
 
    public function fromMessage($message)
90
 
    {
91
 
        static $parser;
92
 
        if (!$parser) {
93
 
            $parser = new MessageParser();
94
 
        }
95
 
 
96
 
        // Parse a response
97
 
        if (strtoupper(substr($message, 0, 4)) == 'HTTP') {
98
 
            $data = $parser->parseResponse($message);
99
 
            return $this->createResponse(
100
 
                $data['code'],
101
 
                $data['headers'],
102
 
                $data['body'] === '' ? null : $data['body'],
103
 
                $data
104
 
            );
105
 
        }
106
 
 
107
 
        // Parse a request
108
 
        if (!($data = ($parser->parseRequest($message)))) {
109
 
            throw new \InvalidArgumentException('Unable to parse request');
110
 
        }
111
 
 
112
 
        return $this->createRequest(
113
 
            $data['method'],
114
 
            Url::buildUrl($data['request_url']),
115
 
            [
116
 
                'headers' => $data['headers'],
117
 
                'body' => $data['body'] === '' ? null : $data['body'],
118
 
                'config' => [
119
 
                    'protocol_version' => $data['protocol_version']
120
 
                ]
121
 
            ]
122
 
        );
123
 
    }
124
 
 
125
 
    /**
126
 
     * Apply POST fields and files to a request to attempt to give an accurate
127
 
     * representation.
128
 
     *
129
 
     * @param RequestInterface $request Request to update
130
 
     * @param array            $body    Body to apply
131
 
     */
132
 
    protected function addPostData(RequestInterface $request, array $body)
133
 
    {
134
 
        static $fields = ['string' => true, 'array' => true, 'NULL' => true,
135
 
            'boolean' => true, 'double' => true, 'integer' => true];
136
 
 
137
 
        $post = new PostBody();
138
 
        foreach ($body as $key => $value) {
139
 
            if (isset($fields[gettype($value)])) {
140
 
                $post->setField($key, $value);
141
 
            } elseif ($value instanceof PostFileInterface) {
142
 
                $post->addFile($value);
143
 
            } else {
144
 
                $post->addFile(new PostFile($key, $value));
145
 
            }
146
 
        }
147
 
 
148
 
        if ($request->getHeader('Content-Type') == 'multipart/form-data') {
149
 
            $post->forceMultipartUpload(true);
150
 
        }
151
 
 
152
 
        $request->setBody($post);
153
 
    }
154
 
 
155
 
    protected function applyOptions(
156
 
        RequestInterface $request,
157
 
        array $options = []
158
 
    ) {
159
 
        // Values specified in the config map are passed to request options
160
 
        static $configMap = ['connect_timeout' => 1, 'timeout' => 1,
161
 
            'verify' => 1, 'ssl_key' => 1, 'cert' => 1, 'proxy' => 1,
162
 
            'debug' => 1, 'save_to' => 1, 'stream' => 1, 'expect' => 1];
163
 
 
164
 
        // Take the class of the instance, not the parent
165
 
        $selfClass = get_class($this);
166
 
 
167
 
        // Check if we already took it's class methods and had them saved
168
 
        if (!isset(self::$classMethods[$selfClass])) {
169
 
            self::$classMethods[$selfClass] = array_flip(get_class_methods($this));
170
 
        }
171
 
 
172
 
        // Take class methods of this particular instance
173
 
        $methods = self::$classMethods[$selfClass];
174
 
 
175
 
        // Iterate over each key value pair and attempt to apply a config using
176
 
        // double dispatch.
177
 
        $config = $request->getConfig();
178
 
        foreach ($options as $key => $value) {
179
 
            $method = "add_{$key}";
180
 
            if (isset($methods[$method])) {
181
 
                $this->{$method}($request, $value);
182
 
            } elseif (isset($configMap[$key])) {
183
 
                $config[$key] = $value;
184
 
            } else {
185
 
                throw new \InvalidArgumentException("No method is configured "
186
 
                    . "to handle the {$key} config key");
187
 
            }
188
 
        }
189
 
    }
190
 
 
191
 
    private function add_body(RequestInterface $request, $value)
192
 
    {
193
 
        if ($value !== null) {
194
 
            if (is_array($value)) {
195
 
                $this->addPostData($request, $value);
196
 
            } else {
197
 
                $request->setBody(Stream::factory($value));
198
 
            }
199
 
        }
200
 
    }
201
 
 
202
 
    private function add_allow_redirects(RequestInterface $request, $value)
203
 
    {
204
 
        static $defaultRedirect = [
205
 
            'max'     => 5,
206
 
            'strict'  => false,
207
 
            'referer' => false
208
 
        ];
209
 
 
210
 
        if ($value === false) {
211
 
            return;
212
 
        }
213
 
 
214
 
        if ($value === true) {
215
 
            $value = $defaultRedirect;
216
 
        } elseif (!isset($value['max'])) {
217
 
            throw new \InvalidArgumentException('allow_redirects must be '
218
 
                . 'true, false, or an array that contains the \'max\' key');
219
 
        } else {
220
 
            // Merge the default settings with the provided settings
221
 
            $value += $defaultRedirect;
222
 
        }
223
 
 
224
 
        $request->getConfig()['redirect'] = $value;
225
 
        $request->getEmitter()->attach($this->redirectPlugin);
226
 
    }
227
 
 
228
 
    private function add_exceptions(RequestInterface $request, $value)
229
 
    {
230
 
        if ($value === true) {
231
 
            $request->getEmitter()->attach($this->errorPlugin);
232
 
        }
233
 
    }
234
 
 
235
 
    private function add_auth(RequestInterface $request, $value)
236
 
    {
237
 
        if (!$value) {
238
 
            return;
239
 
        } elseif (is_array($value)) {
240
 
            $authType = isset($value[2]) ? strtolower($value[2]) : 'basic';
241
 
        } else {
242
 
            $authType = strtolower($value);
243
 
        }
244
 
 
245
 
        $request->getConfig()->set('auth', $value);
246
 
 
247
 
        if ($authType == 'basic') {
248
 
            $request->setHeader(
249
 
                'Authorization',
250
 
                'Basic ' . base64_encode("$value[0]:$value[1]")
251
 
            );
252
 
        } elseif ($authType == 'digest') {
253
 
            // Currently only implemented by the cURL adapter.
254
 
            // @todo: Need an event listener solution that does not rely on cURL
255
 
            $config = $request->getConfig();
256
 
            $config->setPath('curl/' . CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
257
 
            $config->setPath('curl/' . CURLOPT_USERPWD, "$value[0]:$value[1]");
258
 
        }
259
 
    }
260
 
 
261
 
    private function add_query(RequestInterface $request, $value)
262
 
    {
263
 
        if ($value instanceof Query) {
264
 
            $original = $request->getQuery();
265
 
            // Do not overwrite existing query string variables by overwriting
266
 
            // the object with the query string data passed in the URL
267
 
            $request->setQuery($value->overwriteWith($original->toArray()));
268
 
        } elseif (is_array($value)) {
269
 
            // Do not overwrite existing query string variables
270
 
            $query = $request->getQuery();
271
 
            foreach ($value as $k => $v) {
272
 
                if (!isset($query[$k])) {
273
 
                    $query[$k] = $v;
274
 
                }
275
 
            }
276
 
        } else {
277
 
            throw new \InvalidArgumentException('query value must be an array '
278
 
                . 'or Query object');
279
 
        }
280
 
    }
281
 
 
282
 
    private function add_headers(RequestInterface $request, $value)
283
 
    {
284
 
        if (!is_array($value)) {
285
 
            throw new \InvalidArgumentException('header value must be an array');
286
 
        }
287
 
 
288
 
        // Do not overwrite existing headers
289
 
        foreach ($value as $k => $v) {
290
 
            if (!$request->hasHeader($k)) {
291
 
                $request->setHeader($k, $v);
292
 
            }
293
 
        }
294
 
    }
295
 
 
296
 
    private function add_cookies(RequestInterface $request, $value)
297
 
    {
298
 
        if ($value === true) {
299
 
            static $cookie = null;
300
 
            if (!$cookie) {
301
 
                $cookie = new Cookie();
302
 
            }
303
 
            $request->getEmitter()->attach($cookie);
304
 
        } elseif (is_array($value)) {
305
 
            $request->getEmitter()->attach(
306
 
                new Cookie(CookieJar::fromArray($value, $request->getHost()))
307
 
            );
308
 
        } elseif ($value instanceof CookieJarInterface) {
309
 
            $request->getEmitter()->attach(new Cookie($value));
310
 
        } elseif ($value !== false) {
311
 
            throw new \InvalidArgumentException('cookies must be an array, '
312
 
                . 'true, or a CookieJarInterface object');
313
 
        }
314
 
    }
315
 
 
316
 
    private function add_events(RequestInterface $request, $value)
317
 
    {
318
 
        if (!is_array($value)) {
319
 
            throw new \InvalidArgumentException('events value must be an array');
320
 
        }
321
 
 
322
 
        $this->attachListeners($request, $this->prepareListeners($value,
323
 
            ['before', 'complete', 'error', 'headers']
324
 
        ));
325
 
    }
326
 
 
327
 
    private function add_subscribers(RequestInterface $request, $value)
328
 
    {
329
 
        if (!is_array($value)) {
330
 
            throw new \InvalidArgumentException('subscribers must be an array');
331
 
        }
332
 
 
333
 
        $emitter = $request->getEmitter();
334
 
        foreach ($value as $subscribers) {
335
 
            $emitter->attach($subscribers);
336
 
        }
337
 
    }
338
 
 
339
 
    private function add_json(RequestInterface $request, $value)
340
 
    {
341
 
        if (!$request->hasHeader('Content-Type')) {
342
 
            $request->setHeader('Content-Type', 'application/json');
343
 
        }
344
 
 
345
 
        $request->setBody(Stream::factory(json_encode($value)));
346
 
    }
347
 
 
348
 
    private function add_decode_content(RequestInterface $request, $value)
349
 
    {
350
 
        if ($value === false) {
351
 
            return;
352
 
        }
353
 
 
354
 
        if ($value !== true) {
355
 
            $request->setHeader('Accept-Encoding', $value);
356
 
        }
357
 
 
358
 
        $request->getConfig()['decode_content'] = true;
359
 
    }
360
 
}