~tcuthbert/wordpress/openstack-objectstorage-k8s

« back to all changes in this revision

Viewing changes to vendor/guzzlehttp/guzzle/src/Adapter/StreamAdapter.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;
4
 
 
5
 
use GuzzleHttp\Event\RequestEvents;
6
 
use GuzzleHttp\Exception\AdapterException;
7
 
use GuzzleHttp\Exception\RequestException;
8
 
use GuzzleHttp\Message\AbstractMessage;
9
 
use GuzzleHttp\Message\MessageFactoryInterface;
10
 
use GuzzleHttp\Message\RequestInterface;
11
 
use GuzzleHttp\Stream\InflateStream;
12
 
use GuzzleHttp\Stream\LazyOpenStream;
13
 
use GuzzleHttp\Stream\Stream;
14
 
use GuzzleHttp\Stream\StreamInterface;
15
 
use GuzzleHttp\Stream\Utils;
16
 
 
17
 
/**
18
 
 * HTTP adapter that uses PHP's HTTP stream wrapper.
19
 
 *
20
 
 * When using the StreamAdapter, custom stream context options can be specified
21
 
 * using the **stream_context** option in a request's **config** option. The
22
 
 * structure of the "stream_context" option is an associative array where each
23
 
 * key is a transport name and each option is an associative array of options.
24
 
 */
25
 
class StreamAdapter implements AdapterInterface
26
 
