PluginProbe
WCPOS – Point of Sale (POS) plugin for WooCommerce / 1.10.20
WCPOS – Point of Sale (POS) plugin for WooCommerce v1.10.20
1.10.20 1.10.19 1.10.18 1.10.17 1.10.16 1.10.15 1.10.13 1.10.14 1.10.12 1.10.11 1.10.10 1.10.9 1.10.8 untagged-3d9b7ccddc54df87c672 1.10.7 1.10.6 1.10.5 1.10.3 1.10.4 1.10.2 1.10.1 1.10.0 1.9.17 1.9.15 1.9.16 All 164 releases
woocommerce-pos / vendor_prefixed / guzzlehttp / psr7 / src / MessageTrait.php

MessageTrait.php in WCPOS – Point of Sale (POS) plugin for WooCommerce 1.10.20, at vendor_prefixed/guzzlehttp/psr7/src/MessageTrait.php

230 lines 7.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare (strict_types=1);
4 namespace WCPOS\Vendor\GuzzleHttp\Psr7;
5
6 use WCPOS\Vendor\Psr\Http\Message\MessageInterface;
7 use WCPOS\Vendor\Psr\Http\Message\StreamInterface;
8 /**
9 * Trait implementing functionality common to requests and responses.
10 */
11 trait MessageTrait
12 {
13 /** @var string[][] Map of all registered headers, as original name => array of values */
14 private array $headers = [];
15 /** @var string[] Map of lowercase header name => original name at registration */
16 private array $headerNames = [];
17 private string $protocol = '1.1';
18 private ?StreamInterface $stream = null;
19 public function getProtocolVersion() : string
20 {
21 return $this->protocol;
22 }
23 /**
24 * @return static
25 */
26 public function withProtocolVersion(string $version) : MessageInterface
27 {
28 $this->assertProtocolVersion($version);
29 if ($this->protocol === $version) {
30 return $this;
31 }
32 $new = clone $this;
33 $new->protocol = $version;
34 return $new;
35 }
36 public function getHeaders() : array
37 {
38 return $this->headers;
39 }
40 public function hasHeader(string $name) : bool
41 {
42 return isset($this->headerNames[Utils::asciiToLower($name)]);
43 }
44 public function getHeader(string $name) : array
45 {
46 $header = Utils::asciiToLower($name);
47 if (!isset($this->headerNames[$header])) {
48 return [];
49 }
50 $header = $this->headerNames[$header];
51 return $this->headers[$header];
52 }
53 public function getHeaderLine(string $name) : string
54 {
55 return \implode(', ', $this->getHeader($name));
56 }
57 /**
58 * @return static
59 */
60 public function withHeader(string $name, $value) : MessageInterface
61 {
62 $this->assertHeader($name);
63 $value = $this->normalizeHeaderValue($name, $value);
64 $normalized = Utils::asciiToLower($name);
65 $new = clone $this;
66 if (isset($new->headerNames[$normalized])) {
67 unset($new->headers[$new->headerNames[$normalized]]);
68 }
69 $new->headerNames[$normalized] = $name;
70 $new->headers[$name] = $value;
71 return $new;
72 }
73 /**
74 * @return static
75 */
76 public function withAddedHeader(string $name, $value) : MessageInterface
77 {
78 $this->assertHeader($name);
79 $value = $this->normalizeHeaderValue($name, $value);
80 $normalized = Utils::asciiToLower($name);
81 $new = clone $this;
82 if (isset($new->headerNames[$normalized])) {
83 $name = $this->headerNames[$normalized];
84 $new->headers[$name] = \array_merge($this->headers[$name], $value);
85 } else {
86 $new->headerNames[$normalized] = $name;
87 $new->headers[$name] = $value;
88 }
89 return $new;
90 }
91 /**
92 * @return static
93 */
94 public function withoutHeader(string $name) : MessageInterface
95 {
96 $normalized = Utils::asciiToLower($name);
97 if (!isset($this->headerNames[$normalized])) {
98 return $this;
99 }
100 $name = $this->headerNames[$normalized];
101 $new = clone $this;
102 unset($new->headers[$name], $new->headerNames[$normalized]);
103 return $new;
104 }
105 public function getBody() : StreamInterface
106 {
107 if (!$this->stream) {
108 $this->stream = Utils::streamFor('');
109 }
110 return $this->stream;
111 }
112 /**
113 * @return static
114 */
115 public function withBody(StreamInterface $body) : MessageInterface
116 {
117 if ($body === $this->stream) {
118 return $this;
119 }
120 $new = clone $this;
121 $new->stream = $body;
122 return $new;
123 }
124 /**
125 * @param (string|string[])[] $headers
126 */
127 private function setHeaders(array $headers) : void
128 {
129 $this->headerNames = $this->headers = [];
130 foreach ($headers as $header => $value) {
131 // Numeric array keys are converted to int by PHP.
132 $header = (string) $header;
133 $this->assertHeader($header);
134 $value = $this->normalizeHeaderValue($header, $value);
135 $normalized = Utils::asciiToLower($header);
136 if (isset($this->headerNames[$normalized])) {
137 $header = $this->headerNames[$normalized];
138 $this->headers[$header] = \array_merge($this->headers[$header], $value);
139 } else {
140 $this->headerNames[$normalized] = $header;
141 $this->headers[$header] = $value;
142 }
143 }
144 }
145 /**
146 * @param mixed $value
147 *
148 * @return string[]
149 */
150 private function normalizeHeaderValue(string $header, $value) : array
151 {
152 if (\is_array($value) && $value === []) {
153 throw new \InvalidArgumentException('Header value must be a non-empty array or string.');
154 }
155 if (!\is_array($value)) {
156 return $this->trimAndValidateHeaderValues($header, [$value]);
157 }
158 return $this->trimAndValidateHeaderValues($header, $value);
159 }
160 /**
161 * Trims whitespace from the header values.
162 *
163 * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.
164 *
165 * header-field = field-name ":" OWS field-value OWS
166 * OWS = *( SP / HTAB )
167 *
168 * @param mixed[] $values Header values
169 *
170 * @return string[] Trimmed header values
171 *
172 * @see https://datatracker.ietf.org/doc/html/rfc9110#section-5.5
173 */
174 private function trimAndValidateHeaderValues(string $header, array $values) : array
175 {
176 return \array_map(function ($value) use($header) : string {
177 if (!\is_string($value)) {
178 throw new \InvalidArgumentException(\sprintf('Header value must be a string or array of strings but %s provided.', \get_debug_type($value)));
179 }
180 $trimmed = \trim($value, " \t");
181 $this->assertValue($header, $trimmed);
182 return $trimmed;
183 }, \array_values($values));
184 }
185 /**
186 * @see https://datatracker.ietf.org/doc/html/rfc9110#section-5.1
187 */
188 private function assertHeader(string $header) : void
189 {
190 if (!Rfc9110::isToken($header)) {
191 throw new \InvalidArgumentException(\sprintf('Invalid header name: %s', DiagnosticValue::escape($header)));
192 }
193 }
194 private function assertProtocolVersion(string $version) : void
195 {
196 if (!Rfc9112::isValidProtocolVersion($version)) {
197 throw new \InvalidArgumentException('Protocol version must be a valid HTTP version number.');
198 }
199 }
200 /**
201 * @see https://datatracker.ietf.org/doc/html/rfc9110#section-5.5
202 *
203 * field-value = *( field-content / obs-fold )
204 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
205 * field-vchar = VCHAR / obs-text
206 * VCHAR = %x21-7E
207 * obs-text = %x80-FF
208 * obs-fold = CRLF 1*( SP / HTAB )
209 */
210 private function assertValue(string $header, string $value) : void
211 {
212 // The regular expression intentionally does not support the obs-fold
213 // production, because as per RFC 9112#5.2:
214 //
215 // A sender MUST NOT generate a message that includes line folding
216 // (i.e., that has any field-value that contains a match to the obs-fold
217 // rule) unless the message is intended for packaging within the
218 // message/http media type.
219 //
220 // Clients must not send a request with line folding and a server
221 // sending folded headers is likely very rare. Line folding is a fairly
222 // obscure feature of HTTP/1.1 and thus not accepting folding is not
223 // likely to break any legitimate use case.
224 if (!Rfc9110::isFieldValue($value)) {
225 $reason = \strpbrk($value, "\r\n") !== \false ? 'must not contain CR or LF characters' : 'contains an invalid control character';
226 throw new \InvalidArgumentException(\sprintf('Header "%s" %s.', DiagnosticValue::escape($header), $reason));
227 }
228 }
229 }
230