aboutsummaryrefslogtreecommitdiffstats
path: root/public/system/storage/vendor/guzzlehttp/guzzle/src/RingBridge.php
blob: bc6841d42bc68a12a77b7a2abdc6a0f150b18915 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
<?php
namespace GuzzleHttp;

use GuzzleHttp\Message\MessageFactoryInterface;
use GuzzleHttp\Message\RequestInterface;
use GuzzleHttp\Event\ProgressEvent;
use GuzzleHttp\Message\Request;
use GuzzleHttp\Ring\Core;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Exception\RequestException;

/**
 * Provides the bridge between Guzzle requests and responses and Guzzle Ring.
 */
class RingBridge
{
    /**
     * Creates a Ring request from a request object.
     *
     * This function does not hook up the "then" and "progress" events that
     * would be required for actually sending a Guzzle request through a
     * RingPHP handler.
     *
     * @param RequestInterface $request Request to convert.
     *
     * @return array Converted Guzzle Ring request.
     */
    public static function createRingRequest(RequestInterface $request)
    {
        $options = $request->getConfig()->toArray();
        $url = $request->getUrl();
        // No need to calculate the query string twice (in URL and query).
        $qs = ($pos = strpos($url, '?')) ? substr($url, $pos + 1) : null;

        return [
            'scheme'       => $request->getScheme(),
            'http_method'  => $request->getMethod(),
            'url'          => $url,
            'uri'          => $request->getPath(),
            'headers'      => $request->getHeaders(),
            'body'         => $request->getBody(),
            'version'      => $request->getProtocolVersion(),
            'client'       => $options,
            'query_string' => $qs,
            'future'       => isset($options['future']) ? $options['future'] : false
        ];
    }

    /**
     * Creates a Ring request from a request object AND prepares the callbacks.
     *
     * @param Transaction $trans Transaction to update.
     *
     * @return array Converted Guzzle Ring request.
     */
    public static function prepareRingRequest(Transaction $trans)
    {
        // Clear out the transaction state when initiating.
        $trans->exception = null;
        $request = self::createRingRequest($trans->request);

        // Emit progress events if any progress listeners are registered.
        if ($trans->request->getEmitter()->hasListeners('progress')) {
            $emitter = $trans->request->getEmitter();
            $request['client']['progress'] = function ($a, $b, $c, $d) use ($trans, $emitter) {
                $emitter->emit('progress', new ProgressEvent($trans, $a, $b, $c, $d));
            };
        }

        return $request;
    }

    /**
     * Handles the process of processing a response received from a ring
     * handler. The created response is added to the transaction, and the
     * transaction stat is set appropriately.
     *
     * @param Transaction             $trans          Owns request and response.
     * @param array                   $response       Ring response array
     * @param MessageFactoryInterface $messageFactory Creates response objects.
     */
    public static function completeRingResponse(
        Transaction $trans,
        array $response,
        MessageFactoryInterface $messageFactory
    ) {
        $trans->state = 'complete';
        $trans->transferInfo = isset($response['transfer_stats'])
            ? $response['transfer_stats'] : [];

        if (!empty($response['status'])) {
            $options = [];
            if (isset($response['version'])) {
                $options['protocol_version'] = $response['version'];
            }
            if (isset($response['reason'])) {
                $options['reason_phrase'] = $response['reason'];
            }
            $trans->response = $messageFactory->createResponse(
                $response['status'],
                isset($response['headers']) ? $response['headers'] : [],
                isset($response['body']) ? $response['body'] : null,
                $options
            );
            if (isset($response['effective_url'])) {
                $trans->response->setEffectiveUrl($response['effective_url']);
            }
        } elseif (empty($response['error'])) {
            // When nothing was returned, then we need to add an error.
            $response['error'] = self::getNoRingResponseException($trans->request);
        }

        if (isset($response['error'])) {
            $trans->state = 'error';
            $trans->exception = $response['error'];
        }
    }

    /**
     * Creates a Guzzle request object using a ring request array.
     *
     * @param array $request Ring request
     *
     * @return Request
     * @throws \InvalidArgumentException for incomplete requests.
     */
    public static function fromRingRequest(array $request)
    {
        $options = [];
        if (isset($request['version'])) {
            $options['protocol_version'] = $request['version'];
        }

        if (!isset($request['http_method'])) {
            throw new \InvalidArgumentException('No http_method');
        }

        return new Request(
            $request['http_method'],
            Core::url($request),
            isset($request['headers']) ? $request['headers'] : [],
            isset($request['body']) ? Stream::factory($request['body']) : null,
            $options
        );
    }

    /**
     * Get an exception that can be used when a RingPHP handler does not
     * populate a response.
     *
     * @param RequestInterface $request
     *
     * @return RequestException
     */
    public static function getNoRingResponseException(RequestInterface $request)
    {
        $message = <<<EOT
Sending the request did not return a response, exception, or populate the
transaction with a response. This is most likely due to an incorrectly
implemented RingPHP handler. If you are simply trying to mock responses,
then it is recommended to use the GuzzleHttp\Ring\Client\MockHandler.
EOT;
        return new RequestException($message, $request);
    }
}