~tcuthbert/wordpress/openstack-objectstorage

« back to all changes in this revision

Viewing changes to vendor/guzzlehttp/guzzle/src/Message/MessageFactory.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
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
}