krz/vox-populi
A Tumblr web client.
clone: git clone https://gitbay.org/krz/vox-populi.git
main: vendor/guzzlehttp/psr7/src/MessageTrait.php · raw
1<?php
2namespace GuzzleHttp\Psr7;
3
4use Psr\Http\Message\StreamInterface;
5
6/**
7 * Trait implementing functionality common to requests and responses.
8 */
9trait MessageTrait
10{
11 /** @var array Map of all registered headers, as original name => array of values */
12 private $headers = [];
13
14 /** @var array Map of lowercase header name => original name at registration */
15 private $headerNames = [];
16
17 /** @var string */
18 private $protocol = '1.1';
19
20 /** @var StreamInterface */
21 private $stream;
22
23 public function getProtocolVersion()
24 {
25 return $this->protocol;
26 }
27
28 public function withProtocolVersion($version)
29 {
30 if ($this->protocol === $version) {
31 return $this;
32 }
33
34 $new = clone $this;
35 $new->protocol = $version;
36 return $new;
37 }
38
39 public function getHeaders()
40 {
41 return $this->headers;
42 }
43
44 public function hasHeader($header)
45 {
46 return isset($this->headerNames[strtolower($header)]);
47 }
48
49 public function getHeader($header)
50 {
51 $header = strtolower($header);
52
53 if (!isset($this->headerNames[$header])) {
54 return [];
55 }
56
57 $header = $this->headerNames[$header];
58
59 return $this->headers[$header];
60 }
61
62 public function getHeaderLine($header)
63 {
64 return implode(', ', $this->getHeader($header));
65 }
66
67 public function withHeader($header, $value)
68 {
69 $this->assertHeader($header);
70 $value = $this->normalizeHeaderValue($value);
71 $normalized = strtolower($header);
72
73 $new = clone $this;
74 if (isset($new->headerNames[$normalized])) {
75 unset($new->headers[$new->headerNames[$normalized]]);
76 }
77 $new->headerNames[$normalized] = $header;
78 $new->headers[$header] = $value;
79
80 return $new;
81 }
82
83 public function withAddedHeader($header, $value)
84 {
85 $this->assertHeader($header);
86 $value = $this->normalizeHeaderValue($value);
87 $normalized = strtolower($header);
88
89 $new = clone $this;
90 if (isset($new->headerNames[$normalized])) {
91 $header = $this->headerNames[$normalized];
92 $new->headers[$header] = array_merge($this->headers[$header], $value);
93 } else {
94 $new->headerNames[$normalized] = $header;
95 $new->headers[$header] = $value;
96 }
97
98 return $new;
99 }
100
101 public function withoutHeader($header)
102 {
103 $normalized = strtolower($header);
104
105 if (!isset($this->headerNames[$normalized])) {
106 return $this;
107 }
108
109 $header = $this->headerNames[$normalized];
110
111 $new = clone $this;
112 unset($new->headers[$header], $new->headerNames[$normalized]);
113
114 return $new;
115 }
116
117 public function getBody()
118 {
119 if (!$this->stream) {
120 $this->stream = stream_for('');
121 }
122
123 return $this->stream;
124 }
125
126 public function withBody(StreamInterface $body)
127 {
128 if ($body === $this->stream) {
129 return $this;
130 }
131
132 $new = clone $this;
133 $new->stream = $body;
134 return $new;
135 }
136
137 private function setHeaders(array $headers)
138 {
139 $this->headerNames = $this->headers = [];
140 foreach ($headers as $header => $value) {
141 if (is_int($header)) {
142 // Numeric array keys are converted to int by PHP but having a header name '123' is not forbidden by the spec
143 // and also allowed in withHeader(). So we need to cast it to string again for the following assertion to pass.
144 $header = (string) $header;
145 }
146 $this->assertHeader($header);
147 $value = $this->normalizeHeaderValue($value);
148 $normalized = strtolower($header);
149 if (isset($this->headerNames[$normalized])) {
150 $header = $this->headerNames[$normalized];
151 $this->headers[$header] = array_merge($this->headers[$header], $value);
152 } else {
153 $this->headerNames[$normalized] = $header;
154 $this->headers[$header] = $value;
155 }
156 }
157 }
158
159 private function normalizeHeaderValue($value)
160 {
161 if (!is_array($value)) {
162 return $this->trimHeaderValues([$value]);
163 }
164
165 if (count($value) === 0) {
166 throw new \InvalidArgumentException('Header value can not be an empty array.');
167 }
168
169 return $this->trimHeaderValues($value);
170 }
171
172 /**
173 * Trims whitespace from the header values.
174 *
175 * Spaces and tabs ought to be excluded by parsers when extracting the field value from a header field.
176 *
177 * header-field = field-name ":" OWS field-value OWS
178 * OWS = *( SP / HTAB )
179 *
180 * @param string[] $values Header values
181 *
182 * @return string[] Trimmed header values
183 *
184 * @see https://tools.ietf.org/html/rfc7230#section-3.2.4
185 */
186 private function trimHeaderValues(array $values)
187 {
188 return array_map(function ($value) {
189 if (!is_scalar($value) && null !== $value) {
190 throw new \InvalidArgumentException(sprintf(
191 'Header value must be scalar or null but %s provided.',
192 is_object($value) ? get_class($value) : gettype($value)
193 ));
194 }
195
196 return trim((string) $value, " \t");
197 }, $values);
198 }
199
200 private function assertHeader($header)
201 {
202 if (!is_string($header)) {
203 throw new \InvalidArgumentException(sprintf(
204 'Header name must be a string but %s provided.',
205 is_object($header) ? get_class($header) : gettype($header)
206 ));
207 }
208
209 if ($header === '') {
210 throw new \InvalidArgumentException('Header name can not be empty.');
211 }
212 }
213}