~tcuthbert/wordpress/openstack-objectstorage-k8s

« back to all changes in this revision

Viewing changes to vendor/guzzlehttp/guzzle/docs/adapters.rst

  • 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
 
========
2
 
Adapters
3
 
========
4
 
 
5
 
Guzzle uses *adapters* to send HTTP requests. Adapters emit the lifecycle
6
 
events of requests, transfer HTTP requests, and normalize error handling.
7
 
 
8
 
Default Adapter
9
 
===============
10
 
 
11
 
Guzzle will use the best possible adapter based on your environment.
12
 
 
13
 
If cURL is present, Guzzle will use the following adapters by default:
14
 
 
15
 
- ``GuzzleHttp\Adapter\Curl\MultiAdapter`` is used to transfer requests in
16
 
  parallel.
17
 
- If ``allow_url_fopen`` is enabled, then a
18
 
  ``GuzzleHttp\Adapter\StreamingProxyAdapter`` is added so that streaming
19
 
  requests are sent using the PHP stream wrapper. If this setting is disabled,
20
 
  then streaming requests are sent through a cURL adapter.
21
 
- If using PHP 5.5 or greater, then a ``GuzzleHttp\Adapter\Curl\CurlAdapter``
22
 
  is used to send serial requests. Otherwise, the
23
 
  ``GuzzleHttp\Adapter\Curl\MultiAdapter`` is used for serial and parallel
24
 
  requests.
25
 
 
26
 
If cURL is not installed, then Guzzle will use a
27
 
``GuzzleHttp\Adapter\StreamingAdapter`` to send requests through PHP's
28
 
HTTP stream wrapper. ``allow_url_fopen`` must be enabled if cURL is not
29
 
installed on your system.
30
 
 
31
 
Creating an Adapter
32
 
===================
33
 
 
34
 
Creating a custom HTTP adapter allows you to completely customize the way an
35
 
HTTP request is sent over the wire. In some cases, you might need to use a
36
 
different mechanism for transferring HTTP requests other than cURL or PHP's
37
 
stream wrapper. For example, you might need to use a socket because the version
38
 
of cURL on your system has an old bug, maybe you'd like to implement future
39
 
response objects, or you want to create a thread pool and send parallel
40
 
requests using pthreads.
41
 
 
42
 
The first thing you need to know about implementing custom adapters are the
43
 
responsibilities of an adapter.
44
 
 
45
 
Adapter Responsibilities
46
 
------------------------
47
 
 
48
 
Adapters use a ``GuzzleHttp\Adapter\TransactionInterface`` which acts as a
49
 
mediator between ``GuzzleHttp\Message\RequestInterface`` and
50
 
``GuzzleHttp\Message\ResponseInterface`` objects. The main goal of an adapter
51
 
is to set a response on the provided transaction object.
52
 
 
53
 
1. The adapter MUST return a ``GuzzleHttp\Message\ResponseInterface`` object in
54
 
   a successful condition.
55
 
 
56
 
2. When preparing requests, adapters MUST properly handle as many of the
57
 
   following request configuration options as possible:
58
 
 
59
 
   - :ref:`cert-option`
60
 
   - :ref:`connect_timeout-option`
61
 
   - :ref:`debug-option`
62
 
   - :ref:`expect-option`
63
 
   - :ref:`proxy-option`
64
 
   - :ref:`save_to-option`
65
 
   - :ref:`ssl_key-option`
66
 
   - :ref:`stream-option`
67
 
   - :ref:`timeout-option`
68
 
   - :ref:`verify-option`
69
 
   - :ref:`decode_content` - When set to ``true``, the adapter must attempt to
70
 
     decode the body of a ``Content-Encoding`` response (e.g., gzip).
71
 
 
72
 
3. Adapters SHOULD not follow redirects. In the normal case, redirects are
73
 
   followed by ``GuzzleHttp\Subscriber\Redirect``. Redirects SHOULD be
74
 
   implemented using Guzzle event subscribers, not by an adapter.
75
 
 
76
 
4. The adapter MUST emit a ``before`` event with a
77
 
   ``GuzzleHttp\Event\BeforeEvent`` object before sending a request. If the
78
 
   event is intercepted and a response is associated with a transaction during
79
 
   the ``before`` event, then the adapter MUST not send the request over the
80
 
   wire, but rather return the response.
81
 
 
82
 
5. When all of the headers of a response have been received, the adapter MUST
83
 
   emit a ``headers`` event with a ``GuzzleHttp\Event\HeadersEvent``. This
84
 
   event MUST be emitted before any data is written to the body of the response
85
 
   object. It is important to keep in mind that event listeners MAY mutate a
86
 
   response during the emission of this event.
87
 
 
88
 
6. The adapter MUST emit a ``complete`` event with a
89
 
   ``GuzzleHttp\Event\CompleteEvent`` when a request has completed sending.
90
 
   Adapters MUST emit the complete event for all valid HTTP responses,
91
 
   including responses that resulted in a non 2xx level response.
92
 
 
93
 
7. The adapter MUST emit an ``error`` event with a
94
 
   ``GuzzleHttp\Event\ErrorEvent``when an error occurs during the transfer.
95
 
   This includes when preparing a request for transfer, during the ``before``
96
 
   event, during the ``headers`` event, during the ``complete`` event, when
97
 
   a networking error occurs, and so on.
