aboutsummaryrefslogtreecommitdiffstats
path: root/public/system/storage/vendor/guzzlehttp/guzzle/src/Message/MessageParser.php
blob: c3cc195e3293645732fa72edfedfb3cb7486670d (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
166
167
168
169
170
171
<?php
namespace GuzzleHttp\Message;

/**
 * Request and response parser used by Guzzle
 */
class MessageParser
{
    /**
     * Parse an HTTP request message into an associative array of parts.
     *
     * @param string $message HTTP request to parse
     *
     * @return array|bool Returns false if the message is invalid
     */
    public function parseRequest($message)
    {
        if (!($parts = $this->parseMessage($message))) {
            return false;
        }

        // Parse the protocol and protocol version
        if (isset($parts['start_line'][2])) {
            $startParts = explode('/', $parts['start_line'][2]);
            $protocol = strtoupper($startParts[0]);
            $version = isset($startParts[1]) ? $startParts[1] : '1.1';
        } else {
            $protocol = 'HTTP';
            $version = '1.1';
        }

        $parsed = [
            'method'   => strtoupper($parts['start_line'][0]),
            'protocol' => $protocol,
            'protocol_version' => $version,
            'headers'  => $parts['headers'],
            'body'     => $parts['body']
        ];

        $parsed['request_url'] = $this->getUrlPartsFromMessage(
            (isset($parts['start_line'][1]) ? $parts['start_line'][1] : ''), $parsed);

        return $parsed;
    }

    /**
     * Parse an HTTP response message into an associative array of parts.
     *
     * @param string $message HTTP response to parse
     *
     * @return array|bool Returns false if the message is invalid
     */
    public function parseResponse($message)
    {
        if (!($parts = $this->parseMessage($message))) {
            return false;
        }

        list($protocol, $version) = explode('/', trim($parts['start_line'][0]));

        return [
            'protocol'         => $protocol,
            'protocol_version' => $version,
            'code'             => $parts['start_line'][1],
            'reason_phrase'    => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '',
            'headers'          => $parts['headers'],
            'body'             => $parts['body']
        ];
    }

    /**
     * Parse a message into parts
     *
     * @param string $message Message to parse
     *
     * @return array|bool
     */
    private function parseMessage($message)
    {
        if (!$message) {
            return false;
        }

        $startLine = null;
        $headers = [];
        $body = '';

        // Iterate over each line in the message, accounting for line endings
        $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
        for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {

            $line = $lines[$i];

            // If two line breaks were encountered, then this is the end of body
            if (empty($line)) {
                if ($i < $totalLines - 1) {
                    $body = implode('', array_slice($lines, $i + 2));
                }
                break;
            }

            // Parse message headers
            if (!$startLine) {
                $startLine = explode(' ', $line, 3);
            } elseif (strpos($line, ':')) {
                $parts = explode(':', $line, 2);
                $key = trim($parts[0]);
                $value = isset($parts[1]) ? trim($parts[1]) : '';
                if (!isset($headers[$key])) {
                    $headers[$key] = $value;
                } elseif (!is_array($headers[$key])) {
                    $headers[$key] = [$headers[$key], $value];
                } else {
                    $headers[$key][] = $value;
                }
            }
        }

        return [
            'start_line' => $startLine,
            'headers'    => $headers,
            'body'       => $body
        ];
    }

    /**
     * Create URL parts from HTTP message parts
     *
     * @param string $requestUrl Associated URL
     * @param array  $parts      HTTP message parts
     *
     * @return array
     */
    private function getUrlPartsFromMessage($requestUrl, array $parts)
    {
        // Parse the URL information from the message
        $urlParts = ['path' => $requestUrl, 'scheme' => 'http'];

        // Check for the Host header
        if (isset($parts['headers']['Host'])) {
            $urlParts['host'] = $parts['headers']['Host'];
        } elseif (isset($parts['headers']['host'])) {
            $urlParts['host'] = $parts['headers']['host'];
        } else {
            $urlParts['host'] = null;
        }

        if (false === strpos($urlParts['host'], ':')) {
            $urlParts['port'] = '';
        } else {
            $hostParts = explode(':', $urlParts['host']);
            $urlParts['host'] = trim($hostParts[0]);
            $urlParts['port'] = (int) trim($hostParts[1]);
            if ($urlParts['port'] == 443) {
                $urlParts['scheme'] = 'https';
            }
        }

        // Check if a query is present
        $path = $urlParts['path'];
        $qpos = strpos($path, '?');
        if ($qpos) {
            $urlParts['query'] = substr($path, $qpos + 1);
            $urlParts['path'] = substr($path, 0, $qpos);
        } else {
            $urlParts['query'] = '';
        }

        return $urlParts;
    }
}