PluginProbe ʕ •ᴥ•ʔ
ShareThis Dashboard for Google Analytics / 3.1.7
ShareThis Dashboard for Google Analytics v3.1.7
3.3.2 trunk 1.0.7 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1 2.1.2 2.1.3 2.1.4 2.1.5 2.2.5 2.3.5 2.3.6 2.3.7 2.3.8 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 3.0.0 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.3.0 3.3.1
googleanalytics / lib / analytics-admin / vendor / guzzlehttp / psr7 / src / Message.php
googleanalytics / lib / analytics-admin / vendor / guzzlehttp / psr7 / src Last commit date
Exception 3 years ago AppendStream.php 3 years ago BufferStream.php 3 years ago CachingStream.php 3 years ago DroppingStream.php 3 years ago FnStream.php 3 years ago Header.php 3 years ago HttpFactory.php 3 years ago InflateStream.php 3 years ago LazyOpenStream.php 3 years ago LimitStream.php 3 years ago Message.php 3 years ago MessageTrait.php 3 years ago MimeType.php 3 years ago MultipartStream.php 3 years ago NoSeekStream.php 3 years ago PumpStream.php 3 years ago Query.php 3 years ago Request.php 3 years ago Response.php 3 years ago Rfc7230.php 3 years ago ServerRequest.php 3 years ago Stream.php 3 years ago StreamDecoratorTrait.php 3 years ago StreamWrapper.php 3 years ago UploadedFile.php 3 years ago Uri.php 3 years ago UriComparator.php 3 years ago UriNormalizer.php 3 years ago UriResolver.php 3 years ago Utils.php 3 years ago
Message.php
246 lines
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 (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 $summary = $body->read($truncateAt);
71 $body->rewind();
72
73 if ($size > $truncateAt) {
74 $summary .= ' (truncated...)';
75 }
76
77 // Matches any printable character, including unicode characters:
78 // letters, marks, numbers, punctuation, spacing, and separators.
79 if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/u', $summary)) {
80 return null;
81 }
82
83 return $summary;
84 }
85
86 /**
87 * Attempts to rewind a message body and throws an exception on failure.
88 *
89 * The body of the message will only be rewound if a call to `tell()`
90 * returns a value other than `0`.
91 *
92 * @param MessageInterface $message Message to rewind
93 *
94 * @throws \RuntimeException
95 */
96 public static function rewindBody(MessageInterface $message): void
97 {
98 $body = $message->getBody();
99
100 if ($body->tell()) {
101 $body->rewind();
102 }
103 }
104
105 /**
106 * Parses an HTTP message into an associative array.
107 *
108 * The array contains the "start-line" key containing the start line of
109 * the message, "headers" key containing an associative array of header
110 * array values, and a "body" key containing the body of the message.
111 *
112 * @param string $message HTTP request or response to parse.
113 */
114 public static function parseMessage(string $message): array
115 {
116 if (!$message) {
117 throw new \InvalidArgumentException('Invalid message');
118 }
119
120 $message = ltrim($message, "\r\n");
121
122 $messageParts = preg_split("/\r?\n\r?\n/", $message, 2);
123
124 if ($messageParts === false || count($messageParts) !== 2) {
125 throw new \InvalidArgumentException('Invalid message: Missing header delimiter');
126 }
127
128 [$rawHeaders, $body] = $messageParts;
129 $rawHeaders .= "\r\n"; // Put back the delimiter we split previously
130 $headerParts = preg_split("/\r?\n/", $rawHeaders, 2);
131
132 if ($headerParts === false || count($headerParts) !== 2) {
133 throw new \InvalidArgumentException('Invalid message: Missing status line');
134 }
135
136 [$startLine, $rawHeaders] = $headerParts;
137
138 if (preg_match("/(?:^HTTP\/|^[A-Z]+ \S+ HTTP\/)(\d+(?:\.\d+)?)/i", $startLine, $matches) && $matches[1] === '1.0') {
139 // Header folding is deprecated for HTTP/1.1, but allowed in HTTP/1.0
140 $rawHeaders = preg_replace(Rfc7230::HEADER_FOLD_REGEX, ' ', $rawHeaders);
141 }
142
143 /** @var array[] $headerLines */
144 $count = preg_match_all(Rfc7230::HEADER_REGEX, $rawHeaders, $headerLines, PREG_SET_ORDER);
145
146 // If these aren't the same, then one line didn't match and there's an invalid header.
147 if ($count !== substr_count($rawHeaders, "\n")) {
148 // Folding is deprecated, see https://tools.ietf.org/html/rfc7230#section-3.2.4
149 if (preg_match(Rfc7230::HEADER_FOLD_REGEX, $rawHeaders)) {
150 throw new \InvalidArgumentException('Invalid header syntax: Obsolete line folding');
151 }
152
153 throw new \InvalidArgumentException('Invalid header syntax');
154 }
155
156 $headers = [];
157
158 foreach ($headerLines as $headerLine) {
159 $headers[$headerLine[1]][] = $headerLine[2];
160 }
161
162 return [
163 'start-line' => $startLine,
164 'headers' => $headers,
165 'body' => $body,
166 ];
167 }
168
169 /**
170 * Constructs a URI for an HTTP request message.
171 *
172 * @param string $path Path from the start-line
173 * @param array $headers Array of headers (each value an array).
174 */
175 public static function parseRequestUri(string $path, array $headers): string
176 {
177 $hostKey = array_filter(array_keys($headers), function ($k) {
178 // Numeric array keys are converted to int by PHP.
179 $k = (string) $k;
180
181 return strtolower($k) === 'host';
182 });
183
184 // If no host is found, then a full URI cannot be constructed.
185 if (!$hostKey) {
186 return $path;
187 }
188
189 $host = $headers[reset($hostKey)][0];
190 $scheme = substr($host, -4) === ':443' ? 'https' : 'http';
191
192 return $scheme . '://' . $host . '/' . ltrim($path, '/');
193 }
194
195 /**
196 * Parses a request message string into a request object.
197 *
198 * @param string $message Request message string.
199 */
200 public static function parseRequest(string $message): RequestInterface
201 {
202 $data = self::parseMessage($message);
203 $matches = [];
204 if (!preg_match('/^[\S]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) {
205 throw new \InvalidArgumentException('Invalid request string');
206 }
207 $parts = explode(' ', $data['start-line'], 3);
208 $version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';
209
210 $request = new Request(
211 $parts[0],
212 $matches[1] === '/' ? self::parseRequestUri($parts[1], $data['headers']) : $parts[1],
213 $data['headers'],
214 $data['body'],
215 $version
216 );
217
218 return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
219 }
220
221 /**
222 * Parses a response message string into a response object.
223 *
224 * @param string $message Response message string.
225 */
226 public static function parseResponse(string $message): ResponseInterface
227 {
228 $data = self::parseMessage($message);
229 // According to https://tools.ietf.org/html/rfc7230#section-3.1.2 the space
230 // between status-code and reason-phrase is required. But browsers accept
231 // responses without space and reason as well.
232 if (!preg_match('/^HTTP\/.* [0-9]{3}( .*|$)/', $data['start-line'])) {
233 throw new \InvalidArgumentException('Invalid response string: ' . $data['start-line']);
234 }
235 $parts = explode(' ', $data['start-line'], 3);
236
237 return new Response(
238 (int) $parts[1],
239 $data['headers'],
240 $data['body'],
241 explode('/', $parts[0])[1],
242 $parts[2] ?? null
243 );
244 }
245 }
246