{
27
 
    /** @var MessageFactoryInterface */
28
 
    private $messageFactory;
29
 
 
30
 
    /**
31
 
     * @param MessageFactoryInterface $messageFactory
32
 
     */
33
 
    public function __construct(MessageFactoryInterface $messageFactory)
34
 
    {
35
 
        $this->messageFactory = $messageFactory;
36
 
    }
37
 
 
38
 
    public function send(TransactionInterface $transaction)
39
 
    {
40
 
        // HTTP/1.1 streams using the PHP stream wrapper require a
41
 
        // Connection: close header. Setting here so that it is added before
42
 
        // emitting the request.before_send event.
43
 
        $request = $transaction->getRequest();
44
 
        if ($request->getProtocolVersion() == '1.1' &&
45
 
            !$request->hasHeader('Connection')
46
 
        ) {
47
 
            $transaction->getRequest()->setHeader('Connection', 'close');
48
 
        }
49
 
 
50
 
        RequestEvents::emitBefore($transaction);
51
 
        if (!$transaction->getResponse()) {
52
 
            $this->createResponse($transaction);
53
 
            RequestEvents::emitComplete($transaction);
54
 
        }
55
 
 
56
 
        return $transaction->getResponse();
57
 
    }
58
 
 
59
 
    private function createResponse(TransactionInterface $transaction)
60
 
    {
61
 
        $request = $transaction->getRequest();
62
 
        $stream = $this->createStream($request, $http_response_header);
63
 
        $this->createResponseObject(
64
 
            $request,
65
 
            $http_response_header,
66
 
            $transaction,
67
 
            new Stream($stream)
68
 
        );
69
 
    }
70
 
 
71
 
    private function createResponseObject(
72
 
        RequestInterface $request,
73
 
        array $headers,
74
 
        TransactionInterface $transaction,
75
 
        StreamInterface $stream
76
 
    ) {
77
 
        $parts = explode(' ', array_shift($headers), 3);
78
 
        $options = ['protocol_version' => substr($parts[0], -3)];
79
 
 
80
 
        if (isset($parts[2])) {
81
 
            $options['reason_phrase'] = $parts[2];
82
 
        }
83
 
 
84
 
        $response = $this->messageFactory->createResponse(
85
 
            $parts[1],
86
 
            $this->headersFromLines($headers),
87
 
            null,
88
 
            $options
89
 
        );
90
 
 
91
 
        // Automatically decode responses when instructed.
92
 
        if ($request->getConfig()->get('decode_content')) {
93
 
            switch ($response->getHeader('Content-Encoding')) {
94
 
                case 'gzip':
95
 
                case 'deflate':
96
 
                    $stream = new InflateStream($stream);
97
 
                    break;
98
 
            }
99
 
        }
100
 
 
101
 
        // Drain the stream immediately if 'stream' was not enabled.
102
 
        if (!$request->getConfig()['stream']) {
103
 
            $stream = $this->getSaveToBody($request, $stream);
104
 
        }
105
 
 
106
 
        $response->setBody($stream);
107
 
        $transaction->setResponse($response);
108
 
        RequestEvents::emitHeaders($transaction);
109
 
 
110
 
        return $response;
111
 
    }
112
 
 
113
 
    /**
114
 
     * Drain the stream into the destination stream
115
 
     */
116
 
    private function getSaveToBody(
117
 
        RequestInterface $request,
118
 
        StreamInterface $stream
119
 
    ) {
120
 
        if ($saveTo = $request->getConfig()['save_to']) {
121
 
            // Stream the response into the destination stream
122
 
            $saveTo = is_string($saveTo)
123
 
                ? new Stream(Utils::open($saveTo, 'r+'))
124
 
                : Stream::factory($saveTo);
125
 
        } else {
126
 
            // Stream into the default temp stream
127
 
            $saveTo = Stream::factory();
128
 
        }
129
 
 
130
 
        Utils::copyToStream($stream, $saveTo);
131
 
        $saveTo->seek(0);
132
 
        $stream->close();
133
 
 
134
 
        return $saveTo;
135
 
    }
136
 
 
137
 
    private function headersFromLines(array $lines)
138
 
    {
139
 
        $responseHeaders = [];
140
 
 
141
 
        foreach ($lines as $line) {
142
 
            $headerParts = explode(':', $line, 2);
143
 
            $responseHeaders[$headerParts[0]][] = isset($headerParts[1])
144
 
                ? trim($headerParts[1])
145
 
                : '';
146
 
        }
147
 
 
148
 
        return $responseHeaders;
149
 
    }
150
 
 
151
 
    /**
152
 
     * Create a resource and check to ensure it was created successfully
153
 
     *
154
 
     * @param callable         $callback Callable that returns stream resource
155
 
     * @param RequestInterface $request  Request used when throwing exceptions
156
 
     * @param array            $options  Options used when throwing exceptions
157
 
     *
158
 
     * @return resource
159
 
     * @throws RequestException on error
160
 
     */
161
 
    private function createResource(callable $callback, RequestInterface $request, $options)
162
 
    {
163
 
        // Turn off error reporting while we try to initiate the request
164
 
        $level = error_reporting(0);
165
 
        $resource = call_user_func($callback);
166
 
        error_reporting($level);
167
 
 
168
 
        // If the resource could not be created, then grab the last error and
169
 
        // throw an exception.
170
 
        if (!is_resource($resource)) {
171
 
            $message = 'Error creating resource. [url] ' . $request->getUrl() . ' ';
172
 
            if (isset($options['http']['proxy'])) {
173
 
                $message .= "[proxy] {$options['http']['proxy']} ";
174
 
            }
175
 
            foreach ((array) error_get_last() as $key => $value) {
176
 
                $message .= "[{$key}] {$value} ";
177
 
            }
178
 
            throw new RequestException(trim($message), $request);
179
 
        }
180
 
 
181
 
        return $resource;
182
 
    }
183
 
 
184
 
    /**
185
 
     * Create the stream for the request with the context options.
186
 
     *
187
 
     * @param RequestInterface $request              Request being sent
188
 
     * @param mixed            $http_response_header Populated by stream wrapper
189
 
     *
190
 
     * @return resource
191
 
     */
192
 
    private function createStream(
193
 
        RequestInterface $request,
194
 
        &$http_response_header
195
 
    ) {
196
 
        static $methods;
197
 
        if (!$methods) {
198
 
            $methods = array_flip(get_class_methods(__CLASS__));
199
 
        }
200
 
 
201
 
        $params = [];
202
 
        $options = $this->getDefaultOptions($request);
203
 
        foreach ($request->getConfig()->toArray() as $key => $value) {
204
 
            $method = "add_{$key}";
205
 
            if (isset($methods[$method])) {
206
 
                $this->{$method}($request, $options, $value, $params);
207
 
            }
208
 
        }
209
 
 
210
 
        $this->applyCustomOptions($request, $options);
211
 
        $context = $this->createStreamContext($request, $options, $params);
212
 
 
213
 
        return $this->createStreamResource(
214
 
            $request,
215
 
            $options,
216
 
            $context,
217
 
            $http_response_header
218
 
        );
219
 
    }
220
 
 
221
 
    private function getDefaultOptions(RequestInterface $request)
222
 
    {
223
 
        $headers = AbstractMessage::getHeadersAsString($request);
224
 
 
225
 
        $context = [
226
 
            'http' => [
227
 
                'method'           => $request->getMethod(),
228
 
                'header'           => trim($headers),
229
 
                'protocol_version' => $request->getProtocolVersion(),
230
 
                'ignore_errors'    => true,
231
 
                'follow_location'  => 0
232
 
            ]
233
 
        ];
234
 
 
235
 
        if ($body = $request->getBody()) {
236
 
            $context['http']['content'] = (string) $body;
237
 
            // Prevent the HTTP adapter from adding a Content-Type header.
238
 
            if (!$request->hasHeader('Content-Type')) {
239
 
                $context['http']['header'] .= "\r\nContent-Type:";
240
 
            }
241
 
        }
242
 
 
243
 
        return $context;
244
 
    }
245
 
 
246
 
    private function add_proxy(RequestInterface $request, &$options, $value, &$params)
247
 
    {
248
 
        if (!is_array($value)) {
249
 
            $options['http']['proxy'] = $value;
250
 
        } else {
251
 
            $scheme = $request->getScheme();
252
 
            if (isset($value[$scheme])) {
253
 
                $options['http']['proxy'] = $value[$scheme];
254
 
            }
255
 
        }
256
 
    }
257
 
 
258
 
    private function add_timeout(RequestInterface $request, &$options, $value, &$params)
259
 
    {
260
 
        $options['http']['timeout'] = $value;
261
 
    }
262
 
 
263
 
    private function add_verify(RequestInterface $request, &$options, $value, &$params)
264
 
    {
265
 
        if ($value === true || is_string($value)) {
266
 
            $options['http']['verify_peer'] = true;
267
 
            if ($value !== true) {
268
 
                if (!file_exists($value)) {
269
 
                    throw new \RuntimeException("SSL certificate authority file not found: {$value}");
270
 
                }
271
 
                $options['http']['allow_self_signed'] = true;
272
 
                $options['http']['cafile'] = $value;
273
 
            }
274
 
        } elseif ($value === false) {
275
 
            $options['http']['verify_peer'] = false;
276
 
        }
277
 
    }
278
 
 
279
 
    private function add_cert(RequestInterface $request, &$options, $value, &$params)
280
 
    {
281
 
        if (is_array($value)) {
282
 
            $options['http']['passphrase'] = $value[1];
283
 
            $value = $value[0];
284
 
        }
285
 
 
286
 
        if (!file_exists($value)) {
287
 
            throw new \RuntimeException("SSL certificate not found: {$value}");
288
 
        }
289
 
 
290
 
        $options['http']['local_cert'] = $value;
291
 
    }
292
 
 
293
 
    private function add_debug(RequestInterface $request, &$options, $value, &$params)
294
 
    {
295
 
        static $map = [
296
 
            STREAM_NOTIFY_CONNECT       => 'CONNECT',
297
 
            STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
298
 
            STREAM_NOTIFY_AUTH_RESULT   => 'AUTH_RESULT',
299
 
            STREAM_NOTIFY_MIME_TYPE_IS  => 'MIME_TYPE_IS',
300
 
            STREAM_NOTIFY_FILE_SIZE_IS  => 'FILE_SIZE_IS',
301
 
            STREAM_NOTIFY_REDIRECTED    => 'REDIRECTED',
302
 
            STREAM_NOTIFY_PROGRESS      => 'PROGRESS',
303
 
            STREAM_NOTIFY_FAILURE       => 'FAILURE',
304
 
            STREAM_NOTIFY_COMPLETED     => 'COMPLETED',
305
 
            STREAM_NOTIFY_RESOLVE       => 'RESOLVE'
306
 
        ];
307
 
 
308
 
        static $args = ['severity', 'message', 'message_code',
309
 
            'bytes_transferred', 'bytes_max'];
310
 
 
311
 
        if (!is_resource($value)) {
312
 
            $value = defined('STDOUT') ? STDOUT : fopen('php://output', 'w');
313
 
        }
314
 
 
315
 
        $params['notification'] = function () use ($request, $value, $map, $args) {
316
 
            $passed = func_get_args();
317
 
            $code = array_shift($passed);
318
 
            fprintf($value, '<%s> [%s] ', $request->getUrl(), $map[$code]);
319
 
            foreach (array_filter($passed) as $i => $v) {
320
 
                fwrite($value, $args[$i] . ': "' . $v . '" ');
321
 
            }
322
 
            fwrite($value, "\n");
323
 
        };
324
 
    }
325
 
 
326
 
    private function applyCustomOptions(
327
 
        RequestInterface $request,
328
 
        array &$options
329
 
    ) {
330
 
        // Overwrite any generated options with custom options
331
 
        if ($custom = $request->getConfig()['stream_context']) {
332
 
            if (!is_array($custom)) {
333
 
                throw new AdapterException('stream_context must be an array');
334
 
            }
335
 
            $options = array_replace_recursive($options, $custom);
336
 
        }
337
 
    }
338
 
 
339
 
    private function createStreamContext(
340
 
        RequestInterface $request,
341
 
        array $options,
342
 
        array $params
343
 
    ) {
344
 
        return $this->createResource(
345
 
            function () use ($request, $options, $params) {
346
 
                return stream_context_create($options, $params);
347
 
            },
348
 
            $request,
349
 
            $options
350
 
        );
351
 
    }
352
 
 
353
 
    private function createStreamResource(
354
 
        RequestInterface $request,
355
 
        array $options,
356
 
        $context,
357
 
        &$http_response_header
358
 
    ) {
359
 
        $url = $request->getUrl();
360
 
 
361
 
        return $this->createResource(
362
 
            function () use ($url, &$http_response_header, $context) {
363
 
                if (false === strpos($url, 'http')) {
364
 
                    trigger_error("URL is invalid: {$url}", E_USER_WARNING);
365
 
                    return null;
366
 
                }
367
 
                return fopen($url, 'r', null, $context);
368
 
            },
369
 
            $request,
370
 
            $options
371
 
        );
372
 
    }
373
 
}