dokuwiki-matrixnotifierwas-plugin – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 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\StreamInterface;
9  
10 /**
11 * Trait implementing functionality common to requests and responses.
12 */
13 trait MessageTrait
14 {
15 /** @var string[][] Map of all registered headers, as original name => array of values */
16 private $headers = [];
17  
18 /** @var string[] Map of lowercase header name => original name at registration */
19 private $headerNames = [];
20  
21 /** @var string */
22 private $protocol = '1.1';
23  
24 /** @var StreamInterface|null */
25 private $stream;
26  
27 public function getProtocolVersion(): string
28 {
29 return $this->protocol;
30 }
31  
32 public function withProtocolVersion($version): MessageInterface
33 {
34 if ($this->protocol === $version) {
35 return $this;
36 }
37  
38 $new = clone $this;
39 $new->protocol = $version;
40  
41 return $new;
42 }
43  
44 public function getHeaders(): array
45 {
46 return $this->headers;
47 }
48  
49 public function hasHeader($header): bool
50 {
51 return isset($this->headerNames[strtolower($header)]);
52 }
53  
54 public function getHeader($header): array
55 {
56 $header = strtolower($header);
57  
58 if (!isset($this->headerNames[$header])) {
59 return [];
60 }
61  
62 $header = $this->headerNames[$header];
63  
64 return $this->headers[$header];
65 }
66  
67 public function getHeaderLine($header): string
68 {
69 return implode(', ', $this->getHeader($header));
70 }
71  
72 public function withHeader($header, $value): MessageInterface
73 {
74 $this->assertHeader($header);
75 $value = $this->normalizeHeaderValue($value);
76 $normalized = strtolower($header);
77  
78 $new = clone $this;
79 if (isset($new->headerNames[$normalized])) {
80 unset($new->headers[$new->headerNames[$normalized]]);
81 }
82 $new->headerNames[$normalized] = $header;
83 $new->headers[$header] = $value;
84  
85 return $new;
86 }
87  
88 public function withAddedHeader($header, $value): MessageInterface
89 {
90 $this->assertHeader($header);
91 $value = $this->normalizeHeaderValue($value);
92 $normalized = strtolower($header);
93  
94 $new = clone $this;
95 if (isset($new->headerNames[$normalized])) {
96 $header = $this->headerNames[$normalized];
97 $new->headers[$header] = array_merge($this->headers[$header], $value);
98 } else {
99 $new->headerNames[$normalized] = $header;
100 $new->headers[$header] = $value;
101 }
102  
103 return $new;
104 }
105  
106 public function withoutHeader($header): MessageInterface
107 {
108 $normalized = strtolower($header);
109  
110 if (!isset($this->headerNames[$normalized])) {
111 return $this;
112 }
113  
114 $header = $this->headerNames[$normalized];
115  
116 $new = clone $this;
117 unset($new->headers[$header], $new->headerNames[$normalized]);
118  
119 return $new;
120 }
121  
122 public function getBody(): StreamInterface
123 {
124 if (!$this->stream) {
125 $this->stream = Utils::streamFor('');
126 }
127  
128 return $this->stream;
129 }
130  
131 public function withBody(StreamInterface $body): MessageInterface
132 {
133 if ($body === $this->stream) {
134 return $this;
135 }
136  
137 $new = clone $this;
138 $new->stream = $body;
139  
140 return $new;
141 }
142  
143 /**
144 * @param (string|string[])[] $headers
145 */
146 private function setHeaders(array $headers): void
147 {
148 $this->headerNames = $this->headers = [];
149 foreach ($headers as $header => $value) {
150 // Numeric array keys are converted to int by PHP.
151 $header = (string) $header;
152  
153 $this->assertHeader($header);
154 $value = $this->normalizeHeaderValue($value);
155 $normalized = strtolower($header);
156 if (isset($this->headerNames[$normalized])) {
157 $header = $this->headerNames[$normalized];
158 $this->headers[$header] = array_merge($this->headers[$header], $value);
159 } else {
160 $this->headerNames[$normalized] = $header;
161 $this->headers[$header] = $value;
162 }
163 }
164 }
165  
166 /**
167 * @param mixed $value
168 *
169 * @return string[]
170 */
171 private function normalizeHeaderValue($value): array
172 {
173 if (!is_array($value)) {
174 return $this->trimAndValidateHeaderValues([$value]);
175 }
176  
177 if (count($value) === 0) {
178 throw new \InvalidArgumentException('Header value can not be an empty array.');
179 }
180  
181 return $this->trimAndValidateHeaderValues($value);
182 }
183  
184 /**
185 * Trims whitespace from the header values.
186 *
187 * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.
188 *
189 * header-field = field-name ":" OWS field-value OWS
190 * OWS = *( SP / HTAB )
191 *
192 * @param mixed[] $values Header values
193 *
194 * @return string[] Trimmed header values
195 *
196 * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4
197 */
198 private function trimAndValidateHeaderValues(array $values): array
199 {
200 return array_map(function ($value) {
201 if (!is_scalar($value) && null !== $value) {
202 throw new \InvalidArgumentException(sprintf(
203 'Header value must be scalar or null but %s provided.',
204 is_object($value) ? get_class($value) : gettype($value)
205 ));
206 }
207  
208 $trimmed = trim((string) $value, " \t");
209 $this->assertValue($trimmed);
210  
211 return $trimmed;
212 }, array_values($values));
213 }
214  
215 /**
216 * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2
217 *
218 * @param mixed $header
219 */
220 private function assertHeader($header): void
221 {
222 if (!is_string($header)) {
223 throw new \InvalidArgumentException(sprintf(
224 'Header name must be a string but %s provided.',
225 is_object($header) ? get_class($header) : gettype($header)
226 ));
227 }
228  
229 if (!preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D', $header)) {
230 throw new \InvalidArgumentException(
231 sprintf('"%s" is not valid header name.', $header)
232 );
233 }
234 }
235  
236 /**
237 * @see https://datatracker.ietf.org/doc/html/rfc7230#section-3.2
238 *
239 * field-value = *( field-content / obs-fold )
240 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
241 * field-vchar = VCHAR / obs-text
242 * VCHAR = %x21-7E
243 * obs-text = %x80-FF
244 * obs-fold = CRLF 1*( SP / HTAB )
245 */
246 private function assertValue(string $value): void
247 {
248 // The regular expression intentionally does not support the obs-fold production, because as
249 // per RFC 7230#3.2.4:
250 //
251 // A sender MUST NOT generate a message that includes
252 // line folding (i.e., that has any field-value that contains a match to
253 // the obs-fold rule) unless the message is intended for packaging
254 // within the message/http media type.
255 //
256 // Clients must not send a request with line folding and a server sending folded headers is
257 // likely very rare. Line folding is a fairly obscure feature of HTTP/1.1 and thus not accepting
258 // folding is not likely to break any legitimate use case.
259 if (!preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*$/D', $value)) {
260 throw new \InvalidArgumentException(
261 sprintf('"%s" is not valid header value.', $value)
262 );
263 }
264 }
265 }