98
 
 
99
 
8. After emitting the ``error`` event, the adapter MUST check if the
100
 
   error event was intercepted and a response was associated with the
101
 
   transaction. If the propagation of the ``error`` event was not stopped, then
102
 
   the adapter MUST throw the exception. If the propagation was stopped, then
103
 
   the adapter MUST NOT throw the exception.
104
 
 
105
 
Parallel Adapters
106
 
-----------------
107
 
 
108
 
Parallel adapters are used when using a client's ``sendAll()`` method. Parallel
109
 
adapters are expected to send one or more transactions in parallel. Parallel
110
 
adapters accept an ``\Iterator`` that yields
111
 
``GuzzleHttp\Adapter\TransactionInterface`` object. In addition to the
112
 
iterator, the adapter is also provided an integer representing the number of
113
 
transactions to execute in parallel.
114
 
 
115
 
Parallel adapters are similar to adapters (described earlier), except for the
116
 
following:
117
 
 
118
 
1. RequestExceptions are only thrown from a parallel adapter when the
119
 
   ``GuzzleHttp\Exception\RequestException::getThrowImmediately()`` method of
120
 
   an encountered exception returns ``true``. If this method does not return
121
 
   ``true`` or the exception is not an instance of RequestException, then the
122
 
   parallel adapter MUST NOT throw the exception. Error handling for parallel
123
 
   transfers should normally be handled through event listeners that use
124
 
   ``error`` events.
125
 
 
126
 
2. Parallel adapters are not expected to return responses. Because parallel
127
 
   adapters can, in theory, send an infinite number of requests, developers
128
 
   must use event listeners to receive the ``complete`` event and handle
129
 
   responses accordingly.
130
 
 
131
 
Emitting Lifecycle Events
132
 
-------------------------
133
 
 
134
 
Request lifecycle events MUST be emitted by adapters and parallel adapters.
135
 
These lifecycle events are used by event listeners to modify requests, modify
136
 
responses, perform validation, and anything else required by an application.
137
 
 
138
 
Emitting request lifecycle events in an adapter is much simpler if you use the
139
 
static helper method of ``GuzzleHttp\Event\RequestEvents``. These methods are
140
 
used by the built-in in curl and stream wrapper adapters of Guzzle, so you
141
 
should use them too.
142
 
 
143
 
Example Adapter
144
 
===============
145
 
 
146
 
Here's a really simple example of creating a custom HTTP adapter. For
147
 
simplicity, this example uses a magic ``send_request()`` function.
148
 
 
149
 
.. code-block:: php
150
 
 
151
 
    <?php
152
 
 
153
 
    namespace MyProject\Adapter;
154
 
 
155
 
    use GuzzleHttp\Event\RequestEvents;
156
 
    use GuzzleHttp\Event\HeadersEvent;
157
 
    use GuzzleHttp\Message\MessageFactoryInterface;
158
 
 
159
 
    class MyAdapter implements AdapterInterface
160
 
    {
161
 
        private $messageFactory;
162
 
 
163
 
        public function __construct(MessageFactoryInterface $messageFactory)
164
 
        {
165
 
            $this->messageFactory = $messageFactory;
166
 
        }
167
 
 
168
 
        public function send(TransactionInterface $transaction)
169
 
        {
170
 
            RequestEvents::emitBefore($transaction);
171
 
 
172
 
            // Check if the transaction was intercepted
173
 
            if (!$transaction->getResponse()) {
174
 
                // It wasn't intercepted, so send the request
175
 
                $this->getResponse($transaction);
176
 
            }
177
 
 
178
 
            // Adapters always return a response in the successful case.
179
 
            return $transaction->getResponse();
180
 
        }
181
 
 
182
 
        private function getResponse(TransactionInterface $transaction)
183
 
        {
184
 
            $request = $transaction->getRequest();
185
 
 
186
 
            $response = send_request(
187
 
                $request->getMethod(),
188
 
                $request->getUrl(),
189
 
                $request->getHeaders(),
190
 
                $request->getBody()
191
 
            );
192
 
 
193
 
            if ($response) {
194
 
                $this->processResponse($response, $transaction);
195
 
            } else {
196
 
                // Emit the error event which allows listeners to intercept
197
 
                // the error with a valid response. If it is not intercepted,
198
 
                // a RequestException is thrown.
199
 
                RequestEvents::emitError($transaction, $e);
200
 
            }
201
 
        }
202
 
 
203
 
        private function processResponse(
204
 
            array $response,
205
 
            TransactionInterface $transaction
206
 
        ) {
207
 
            // Process the response, create a Guzzle Response object, and
208
 
            // associate the response with the transaction.
209
 
            $responseObject = $this->messageFactory->createResponse(
210
 
                $response['status_code'],
211
 
                $response['headers']
212
 
            );
213
 
 
214
 
            $transaction->setResponse($responseObject);
215
 
 
216
 
            // Emit the headers event before downloading the body
217
 
            RequestEvents::emitHeaders($transaction);
218
 
 
219
 
            if ($response['body']) {
220
 
                // Assuming the response body is a stream or something,
221
 
                // associate it with the response object.
222
 
                $responseObject->setBody(Stream::factory($response['body']));
223
 
            }
224
 
 
225
 
            // Emit the complete event
226
 
            RequestEvents::emitComplete($transaction);
227
 
        }
228
 
    }