PluginProbe
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI / 6.0.4
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI v6.0.4
6.0.4 6.0.3 6.0.2 6.0.1 6.0.0 5.8.6 5.8.5 5.8.4 5.8.3 5.8.2 5.8.1 5.8.0 5.7.9.2 5.7.9.1 5.7.8 5.7.9 5.7.6 5.7.7 5.7.5 5.7.4 5.7.3 5.7.2 5.7.1 trunk 5.6.0 All 35 releases
← All changes | integrations/mailchimp/vendor/guzzlehttp/psr7/src/Message.php +246 -0 5.7.9 → 6.0.4 View file →
@@ -1,0 +1,246 @@
1 +<?php
2 +
3 +declare(strict_types=1);
4 +
5 +namespace GuzzleHttp\Psr7;
6 +
7 +use Psr\Http\Message\MessageInterface;
8 +use Psr\Http\Message\RequestInterface;
9 +use Psr\Http\Message\ResponseInterface;
10 +
11 +final class Message
12 +{
13 + /**
14 + * Returns the string representation of an HTTP message.
15 + *
16 + * @param MessageInterface $message Message to convert to a string.
17 + */
18 + public static function toString(MessageInterface $message): string
19 + {
20 + if ($message instanceof RequestInterface) {
21 + $msg = trim($message->getMethod().' '
22 + .$message->getRequestTarget())
23 + .' HTTP/'.$message->getProtocolVersion();
24 + if (!$message->hasHeader('host')) {
25 + $msg .= "\r\nHost: ".$message->getUri()->getHost();
26 + }
27 + } elseif ($message instanceof ResponseInterface) {
28 + $msg = 'HTTP/'.$message->getProtocolVersion().' '
29 + .$message->getStatusCode().' '
30 + .$message->getReasonPhrase();
31 + } else {
32 + throw new \InvalidArgumentException('Unknown message type');
33 + }
34 +
35 + foreach ($message->getHeaders() as $name => $values) {
36 + if (is_string($name) && strtolower($name) === 'set-cookie') {
37 + foreach ($values as $value) {
38 + $msg .= "\r\n{$name}: ".$value;
39 + }
40 + } else {
41 + $msg .= "\r\n{$name}: ".implode(', ', $values);
42 + }
43 + }
44 +
45 + return "{$msg}\r\n\r\n".$message->getBody();
46 + }
47 +
48 + /**
49 + * Get a short summary of the message body.
50 + *
51 + * Will return `null` if the response is not printable.
52 + *
53 + * @param MessageInterface $message The message to get the body summary
54 + * @param int $truncateAt The maximum allowed size of the summary
55 + */
56 + public static function bodySummary(MessageInterface $message, int $truncateAt = 120): ?string
57 + {
58 + $body = $message->getBody();
59 +
60 + if (!$body->isSeekable() || !$body->isReadable()) {
61 + return null;
62 + }
63 +
64 + $size = $body->getSize();
65 +
66 + if ($size === 0) {
67 + return null;
68 + }
69 +
70 + $body->rewind();
71 + $summary = $body->read($truncateAt);
72 + $body->rewind();
73 +
74 + if ($size > $truncateAt) {
75 + $summary .= ' (truncated...)';
76 + }
77 +
78 + // Matches any printable character, including unicode characters:
79 + // letters, marks, numbers, punctuation, spacing, and separators.
80 + if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/u', $summary) !== 0) {
81 + return null;
82 + }
83 +
84 + return $summary;
85 + }
86 +
87 + /**
88 + * Attempts to rewind a message body and throws an exception on failure.
89 + *
90 + * The body of the message will only be rewound if a call to `tell()`
91 + * returns a value other than `0`.
92 + *
93 + * @param MessageInterface $message Message to rewind
94 + *
95 + * @throws \RuntimeException
96 + */
97 + public static function rewindBody(MessageInterface $message): void
98 + {
99 + $body = $message->getBody();
100 +
101 + if ($body->tell()) {
102 + $body->rewind();
103 + }
104 + }
105 +
106 + /**
107 + * Parses an HTTP message into an associative array.
108 + *
109 + * The array contains the "start-line" key containing the start line of
110 + * the message, "headers" key containing an associative array of header
111 + * array values, and a "body" key containing the body of the message.
112 + *
113 + * @param string $message HTTP request or response to parse.
114 + */
115 + public static function parseMessage(string $message): array
116 + {
117 + if (!$message) {
118 + throw new \InvalidArgumentException('Invalid message');
119 + }
120 +
121 + $message = ltrim($message, "\r\n");
122 +
123 + $messageParts = preg_split("/\r?\n\r?\n/", $message, 2);
124 +
125 + if ($messageParts === false || count($messageParts) !== 2) {
126 + throw new \InvalidArgumentException('Invalid message: Missing header delimiter');
127 + }
128 +
129 + [$rawHeaders, $body] = $messageParts;
130 + $rawHeaders .= "\r\n"; // Put back the delimiter we split previously
131 + $headerParts = preg_split("/\r?\n/", $rawHeaders, 2);
132 +
133 + if ($headerParts === false || count($headerParts) !== 2) {
134 + throw new \InvalidArgumentException('Invalid message: Missing status line');
135 + }
136 +
137 + [$startLine, $rawHeaders] = $headerParts;
138 +
139 + if (preg_match("/(?:^HTTP\/|^[A-Z]+ \S+ HTTP\/)(\d+(?:\.\d+)?)/i", $startLine, $matches) && $matches[1] === '1.0') {
140 + // Header folding is deprecated for HTTP/1.1, but allowed in HTTP/1.0
141 + $rawHeaders = preg_replace(Rfc7230::HEADER_FOLD_REGEX, ' ', $rawHeaders);
142 + }
143 +
144 + /** @var array[] $headerLines */
145 + $count = preg_match_all(Rfc7230::HEADER_REGEX, $rawHeaders, $headerLines, PREG_SET_ORDER);
146 +
147 + // If these aren't the same, then one line didn't match and there's an invalid header.
148 + if ($count !== substr_count($rawHeaders, "\n")) {
149 + // Folding is deprecated, see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4
150 + if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) {
151 + throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding');
152 + }
153 +
154 + throw new \InvalidArgumentException('Invalid header syntax');
155 + }
156 +
157 + $headers = [];
158 +
159 + foreach ($headerLines as $headerLine) {
160 + $headers[$headerLine[1]][] = $headerLine[2];
161 + }
162 +
163 + return [
164 + 'start-line' => $startLine,
165 + 'headers' => $headers,
166 + 'body' => $body,
167 + ];
168 + }
169 +
170 + /**
171 + * Constructs a URI for an HTTP request message.
172 + *
173 + * @param string $path Path from the start-line
174 + * @param array $headers Array of headers (each value an array).
175 + */
176 + public static function parseRequestUri(string $path, array $headers): string
177 + {
178 + $hostKey = array_filter(array_keys($headers), function ($k) {
179 + // Numeric array keys are converted to int by PHP.
180 + $k = (string) $k;
181 +
182 + return strtolower($k) === 'host';
183 + });
184 +
185 + // If no host is found, then a full URI cannot be constructed.
186 + if (!$hostKey) {
187 + return $path;
188 + }
189 +
190 + $host = $headers[reset($hostKey)][0];
191 + $scheme = substr($host, -4) === ':443' ? 'https' : 'http';
192 +
193 + return $scheme.'://'.$host.'/'.ltrim($path, '/');
194 + }
195 +
196 + /**
197 + * Parses a request message string into a request object.
198 + *
199 + * @param string $message Request message string.
200 + */
201 + public static function parseRequest(string $message): RequestInterface
202 + {
203 + $data = self::parseMessage($message);
204 + $matches = [];
205 + if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) {
206 + throw new \InvalidArgumentException('Invalid request string');
207 + }
208 + $parts = explode(' ', $data['start-line'], 3);
209 + $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';
210 +
211 + $request = new Request(
212 + $parts[0],
213 + $matches[1] === '/' ? self::parseRequestUri($parts[1], $data['headers']) : $parts[1],
214 + $data['headers'],
215 + $data['body'],
216 + $version
217 + );
218 +
219 + return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
220 + }
221 +
222 + /**
223 + * Parses a response message string into a response object.
224 + *
225 + * @param string $message Response message string.
226 + */
227 + public static function parseResponse(string $message): ResponseInterface
228 + {
229 + $data = self::parseMessage($message);
230 + // According to https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
231 + // the space between status-code and reason-phrase is required. But
232 + // browsers accept responses without space and reason as well.
233 + if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) {
234 + throw new \InvalidArgumentException('Invalid response string: '.$data['start-line']);
235 + }
236 + $parts = explode(' ', $data['start-line'], 3);
237 +
238 + return new Response(
239 + (int) $parts[1],
240 + $data['headers'],
241 + $data['body'],
242 + explode('/', $parts[0])[1],
243 + $parts[2] ?? null
244 + );
245 + }
246 +}